/***************************************************************************** * Copyright (c) 2010 CEA LIST. * * * 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: * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation * *****************************************************************************/ package kr.co.apexsoft.stella.modeler.explorer.provider; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import kr.co.apexsoft.stella.modeler.explorer.core.ApexDIWrapper; import kr.co.apexsoft.stella.modeler.explorer.core.ApexProjectWrapper; import kr.co.apexsoft.stella.modeler.explorer.core.ApexStellaProjectMap; import kr.co.apexsoft.stella.modeler.explorer.util.ApexDiParseHelper; import org.eclipse.core.resources.IContainer; 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.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.facet.infra.browser.Messages; import org.eclipse.emf.facet.infra.browser.custom.MetamodelView; import org.eclipse.emf.facet.infra.browser.custom.TypeView; import org.eclipse.emf.facet.infra.browser.custom.core.CustomizationsCatalog; import org.eclipse.emf.facet.infra.browser.uicore.CustomizableModelContentProvider; import org.eclipse.emf.facet.infra.browser.uicore.internal.AppearanceConfiguration; import org.eclipse.emf.facet.infra.browser.uicore.internal.model.ItemsFactory; import org.eclipse.emf.facet.infra.facet.Facet; import org.eclipse.emf.facet.infra.facet.FacetSet; import org.eclipse.emf.facet.infra.facet.core.FacetSetCatalog; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.osgi.util.NLS; import org.eclipse.papyrus.infra.core.resource.uml.UmlModel; import org.eclipse.papyrus.infra.emf.Activator; import org.eclipse.papyrus.infra.onefile.utils.OneFileUtils; import org.eclipse.swt.widgets.Control; /** * this is a specific content provider used to not display UML stereotype applications * * @deprecated Use {@link kr.co.apexsoft.stella.modeler.explorer.provider.ApexUMLContentProvider.providers.UMLContentProvider} instead */ public class ApexUMLContentProvider extends CustomizableModelContentProvider implements IResourceChangeListener { private Viewer viewer; private ItemsFactory itemsFactory; private final AppearanceConfiguration appearanceConfiguration; public ApexUMLContentProvider() { super(Activator.getDefault().getCustomizationManager()); itemsFactory = new ItemsFactory(); appearanceConfiguration = new AppearanceConfiguration(itemsFactory); // CustomizationManager.getAppearanceConfiguration()이 접근불가하므로 아래와 같이 // Activator에서 해주는 처리와 동일하게 처리 setupAppearanceConfiguration(appearanceConfiguration); // 아래는 없어도 자동으로 리스너로 등록되는 모양 // ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); } private void setupAppearanceConfiguration(AppearanceConfiguration appearanceConfiguration) { appearanceConfiguration.setShowDerivedLinks(true); appearanceConfiguration.setDecorateExternalResources(false); try { // load customizations defined as default through the customization // extension List<MetamodelView> registryDefaultCustomizations = CustomizationsCatalog.getInstance().getRegistryDefaultCustomizations(); for(MetamodelView metamodelView : registryDefaultCustomizations) { appearanceConfiguration.getCustomizationEngine().registerCustomization(metamodelView); } appearanceConfiguration.getCustomizationEngine().loadCustomizations(); loadFacetsForCustomizations(registryDefaultCustomizations,appearanceConfiguration); } catch (Throwable e) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error initializing customizations", e)); //$NON-NLS-1$ } } /** * load the facets * * @param customizations * list of customization * @param customizationManager * the Customization Manager */ protected void loadFacetsForCustomizations( final List<MetamodelView> customizations, final AppearanceConfiguration appearanceConfiguration) { final Set<Facet> referencedFacets = new HashSet<Facet>(); final Collection<FacetSet> facetSets = FacetSetCatalog.getSingleton() .getAllFacetSets(); for (MetamodelView customization : customizations) { String metamodelURI = customization.getMetamodelURI(); // find customized FacetSet FacetSet customizedFacetSet = null; if (metamodelURI != null) { for (FacetSet facetSet : facetSets) { if (metamodelURI.equals(facetSet.getNsURI())) { customizedFacetSet = facetSet; break; } } } if (customizedFacetSet == null) { continue; } // find customized Facets EList<TypeView> types = customization.getTypes(); for (TypeView typeView : types) { String metaclassName = typeView.getMetaclassName(); Facet facet = findFacetWithFullyQualifiedName(metaclassName, customizedFacetSet); if (facet != null) { referencedFacets.add(facet); } else { Activator.log.warn(NLS .bind( Messages.BrowserActionBarContributor_missingRequiredFacet, new Object[] { metaclassName, customizedFacetSet .getName(), customization.getName() })); } } for (Facet referencedFacet : referencedFacets) { appearanceConfiguration.loadFacet(referencedFacet); } } // // for modified facets // customizationManager.getInstancesForMetaclasses().buildDerivationTree(); // customizationManager.getAppearanceConfiguration().touch(); // customizationManager.refreshDelayed(true); } /** * fin a facet from * * @param metaclassName * @param customizedFacetSet * @return */ private Facet findFacetWithFullyQualifiedName(final String metaclassName, final FacetSet customizedFacetSet) { EList<Facet> facets = customizedFacetSet.getFacets(); for (Facet facet : facets) { String facetName = getMetaclassQualifiedName(facet); if (metaclassName.equals(facetName)) { return facet; } } return null; } /** @return the qualified name of the given metaclass */ public static String getMetaclassQualifiedName(final EClassifier eClass) { final ArrayList<String> qualifiedNameParts = new ArrayList<String>(); final StringBuilder builder = new StringBuilder(); EPackage ePackage = eClass.getEPackage(); while (ePackage != null) { qualifiedNameParts.add(ePackage.getName()); ePackage = ePackage.getESuperPackage(); } for (int i = qualifiedNameParts.size() - 1; i >= 0; i--) { builder.append(qualifiedNameParts.get(i) + "."); //$NON-NLS-1$ } builder.append(eClass.getName()); return builder.toString(); } /** * apex updated */ // @Override // public Object[] getElements(final Object inputElement) { // // Object[] rootElements = getRootElements(inputElement); // // if (rootElements == null) { // return null; // } // // List<Object> result = new ArrayList<Object>(); // // for (Object element : rootElements) { // // if (element instanceof EObject) { // EObject eObject = (EObject) element; // result.add(new ModelElementItem(eObject, null, this.appearanceConfiguration)); // } else { // result.add(element); // } // } // return result.toArray(); // } /** * apex updated * * Return the initial values from the input. * Input should be of type {@link UmlModel}. * * @see org.eclipse.gmt.modisco.infra.browser.uicore.CustomizableModelContentProvider#getRootElements(java.lang.Object) * * @param inputElement * @return */ @Override public Object[] getRootElements(Object inputElement) { /* apex improved start */ List<Object> result = new ArrayList<Object>(); try { if ( inputElement instanceof IWorkspaceRoot ) { IWorkspaceRoot root = (IWorkspaceRoot)inputElement; IProject[] projects = root.getProjects(); for ( IProject project : projects ) { result.add(project); } } } catch (Exception e) { Activator.log.error(e); } return result.toArray(); /* apex improved end */ } /** * apex updated */ @Override public Object[] getChildren(final Object parentElement) { List<Object> result = new ArrayList<Object>(); if ( parentElement instanceof IProject ) { IProject project = (IProject)parentElement; IResource[] members; try { members = project.members(); List<IFile> controlledFiles = ApexDiParseHelper.getControlledDiFiles(project); for ( IResource r : members ) { if ( r instanceof IFile ) { IFile file = (IFile)r; if(OneFileUtils.isDi(file)) { if ( !controlledFiles.contains(file) ) { result.add(file); } } } } } catch (CoreException e) { e.printStackTrace(); } } else if ( parentElement instanceof IFile ) { IFile diFile = (IFile)parentElement; if(OneFileUtils.isDi(diFile)) { result = new ApexDIWrapper(diFile, itemsFactory, appearanceConfiguration).getChildren(); } } else { Object[] arrayObject = super.getChildren(parentElement); if(arrayObject != null) { for(int i = 0; i < arrayObject.length; i++) { if ( arrayObject[i] instanceof UmlModel ) { UmlModel umlModel = (UmlModel) arrayObject[i]; // makeModelElementItemList(umlModel, result); } else { result.add(arrayObject[i]); } } } } return result.toArray(); } @Override public boolean hasChildren(Object element) { boolean hasChildren = false; if ( element instanceof IProject ) { IProject project = (IProject)element; try { if (project.isAccessible()) { hasChildren = project.members().length > 0; } } catch (CoreException e) { e.printStackTrace(); } } else if ( element instanceof IFile ) { IFile diFile = (IFile)element; if(OneFileUtils.isDi(diFile)) { hasChildren = true; } } else { hasChildren = super.getChildren(element).length > 0; } return hasChildren; } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { super.inputChanged(viewer, oldInput, newInput); this.viewer = viewer; IWorkspace oldWorkspace = null; IWorkspace newWorkspace = null; if (oldInput instanceof IWorkspace) { oldWorkspace = (IWorkspace) oldInput; } else if (oldInput instanceof IContainer) { oldWorkspace = ((IContainer) oldInput).getWorkspace(); } if (newInput instanceof IWorkspace) { newWorkspace = (IWorkspace) newInput; } else if (newInput instanceof IContainer) { newWorkspace = ((IContainer) newInput).getWorkspace(); } if (oldWorkspace != newWorkspace) { if (oldWorkspace != null) { oldWorkspace.removeResourceChangeListener(this); } if (newWorkspace != null) { newWorkspace.addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); } } } /** * 아래부터 org.eclipse.ui.model.WorkbenchContentProvider에서 가져옴 */ @Override public void resourceChanged(IResourceChangeEvent event) { processDelta(event.getDelta()); } /** * Process the resource delta. * * @param delta */ protected void processDelta(IResourceDelta delta) { Control ctrl = viewer.getControl(); if (ctrl == null || ctrl.isDisposed()) { return; } final Collection runnables = new ArrayList(); processDelta(delta, runnables); if (runnables.isEmpty()) { return; } //Are we in the UIThread? If so spin it until we are done if (ctrl.getDisplay().getThread() == Thread.currentThread()) { runUpdates(runnables); } else { ctrl.getDisplay().asyncExec(new Runnable(){ /* (non-Javadoc) * @see java.lang.Runnable#run() */ public void run() { //Abort if this happens after disposes Control ctrl = viewer.getControl(); if (ctrl == null || ctrl.isDisposed()) { return; } runUpdates(runnables); } }); } } /** * Run all of the runnables that are the widget updates * @param runnables */ private void runUpdates(Collection runnables) { Iterator runnableIterator = runnables.iterator(); while(runnableIterator.hasNext()){ ((Runnable)runnableIterator.next()).run(); } } /** * Process a resource delta. Add any runnables */ private void processDelta(IResourceDelta delta, Collection runnables) { //he widget may have been destroyed // by the time this is run. Check for this and do nothing if so. Control ctrl = viewer.getControl(); if (ctrl == null || ctrl.isDisposed()) { return; } // Get the affected resource final IResource resource = delta.getResource(); // If any children have changed type, just do a full refresh of this // parent, // since a simple update on such children won't work, // and trying to map the change to a remove and add is too dicey. // The case is: folder A renamed to existing file B, answering yes to // overwrite B. IResourceDelta[] affectedChildren = delta .getAffectedChildren(IResourceDelta.CHANGED); for (int i = 0; i < affectedChildren.length; i++) { if ((affectedChildren[i].getFlags() & IResourceDelta.TYPE) != 0) { runnables.add(getRefreshRunnable(resource)); return; } } // Opening a project just affects icon, but we need to refresh when // a project is closed because if child items have not yet been created // in the tree we still need to update the item's children int changeFlags = delta.getFlags(); if ((changeFlags & IResourceDelta.OPEN) != 0) { if (resource.isAccessible()) { runnables.add(getUpdateRunnable(resource)); } else { runnables.add(getRefreshRunnable(resource)); return; } } // Check the flags for changes the Navigator cares about. // See ResourceLabelProvider for the aspects it cares about. // Notice we don't care about F_CONTENT or F_MARKERS currently. if ((changeFlags & (IResourceDelta.SYNC | IResourceDelta.TYPE | IResourceDelta.DESCRIPTION)) != 0) { runnables.add(getUpdateRunnable(resource)); } // Replacing a resource may affect its label and its children if ((changeFlags & IResourceDelta.REPLACED) != 0) { runnables.add(getRefreshRunnable(resource)); return; } // Handle changed children . for (int i = 0; i < affectedChildren.length; i++) { processDelta(affectedChildren[i], runnables); } // @issue several problems here: // - should process removals before additions, to avoid multiple equal // elements in viewer // - Kim: processing removals before additions was the indirect cause of // 44081 and its varients // - Nick: no delta should have an add and a remove on the same element, // so processing adds first is probably OK // - using setRedraw will cause extra flashiness // - setRedraw is used even for simple changes // - to avoid seeing a rename in two stages, should turn redraw on/off // around combined removal and addition // - Kim: done, and only in the case of a rename (both remove and add // changes in one delta). IResourceDelta[] addedChildren = delta .getAffectedChildren(IResourceDelta.ADDED); IResourceDelta[] removedChildren = delta .getAffectedChildren(IResourceDelta.REMOVED); if (addedChildren.length == 0 && removedChildren.length == 0) { return; } List<Object> addedList = new ArrayList<>(); List<Object> removedList = new ArrayList<>(); // Process additions before removals as to not cause selection // preservation prior to new objects being added // Handle added children. Issue one update for all insertions. int numMovedFrom = 0; int numMovedTo = 0; for (int i = 0; i < addedChildren.length; i++) { IResource subRes = addedChildren[i].getResource(); if (subRes instanceof IFile && !OneFileUtils.isDi(subRes)) { continue; } addedList.add(subRes); if ((addedChildren[i].getFlags() & IResourceDelta.MOVED_FROM) != 0) { ++numMovedFrom; } } // Handle removed children. Issue one update for all removals. for (int i = 0; i < removedChildren.length; i++) { IResource subRes = removedChildren[i].getResource(); if (subRes instanceof IFile && !OneFileUtils.isDi(subRes)) { continue; } removedList.add(subRes); if ((removedChildren[i].getFlags() & IResourceDelta.MOVED_TO) != 0) { ++numMovedTo; } } final Object[] addedObjects = addedList.toArray(); final Object[] removedObjects = removedList.toArray(); // heuristic test for items moving within same folder (i.e. renames) final boolean hasRename = numMovedFrom > 0 && numMovedTo > 0; Runnable addAndRemove = new Runnable(){ public void run() { if (viewer instanceof AbstractTreeViewer) { AbstractTreeViewer treeViewer = (AbstractTreeViewer) viewer; // Disable redraw until the operation is finished so we don't // get a flash of both the new and old item (in the case of // rename) // Only do this if we're both adding and removing files (the // rename case) if (hasRename) { treeViewer.getControl().setRedraw(false); } try { if (addedObjects.length > 0) { treeViewer.add(resource, addedObjects); } if (removedObjects.length > 0) { treeViewer.remove(removedObjects); } } finally { if (hasRename) { treeViewer.getControl().setRedraw(true); } } } else { ((StructuredViewer) viewer).refresh(resource); } } }; runnables.add(addAndRemove); } /** * Return a runnable for refreshing a resource. * @param resource * @return Runnable */ private Runnable getRefreshRunnable(final IResource resource) { return new Runnable(){ public void run() { ((StructuredViewer) viewer).refresh(resource); } }; } /** * Return a runnable for refreshing a resource. * @param resource * @return Runnable */ private Runnable getUpdateRunnable(final IResource resource) { return new Runnable(){ public void run() { ((StructuredViewer) viewer).update(resource, null); } }; } }