org.eclipse.team.examples.filesystem.ui.NonSyncModelMergePage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.team.examples.filesystem.ui.NonSyncModelMergePage.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2009 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.filesystem.ui;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.List;

import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.core.resources.*;
import org.eclipse.core.resources.mapping.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.action.*;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.*;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.mapping.IMergeContext;
import org.eclipse.team.core.mapping.provider.ResourceDiffTree;
import org.eclipse.team.examples.filesystem.FileSystemPlugin;
import org.eclipse.team.internal.ui.mapping.SynchronizationResourceMappingContext;
import org.eclipse.team.ui.mapping.ISynchronizationCompareAdapter;
import org.eclipse.team.ui.synchronize.ModelMergeOperation;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.Page;

/**
 * This class provides the page for the {@link NonSyncMergePart}.
 */
public class NonSyncModelMergePage extends Page {

    IMergeContext context;
    TreeViewer viewer;
    List mappings;

    /*
     * Content provider that returns the list of conflicting mappings
     */
    class PageContentProvider implements ITreeContentProvider {
        public Object[] getChildren(Object parentElement) {
            if (parentElement instanceof IMergeContext) {
                if (mappings == null)
                    // TODO: should be using a real progress monitor
                    computeMappings(new NullProgressMonitor());
                return mappings.toArray();
            }
            return new Object[0];
        }

        public Object getParent(Object element) {
            if (element instanceof ResourceMapping) {
                return context;
            }
            return null;
        }

        public boolean hasChildren(Object element) {
            if (element instanceof IMergeContext) {
                return true;
            }
            return false;
        }

        public Object[] getElements(Object inputElement) {
            return getChildren(inputElement);
        }

        public void dispose() {
            // Nothing to do
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            // Nothing to do
        }
    }

    /*
     * Label provider that provides a label and image for conflicting resource mappings
     */
    class PageLabelProvider extends LabelProvider {
        public String getText(Object element) {
            if (element instanceof ResourceMapping) {
                ResourceMapping mapping = (ResourceMapping) element;
                ISynchronizationCompareAdapter adapter = NonSyncMergePart.getCompareAdapter(mapping);
                if (adapter != null)
                    return adapter.getPathString(mapping) + "("
                            + mapping.getModelProvider().getDescriptor().getLabel() + ")";
            }
            if (element instanceof ICompareInput) {
                ICompareInput ci = (ICompareInput) element;
                ci.getName();
            }
            return super.getText(element);
        }

        public Image getImage(Object element) {
            if (element instanceof ICompareInput) {
                ICompareInput ci = (ICompareInput) element;
                ci.getImage();
            }
            if (element instanceof ResourceMapping) {
                ResourceMapping mapping = (ResourceMapping) element;
                ISynchronizationCompareAdapter adapter = NonSyncMergePart.getCompareAdapter(mapping);
                ICompareInput input = adapter.asCompareInput(context, mapping.getModelObject());
                if (input != null)
                    return input.getImage();
            }
            return super.getImage(element);
        }
    }

    /*
     * Sorter that sorts mappings by model and then name
     */
    class PageSorter extends ViewerSorter {
        public int compare(Viewer viewer, Object e1, Object e2) {
            if (e1 instanceof ResourceMapping && e2 instanceof ResourceMapping) {
                ResourceMapping m1 = (ResourceMapping) e1;
                ResourceMapping m2 = (ResourceMapping) e2;
                if (m1.getModelProvider() == m2.getModelProvider()) {
                    return getLabel(m1).compareTo(getLabel(m2));
                }
                return compare(m1, m2);
            }
            return super.compare(viewer, e1, e2);
        }

        private int compare(ResourceMapping m1, ResourceMapping m2) {
            ModelProvider[] sorted = ModelMergeOperation
                    .sortByExtension(new ModelProvider[] { m1.getModelProvider(), m2.getModelProvider() });
            return sorted[0] == m1.getModelProvider() ? -1 : 1;
        }

        private String getLabel(ResourceMapping mapping) {
            ISynchronizationCompareAdapter adapter = NonSyncMergePart.getCompareAdapter(mapping);
            if (adapter != null)
                return adapter.getPathString(mapping);
            return "";
        }
    }

    public NonSyncModelMergePage(IMergeContext context) {
        super();
        this.context = context;
    }

