Java tutorial
/******************************************************************************* * Copyright (c) 2006, 2007 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.team.examples.model.ui.mapping; import java.util.*; import org.eclipse.core.resources.*; import org.eclipse.core.resources.mapping.*; import org.eclipse.core.runtime.*; import org.eclipse.jface.viewers.*; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.team.core.diff.*; import org.eclipse.team.core.mapping.ISynchronizationContext; import org.eclipse.team.core.mapping.ISynchronizationScope; import org.eclipse.team.core.mapping.provider.ResourceDiffTree; import org.eclipse.team.examples.filesystem.FileSystemPlugin; import org.eclipse.team.examples.model.*; import org.eclipse.team.examples.model.mapping.ExampleModelProvider; import org.eclipse.team.examples.model.ui.ModelNavigatorContentProvider; import org.eclipse.team.internal.ui.Utils; import org.eclipse.team.internal.ui.mapping.SynchronizationResourceMappingContext; import org.eclipse.team.ui.mapping.SynchronizationContentProvider; import org.eclipse.ui.navigator.*; /** * The content provider that is used for synchronizations. * It also makes use of the Common Navigator pipeline * to override the resource content extension so that model projects will * replace the corresponding resource project in the Synchronize view. */ public class ModelSyncContentProvider extends SynchronizationContentProvider implements IPipelinedTreeContentProvider { private ModelNavigatorContentProvider delegate; public ModelSyncContentProvider() { super(); } /* (non-Javadoc) * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#init(org.eclipse.ui.navigator.ICommonContentExtensionSite) */ public void init(ICommonContentExtensionSite site) { super.init(site); delegate = new ModelNavigatorContentProvider(getContext() != null); delegate.init(site); } /* (non-Javadoc) * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#dispose() */ public void dispose() { super.dispose(); if (delegate != null) delegate.dispose(); } protected ITreeContentProvider getDelegateContentProvider() { return delegate; } /* (non-Javadoc) * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#getModelProviderId() */ protected String getModelProviderId() { return ExampleModelProvider.ID; } /* (non-Javadoc) * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#getModelRoot() */ protected Object getModelRoot() { return ModelWorkspace.getRoot(); } /* (non-Javadoc) * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#getTraversals(org.eclipse.team.core.mapping.ISynchronizationContext, java.lang.Object) */ protected ResourceTraversal[] getTraversals(ISynchronizationContext context, Object object) { if (object instanceof ModelObject) { ModelObject mo = (ModelObject) object; ResourceMapping mapping = (ResourceMapping) mo.getAdapter(ResourceMapping.class); ResourceMappingContext rmc = new SynchronizationResourceMappingContext(context); try { // Technically speaking, this may end up being too long running for this // (i.e. we may end up hitting the server) but it will do for illustration purposes return mapping.getTraversals(rmc, new NullProgressMonitor()); } catch (CoreException e) { FileSystemPlugin.log(e); } } return new ResourceTraversal[0]; } /* (non-Javadoc) * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#getChildrenInContext(org.eclipse.team.core.mapping.ISynchronizationContext, java.lang.Object, java.lang.Object[]) */ protected Object[] getChildrenInContext(ISynchronizationContext context, Object parent, Object[] children) { Set allChildren = new HashSet(); allChildren.addAll(Arrays.asList(super.getChildrenInContext(context, parent, children))); // We need to override this method in order to ensure that any elements // that exist in the context but do not exist locally are included if (parent instanceof ModelContainer) { ModelContainer mc = (ModelContainer) parent; IDiff[] diffs = context.getDiffTree().getDiffs(mc.getResource(), IResource.DEPTH_ONE); for (int i = 0; i < diffs.length; i++) { IDiff diff = diffs[i]; IResource resource = ResourceDiffTree.getResourceFor(diff); if (!resource.exists() && ModelObjectDefinitionFile.isModFile(resource)) { ModelObject o = ModelObject.create(resource); if (o != null) allChildren.add(o); } } } if (parent instanceof ModelObjectDefinitionFile) { ResourceTraversal[] traversals = getTraversals(context, parent); IDiff[] diffs = context.getDiffTree().getDiffs(traversals); for (int i = 0; i < diffs.length; i++) { IDiff diff = diffs[i]; IResource resource = ResourceDiffTree.getResourceFor(diff); if (!resource.exists() && ModelObjectElementFile.isMoeFile(resource)) { ModelObject o = new ModelObjectElementFile((ModelObjectDefinitionFile) parent, (IFile) resource); if (o != null) allChildren.add(o); } } } return allChildren.toArray(new Object[allChildren.size()]); } /* (non-Javadoc) * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#getPipelinedChildren(java.lang.Object, java.util.Set) */ public void getPipelinedChildren(Object aParent, Set theCurrentChildren) { // Nothing to do } /* (non-Javadoc) * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#getPipelinedElements(java.lang.Object, java.util.Set) */ public void getPipelinedElements(Object anInput, Set theCurrentElements) { // Replace any model projects with a ModelProject if the input // is a synchronization context if (anInput instanceof ISynchronizationContext) { List newProjects = new ArrayList(); for (Iterator iter = theCurrentElements.iterator(); iter.hasNext();) { Object element = iter.next(); if (element instanceof IProject) { IProject project = (IProject) element; try { if (ModelProject.isModProject(project)) { iter.remove(); newProjects.add(ModelObject.create(project)); } } catch (CoreException e) { FileSystemPlugin.log(e); } } } theCurrentElements.addAll(newProjects); } else if (anInput instanceof ISynchronizationScope) { // When the root is a scope, we should return // our model provider so all model providers appear // at the root of the viewer. theCurrentElements.add(getModelProvider()); } } /* (non-Javadoc) * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#getPipelinedParent(java.lang.Object, java.lang.Object) */ public Object getPipelinedParent(Object anObject, Object aSuggestedParent) { // We're not changing the parenting of any resources return aSuggestedParent; } /* (non-Javadoc) * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#interceptAdd(org.eclipse.ui.navigator.PipelinedShapeModification) */ public PipelinedShapeModification interceptAdd(PipelinedShapeModification anAddModification) { if (anAddModification.getParent() instanceof ISynchronizationContext) { for (Iterator iter = anAddModification.getChildren().iterator(); iter.hasNext();) { Object element = iter.next(); if (element instanceof IProject) { IProject project = (IProject) element; try { if (ModelProject.isModProject(project)) { iter.remove(); } } catch (CoreException e) { FileSystemPlugin.log(e); } } } } return null; } /* (non-Javadoc) * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#interceptRefresh(org.eclipse.ui.navigator.PipelinedViewerUpdate) */ public boolean interceptRefresh(PipelinedViewerUpdate aRefreshSynchronization) { // No need to intercept the refresh return false; } /* (non-Javadoc) * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#interceptRemove(org.eclipse.ui.navigator.PipelinedShapeModification) */ public PipelinedShapeModification interceptRemove(PipelinedShapeModification aRemoveModification) { // No need to intercept the remove return aRemoveModification; } /* (non-Javadoc) * @see org.eclipse.ui.navigator.IPipelinedTreeContentProvider#interceptUpdate(org.eclipse.ui.navigator.PipelinedViewerUpdate) */ public boolean interceptUpdate(PipelinedViewerUpdate anUpdateSynchronization) { // No need to intercept the update return false; } /* (non-Javadoc) * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#diffsChanged(org.eclipse.team.core.diff.IDiffChangeEvent, org.eclipse.core.runtime.IProgressMonitor) */ public void diffsChanged(final IDiffChangeEvent event, IProgressMonitor monitor) { // Override in order to perform custom viewer updates when the diff tree changes Utils.syncExec(new Runnable() { public void run() { handleChange(event); } }, (StructuredViewer) getViewer()); } void handleChange(IDiffChangeEvent event) { Set existingProjects = getVisibleModelProjects(); IProject[] changedProjects = getChangedModelProjects(event); List refreshes = new ArrayList(changedProjects.length); List additions = new ArrayList(changedProjects.length); List removals = new ArrayList(changedProjects.length); for (int i = 0; i < changedProjects.length; i++) { IProject project = changedProjects[i]; if (hasVisibleChanges(event.getTree(), project)) { if (existingProjects.contains(project)) { refreshes.add(ModelObject.create(project)); } else { additions.add(ModelObject.create(project)); } } else if (existingProjects.contains(project)) { removals.add(ModelObject.create(project)); } } if (!removals.isEmpty() || !additions.isEmpty() || !refreshes.isEmpty()) { TreeViewer viewer = (TreeViewer) getViewer(); Tree tree = viewer.getTree(); try { tree.setRedraw(false); if (!additions.isEmpty()) viewer.add(viewer.getInput(), additions.toArray()); if (!removals.isEmpty()) viewer.remove(viewer.getInput(), removals.toArray()); if (!refreshes.isEmpty()) { for (Iterator iter = refreshes.iterator(); iter.hasNext();) { Object element = iter.next(); viewer.refresh(element); } } } finally { tree.setRedraw(true); } } } private boolean hasVisibleChanges(IDiffTree tree, IProject project) { return tree.hasMatchingDiffs(project.getFullPath(), new FastDiffFilter() { public boolean select(IDiff diff) { return isVisible(diff); } }); } /* * Return the list of all projects that are model projects */ private IProject[] getChangedModelProjects(IDiffChangeEvent event) { Set result = new HashSet(); IDiff[] changes = event.getChanges(); for (int i = 0; i < changes.length; i++) { IDiff diff = changes[i]; IResource resource = ResourceDiffTree.getResourceFor(diff); if (resource != null && isModProject(resource.getProject())) { result.add(resource.getProject()); } } IDiff[] additions = event.getAdditions(); for (int i = 0; i < additions.length; i++) { IDiff diff = additions[i]; IResource resource = ResourceDiffTree.getResourceFor(diff); if (resource != null && isModProject(resource.getProject())) { result.add(resource.getProject()); } } IPath[] removals = event.getRemovals(); for (int i = 0; i < removals.length; i++) { IPath path = removals[i]; if (path.segmentCount() > 0) { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0)); if (isModProject(project)) result.add(project); } } return (IProject[]) result.toArray(new IProject[result.size()]); } private boolean isModProject(IProject project) { try { return ModelProject.isModProject(project); } catch (CoreException e) { FileSystemPlugin.log(e); } return false; } /* * Return the set of visible model projects */ private Set getVisibleModelProjects() { TreeViewer viewer = (TreeViewer) getViewer(); Tree tree = viewer.getTree(); TreeItem[] children = tree.getItems(); Set result = new HashSet(); for (int i = 0; i < children.length; i++) { TreeItem control = children[i]; Object data = control.getData(); if (data instanceof ModelProject) { result.add(((ModelProject) data).getProject()); } } return result; } /* (non-Javadoc) * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#propertyChanged(org.eclipse.team.core.diff.IDiffTree, int, org.eclipse.core.runtime.IPath[]) */ public void propertyChanged(IDiffTree tree, int property, IPath[] paths) { // We're overriding this message so that label updates occur for any elements // whose labels may have changed if (getContext() == null) return; final Set updates = new HashSet(); boolean refresh = false; for (int i = 0; i < paths.length; i++) { IPath path = paths[i]; IDiff diff = tree.getDiff(path); if (diff != null) { IResource resource = ResourceDiffTree.getResourceFor(diff); ModelObject object = ModelObject.create(resource); if (object != null) { updates.add(object); } else { // If the resource is a MOE file, we need to update both the MOE and the MOD file // Unfortunately, there's no good way to find the parent file so we'll just refresh everything refresh = true; } } } if (!updates.isEmpty() || refresh) { final boolean refreshAll = refresh; final StructuredViewer viewer = (StructuredViewer) getViewer(); Utils.syncExec(new Runnable() { public void run() { if (refreshAll) viewer.refresh(true); else viewer.update(updates.toArray(new Object[updates.size()]), null); } }, viewer); } } }