/* * Copyright (c) 2012, 2013 Hemanta Sapkota. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Hemanta Sapkota (laex.pearl@gmail.com) */ package com.laex.cg2d.entityeditor.views; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSource; import org.eclipse.swt.dnd.DragSourceAdapter; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.RowData; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.events.IHyperlinkListener; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ImageHyperlink; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.part.ViewPart; import com.laex.cg2d.entityeditor.Activator; import com.laex.cg2d.model.CGCProject; import com.laex.cg2d.model.DNDFileTransfer; import com.laex.cg2d.model.DNDFileTransfer.TransferType; import com.laex.cg2d.model.EntityManager; import com.laex.cg2d.model.EntityResourceChangeListener; import com.laex.cg2d.model.EntityResourceChangeListener.EntityChangeListener; import com.laex.cg2d.model.ICGCProject; import com.laex.cg2d.model.IEntityManager; import com.laex.cg2d.model.model.Entity; import com.laex.cg2d.model.model.ModelValidator; import com.laex.cg2d.model.model.ModelValidatorFactory; import com.laex.cg2d.model.resources.ResourceManager; import com.laex.cg2d.model.util.EntitiesUtil; /** * The Class EntitiesView. */ public class EntitiesView extends ViewPart implements ISelectionListener, IEntityManager, EntityChangeListener, ControlListener { /** The Constant ID. */ public static final String ID = EntityManager.ENTITIES_VIEW_ID; //$NON-NLS-1$ /** The form toolkit. */ private final FormToolkit formToolkit = new FormToolkit(Display.getDefault()); /** The selected project. */ private IProject selectedProject; /** The entities map. */ private Map<String, Entity> entitiesMap = new HashMap<String, Entity>(); /** The entities buttons. */ private Map<String, Button> entitiesButtons = new HashMap<String, Button>(); /** The temp removed list. */ Map<String, Button> tempRemovedList = new HashMap<String, Button>(); /** The entities resource listener. */ private EntityResourceChangeListener entitiesResourceListener = new EntityResourceChangeListener(); /** The work to do. */ int workToDO = 0; /** The sctn entities. */ private Section sctnEntities; /** The scrolled composite. */ private ScrolledComposite scrolledComposite; /** The ent composite. */ private Composite entComposite; /** The composite. */ private Composite composite; /** The txt filter. */ private Text txtFilter; /** The label. */ private Label label; /** * Instantiates a new entities view. */ public EntitiesView() { } /** * Create contents of the view part. * * @param parent the parent */ @Override public void createPartControl(Composite parent) { { sctnEntities = formToolkit.createSection(parent, Section.TITLE_BAR); formToolkit.paintBordersFor(sctnEntities); sctnEntities.setExpanded(true); { scrolledComposite = new ScrolledComposite(sctnEntities, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); formToolkit.adapt(scrolledComposite); formToolkit.paintBordersFor(scrolledComposite); sctnEntities.setClient(scrolledComposite); scrolledComposite.setExpandHorizontal(true); scrolledComposite.setExpandVertical(true); entComposite = formToolkit.createComposite(scrolledComposite, SWT.NONE); formToolkit.paintBordersFor(entComposite); } { composite = formToolkit.createComposite(sctnEntities, SWT.NONE); composite.setBackground(null); formToolkit.paintBordersFor(composite); sctnEntities.setTextClient(composite); composite.setLayout(new RowLayout(SWT.HORIZONTAL)); ImageHyperlink mghprlnkNewImagehyperlink = formToolkit.createImageHyperlink(composite, SWT.NONE); mghprlnkNewImagehyperlink.addHyperlinkListener(new IHyperlinkListener() { public void linkActivated(HyperlinkEvent e) { txtFilter.setText(""); loadAllEntitiesWithProgress(); } public void linkEntered(HyperlinkEvent e) { } public void linkExited(HyperlinkEvent e) { } }); mghprlnkNewImagehyperlink.setBackground(null); formToolkit.paintBordersFor(mghprlnkNewImagehyperlink); mghprlnkNewImagehyperlink.setText("Reload"); } txtFilter = formToolkit.createText(sctnEntities, "", SWT.NONE); txtFilter.setText(""); txtFilter.setMessage("Filter entities"); txtFilter.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { doFilter(); } }); sctnEntities.setDescriptionControl(txtFilter); label = formToolkit.createSeparator(sctnEntities, SWT.HORIZONTAL); sctnEntities.setSeparatorControl(label); } createActions(); initializeToolBar(); initializeMenu(); getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(this); ResourcesPlugin.getWorkspace().addResourceChangeListener(entitiesResourceListener, IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE); entitiesResourceListener.addEntityChangeListener(this); } /** * Do filter. */ protected void doFilter() { String text = txtFilter.getText().toLowerCase(); boolean empty = StringUtils.isEmpty(text); for (String key : entitiesButtons.keySet()) { Button b = entitiesButtons.get(key); String entityName = EntitiesUtil.getDisplayName(new Path(key)).toLowerCase(); RowData rd = new RowData(); if (entityName.contains(text)) { b.setVisible(true); rd.exclude = false; } else { b.setVisible(false); rd.exclude = true; } if (empty) { b.setVisible(true); rd.exclude = false; } b.setLayoutData(rd); } setRowLayout(); } /** * Create the actions. */ private void createActions() { // Create the actions } /** * Initialize the toolbar. */ private void initializeToolBar() { IToolBarManager toolbarManager = getViewSite().getActionBars().getToolBarManager(); } /** * Initialize the menu. */ private void initializeMenu() { IMenuManager menuManager = getViewSite().getActionBars().getMenuManager(); } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#setFocus() */ @Override public void setFocus() { } /** * On entity button click. * * @param b the b */ private void onEntityButtonClick(Button b) { Image newImage = ResourceManager.getImage(ResourceManager.rotate(b.getImage().getImageData(), SWT.RIGHT)); b.setImage(newImage); b.setSize(newImage.getBounds().width, newImage.getBounds().height); entComposite.layout(true); } /** * Load new entity. * * @param resource the resource * @throws IOException Signals that an I/O exception has occurred. * @throws CoreException the core exception */ private void loadNewEntity(final IResource resource) throws IOException, CoreException { final Entity entity = Entity.createFromFile((IFile) resource); final String entityName = EntitiesUtil.getInternalName(resource.getFullPath()); if (!validateEntity(resource, entityName, entity)) { return; } entitiesMap.put(entityName, entity); final Image imgScaled = ResourceManager.getImageDescriptor(entity.getDefaultFrame(), 0.5f).createImage(); Button b = entitiesButtons.get(entityName); if (b == null || b.isDisposed()) { b = formToolkit.createButton(entComposite, "", SWT.None); b.addSelectionListener(new SelectionAdapter() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { onEntityButtonClick((Button) e.getSource()); }; }); DragSource dragSource = new DragSource(b, DND.DROP_COPY); dragSource.addDragListener(new DragSourceAdapter() { @Override public void dragSetData(DragSourceEvent event) { DNDFileTransfer.transferType = TransferType.ENTITY; DNDFileTransfer.entityResourceFile = (IFile) resource; event.data = "BOGUS"; } }); dragSource.setTransfer(new Transfer[] { TextTransfer.getInstance() }); entitiesButtons.put(entityName, b); } b.setImage(imgScaled); b.setToolTipText(entityName); /* Compute height hint */ updateCount(); setRowLayout(); } /** * Validate entity. * * @param resource the resource * @param entityName the entity name * @param entity the entity * @return true, if successful */ private boolean validateEntity(final IResource resource, String entityName, final Entity entity) { ModelValidator entityValidator = ModelValidatorFactory.getValidator(Entity.class, entity); boolean isValid = entityValidator.isValid(); if (!isValid) { entitiesMap.remove(resource.getFullPath().toOSString()); removeEntityButton(entityName); } return isValid; } /** * Calculate no of entities to load. */ private void calculateNoOfEntitiesToLoad() { workToDO = 0; try { selectedProject.accept(new IResourceVisitor() { @Override public boolean visit(IResource resource) throws CoreException { if (resource.getName().endsWith(ICGCProject.ENTITIES_EXTENSION)) { workToDO++; } return true; } }); } catch (CoreException e) { Activator.log(e); } } /** * Load entities. * * @param monitor the monitor * @throws CoreException the core exception */ private void loadEntities(final IProgressMonitor monitor) throws CoreException { /* pass 1: Calculate the amount to work */ calculateNoOfEntitiesToLoad(); clearEntities(); if (workToDO <= 0) { return; } monitor.beginTask("Loading entities", workToDO); EntitiesUtil.startCacheSpritesheets(); selectedProject.accept(new IResourceVisitor() { @Override public boolean visit(final IResource resource) throws CoreException { /* Cancel the task */ if (monitor.isCanceled()) { return false; } if (!resource.getName().endsWith(ICGCProject.ENTITIES_EXTENSION)) { return true; } monitor.subTask("Loading " + resource.getName()); try { loadNewEntity(resource); } catch (IOException e) { Activator.log(e); } monitor.worked(1); return true; } }); EntitiesUtil.stopCacheSpritesheet(); setRowLayout(); } /* (non-Javadoc) * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection) */ @Override public void selectionChanged(IWorkbenchPart part, ISelection selection) { if (!(selection instanceof IStructuredSelection)) { return; } IStructuredSelection strucSel = (IStructuredSelection) selection; Object firstElement = strucSel.getFirstElement(); if (!(firstElement instanceof IResource)) { return; } final IResource res = (IResource) firstElement; boolean isScreen = res.getFileExtension() != null && res.getFileExtension().equals(ICGCProject.SCREEN_EXTENSION); if (!isScreen) { return; } final IProject prj = res.getProject(); if (selectedProject != prj) { /* Start our entities loader */ selectedProject = prj; loadAllEntitiesWithProgress(); } } /** * Load all entities with progress. */ private void loadAllEntitiesWithProgress() { if (selectedProject == null) { IEditorPart activeEditor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); if (activeEditor != null) { selectedProject = CGCProject.getInstance().getCurrentProject(activeEditor.getEditorInput()); } else { MessageDialog.openInformation(getSite().getShell(), "Select a resoure", "Select a screen file from the project you want to load the entities or open an entity file."); return; } } ProgressMonitorDialog pmd = new ProgressMonitorDialog(getSite().getShell()); try { pmd.run(false, true, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { loadEntities(monitor); } catch (CoreException e) { Activator.log(e); } } }); } catch (InvocationTargetException e) { Activator.log(e); } catch (InterruptedException e) { Activator.log(e); } } /** * Clear entities. */ private void clearEntities() { for (String key : entitiesButtons.keySet()) { Button b = entitiesButtons.get(key); b.dispose(); b = null; } entitiesButtons.clear(); updateCount(); setRowLayout(); } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#dispose() */ @Override public void dispose() { getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(this); ResourcesPlugin.getWorkspace().removeResourceChangeListener(entitiesResourceListener); super.dispose(); } /* (non-Javadoc) * @see com.laex.cg2d.model.IEntityManager#findEntity(java.lang.String) */ @Override public Entity findEntity(String key) { return entitiesMap.get(key); } /* (non-Javadoc) * @see com.laex.cg2d.model.IEntityManager#removeEntity(java.lang.String) */ @Override public void removeEntity(String key) { entitiesMap.remove(key); } /** * Run in main thread. * * @param r the r */ private void runInMainThread(Runnable r) { getSite().getShell().getDisplay().asyncExec(r); } /* (non-Javadoc) * @see com.laex.cg2d.model.EntityResourceChangeListener.EntityChangeListener#entityChanged(org.eclipse.core.resources.IResource) */ @Override public void entityChanged(final IResource resource) { runInMainThread(new Runnable() { @Override public void run() { try { loadNewEntity(resource); } catch (IOException e) { Activator.log(e); } catch (CoreException e) { Activator.log(e); } } }); } /** * Removes the entity button. * * @param name the name */ void removeEntityButton(final String name) { Button b = entitiesButtons.get(name); if (b != null && !b.isDisposed() && b.getToolTipText().equals(name)) { b.dispose(); b = null; } entitiesButtons.remove(name); entitiesMap.get(name).dispose(); entitiesMap.remove(name); updateCount(); setRowLayout(); } /* (non-Javadoc) * @see com.laex.cg2d.model.EntityResourceChangeListener.EntityChangeListener#entityRemoved(org.eclipse.core.resources.IResource) */ @Override public void entityRemoved(final IResource resource) { runInMainThread(new Runnable() { @Override public void run() { Entity entity = entitiesMap.get(resource.getFullPath().toOSString()); if (entity == null) { return; } final String name = EntitiesUtil.getInternalName(resource.getFullPath()); removeEntityButton(name); } }); } /** * Update count. */ private void updateCount() { sctnEntities.setText("Count: " + entitiesButtons.values().size()); sctnEntities.redraw(); } /** * Sets the row layout. */ private void setRowLayout() { /* * Row Layout on EntComposite should be set once all the components have * been created */ RowLayout rl = new RowLayout(SWT.HORIZONTAL); rl.wrap = true; entComposite.setLayout(rl); entComposite.layout(true); scrolledComposite.setContent(entComposite); Rectangle r = scrolledComposite.getClientArea(); scrolledComposite.setMinSize(entComposite.computeSize(r.width, SWT.DEFAULT)); scrolledComposite.removeControlListener(this); scrolledComposite.addControlListener(this); } /* (non-Javadoc) * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent) */ @Override public void controlMoved(ControlEvent e) { } /* (non-Javadoc) * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent) */ @Override public void controlResized(ControlEvent e) { Rectangle r = scrolledComposite.getClientArea(); scrolledComposite.setMinSize(entComposite.computeSize(r.width, SWT.DEFAULT)); } }