    /**
     * Create the list of all mappings that overlap with the out-of-sync files.
     */
    public void computeMappings(IProgressMonitor monitor) {
        IModelProviderDescriptor[] descriptors = ModelProvider.getModelProviderDescriptors();
        mappings = new ArrayList();
        for (int i = 0; i < descriptors.length; i++) {
            IModelProviderDescriptor descriptor = descriptors[i];
            // Get the subset of files that this model provider cares about
            try {
                IResource[] resources = descriptor.getMatchingResources(getOutOfSyncFiles());
                if (resources.length > 0) {
                    ModelProvider provider = descriptor.getModelProvider();
                    // Get the mappings for those resources
                    ResourceMapping[] mappings = provider.getMappings(resources,
                            new SynchronizationResourceMappingContext(context), monitor);
                    this.mappings.addAll(Arrays.asList(mappings));
                }
            } catch (CoreException e) {
                FileSystemPlugin.log(e);
            }
        }
    }

    private IResource[] getOutOfSyncFiles() {
        IDiff[] diffs = getContext().getDiffTree().getDiffs(ResourcesPlugin.getWorkspace().getRoot(),
                IResource.DEPTH_INFINITE);
        List result = new ArrayList();
        for (int i = 0; i < diffs.length; i++) {
            IDiff diff = diffs[i];
            IResource resource = ResourceDiffTree.getResourceFor(diff);
            if (resource.getType() == IResource.FILE)
                result.add(resource);
        }
        return (IResource[]) result.toArray(new IResource[result.size()]);
    }

    /**
     * Return the merge context.
     * @return the merge context
     */
    public IMergeContext getContext() {
        return context;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.Page#createControl(org.eclipse.swt.widgets.Composite)
     */
    public void createControl(Composite parent) {
        viewer = new TreeViewer(parent);
        viewer.setContentProvider(new PageContentProvider());
        viewer.setLabelProvider(new PageLabelProvider());
        viewer.setSorter(new PageSorter());
        hookContextMenu(viewer);
        viewer.setInput(context);
    }

    /*
     * Hook the context menu to display the Overwrite and Mark-as-merged actions
     */
    private void hookContextMenu(final TreeViewer viewer) {
        final MenuManager menuMgr = new MenuManager();
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                fillContextMenu(manager);
            }
        });
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
    }

    /**
     * Fill the context menu.
     * @param manager the context menu manager
     */
    protected void fillContextMenu(IMenuManager manager) {
        /*
         * Add a mark as merged action. Because we are not using the 
         * Synchronization framework and, more specifically, the
         * Common Navigator content provider for the model providers,
         * we do not have access to the merge handlers of the model.
         * Therefore, we are writing are action to detect whether there
         * are files that overlap between the selected model elements and
         * unselected model elements.
         */
        Action markAsMerged = new Action("Mark as Merged") {
            public void run() {
                try {
                    final IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
                    PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
                        public void run(IProgressMonitor monitor) throws InvocationTargetException {
                            IDiff[] diffs = getSelectedDiffs(selection, monitor);
                            if (!checkForModelOverlap(diffs, monitor)) {
                                return;
                            }
                            try {
                                context.markAsMerged(diffs, false, monitor);
                            } catch (CoreException e) {
                                throw new InvocationTargetException(e);
                            }
                        }
                    });
                } catch (InvocationTargetException e) {
                    FileSystemPlugin.log(new Status(IStatus.ERROR, FileSystemPlugin.ID, 0,
                            e.getTargetException().getMessage(), e.getTargetException()));
                } catch (InterruptedException e) {
                    // Ignore
                }
            }
        };
        manager.add(markAsMerged);
    }

    protected IDiff[] getSelectedDiffs(IStructuredSelection selection, IProgressMonitor monitor) {
        Object[] elements = selection.toArray();
        return getDiffs(elements, monitor);
    }

    private IDiff[] getDiffs(Object[] elements, IProgressMonitor monitor) {
        Set result = new HashSet();
        for (int i = 0; i < elements.length; i++) {
            Object element = elements[i];
            try {
                if (element instanceof ResourceMapping) {
                    ResourceMapping mapping = (ResourceMapping) element;
                    ResourceTraversal[] traversals = mapping
                            .getTraversals(new SynchronizationResourceMappingContext(context), monitor);
                    result.addAll(Arrays.asList(context.getDiffTree().getDiffs(traversals)));
                }
            } catch (CoreException e) {
                FileSystemPlugin.log(e);
            }
        }
        return (IDiff[]) result.toArray(new IDiff[result.size()]);
    }

    /**
     * Check whether any of the diffs overlap with mappings that are not selected
     * @param diffs
     * @return
     */
    protected boolean checkForModelOverlap(IDiff[] diffs, IProgressMonitor monitor) {
        // TODO: This check should see if the diffs are also part of mappings 
        // that are not included in the selection. 
        return true;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.Page#getControl()
     */
    public Control getControl() {
        if (viewer != null)
            return viewer.getControl();
        return null;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.Page#setFocus()
     */
    public void setFocus() {
        if (viewer != null)
            viewer.getControl().setFocus();
    }

    public ISelectionProvider getViewer() {
        return viewer;
    }

}