org.eclipse.compare.internal.patch.PatchCompareEditorInput.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.compare.internal.patch.PatchCompareEditorInput.java

Source

/*******************************************************************************
 * Copyright (c) 2005, 2011 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.compare.internal.patch;

import java.lang.reflect.InvocationTargetException;

import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.CompareUI;
import org.eclipse.compare.CompareViewerPane;
import org.eclipse.compare.IContentChangeListener;
import org.eclipse.compare.IContentChangeNotifier;
import org.eclipse.compare.internal.CompareUIPlugin;
import org.eclipse.compare.internal.ICompareUIConstants;
import org.eclipse.compare.internal.core.patch.DiffProject;
import org.eclipse.compare.internal.core.patch.FileDiffResult;
import org.eclipse.compare.internal.core.patch.FilePatch2;
import org.eclipse.compare.internal.core.patch.HunkResult;
import org.eclipse.compare.patch.PatchConfiguration;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.DiffTreeViewer;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;

public abstract class PatchCompareEditorInput extends CompareEditorInput {

    private static final String IMAGE_CACHE_KEY = "IMAGE_CACHE"; //$NON-NLS-1$

    public static ImageDescriptor createOverlay(Image baseImage, ImageDescriptor overlayImage, int quadrant) {
        return new DecoratorOverlayIcon(baseImage, createArrayFrom(overlayImage, quadrant),
                new Point(Math.max(baseImage.getBounds().width, 16), Math.max(baseImage.getBounds().height, 16)));
    }

    private static ImageDescriptor[] createArrayFrom(ImageDescriptor overlayImage, int quadrant) {
        ImageDescriptor[] descs = new ImageDescriptor[] { null, null, null, null, null };
        descs[quadrant] = overlayImage;
        return descs;
    }

    class PatcherCompareEditorLabelProvider extends LabelProvider {
        private ILabelProvider wrappedProvider;

        public PatcherCompareEditorLabelProvider(ILabelProvider labelProvider) {
            wrappedProvider = labelProvider;
        }

        public String getText(Object element) {
            String text = wrappedProvider.getText(element);
            if (element instanceof PatchDiffNode) {
                PatchDiffNode node = (PatchDiffNode) element;
                if (node instanceof PatchProjectDiffNode) {
                    PatchProjectDiffNode projectNode = (PatchProjectDiffNode) node;
                    if (!Utilities.getProject(projectNode.getDiffProject()).exists()) {
                        text = NLS.bind(PatchMessages.Diff_2Args, new String[] { text,
                                PatchMessages.PreviewPatchLabelDecorator_ProjectDoesNotExist });
                    }
                }
                if (!node.isEnabled()) {
                    return NLS.bind(PatchMessages.Diff_2Args,
                            new String[] { text, PatchMessages.PatcherCompareEditorInput_NotIncluded });
                }
                if (node instanceof PatchFileDiffNode) {
                    PatchFileDiffNode fileNode = (PatchFileDiffNode) node;
                    if (getPatcher().hasCachedContents(fileNode.getDiffResult().getDiff())) {
                        text = NLS.bind(PatchMessages.Diff_2Args,
                                new String[] { text, PatchMessages.HunkMergePage_Merged });
                    }
                    if (!fileNode.fileExists()) {
                        text = NLS.bind(PatchMessages.Diff_2Args,
                                new String[] { text, PatchMessages.PatchCompareEditorInput_0 });
                    }
                }
                if (node instanceof HunkDiffNode) {
                    HunkDiffNode hunkNode = (HunkDiffNode) node;
                    if (hunkNode.isManuallyMerged()) {
                        text = NLS.bind(PatchMessages.Diff_2Args,
                                new String[] { text, PatchMessages.HunkMergePage_Merged });
                    }
                    if (hunkNode.isFuzzUsed()) {
                        text = NLS.bind(PatchMessages.Diff_2Args, new String[] { text, NLS.bind(
                                hunkNode.isAllContextIgnored() ? PatchMessages.PreviewPatchPage_AllContextIgnored
                                        : PatchMessages.PreviewPatchPage_FuzzUsed,
                                new String[] { hunkNode.getHunkResult().getFuzz() + "" }) }); //$NON-NLS-1$
                    }
                }
                if (getPatcher().isRetargeted(node.getPatchElement()))
                    return NLS.bind(PatchMessages.Diff_2Args, new String[] {
                            getPatcher().getOriginalPath(node.getPatchElement()).toString(),
                            NLS.bind(PatchMessages.PreviewPatchPage_Target, new String[] { node.getName() }) });
            }
            return text;
        }

        public Image getImage(Object element) {
            Image image = wrappedProvider.getImage(element);
            if (element instanceof PatchDiffNode) {
                PatchDiffNode node = (PatchDiffNode) element;
                if (!node.isEnabled() && image != null) {
                    LocalResourceManager imageCache = PatchCompareEditorInput
                            .getImageCache(getPatcher().getConfiguration());
                    return imageCache.createImage(createOverlay(image,
                            CompareUIPlugin.getImageDescriptor(ICompareUIConstants.REMOVED_OVERLAY),
                            IDecoration.TOP_LEFT));
                }
            }
            if (element instanceof HunkDiffNode) {
                HunkDiffNode node = (HunkDiffNode) element;
                if (node.isManuallyMerged()) {
                    LocalResourceManager imageCache = PatchCompareEditorInput
                            .getImageCache(getPatcher().getConfiguration());
                    return imageCache.createImage(PatchCompareEditorInput.createOverlay(image,
                            CompareUIPlugin.getImageDescriptor(ICompareUIConstants.IS_MERGED_OVERLAY),
                            IDecoration.TOP_LEFT));
                }
            }
            return image;
        }
    }

    private final DiffNode root;
    private final WorkspacePatcher patcher;
    private TreeViewer viewer;
    private boolean fShowAll;
    private boolean showMatched = false;

    /**
     * Creates a new PatchCompareEditorInput and makes use of the passed in CompareConfiguration
     * to configure the UI elements.
     * @param patcher 
     * @param configuration
     */
    public PatchCompareEditorInput(WorkspacePatcher patcher, CompareConfiguration configuration) {
        super(configuration);
        Assert.isNotNull(patcher);
        this.patcher = patcher;
        root = new DiffNode(Differencer.NO_CHANGE) {
            public boolean hasChildren() {
                return true;
            }
        };
        initializeImageCache();
    }

    private void initializeImageCache() {
        initializeImageCache(patcher.getConfiguration());
    }

    private static LocalResourceManager initializeImageCache(PatchConfiguration patchConfiguration) {
        LocalResourceManager imageCache = new LocalResourceManager(JFaceResources.getResources());
        patchConfiguration.setProperty(IMAGE_CACHE_KEY, imageCache);
        return imageCache;
    }

    protected void handleDispose() {
        super.handleDispose();
        getImageCache(getPatcher().getConfiguration()).dispose();
    }

    public static LocalResourceManager getImageCache(PatchConfiguration patchConfiguration) {
        LocalResourceManager cache = (LocalResourceManager) patchConfiguration.getProperty(IMAGE_CACHE_KEY);
        if (cache == null) {
            return initializeImageCache(patchConfiguration);
        }
        return cache;
    }

    protected Object prepareInput(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
        initLabels();
        return root;
    }

    private void initLabels() {
        CompareConfiguration cc = getCompareConfiguration();
        // set left editable so that unmatched hunks can be edited
        cc.setLeftEditable(true);
        cc.setRightEditable(false);
        //cc.setProperty(CompareEditor.CONFIRM_SAVE_PROPERTY, new Boolean(false));
        cc.setLeftLabel(getCompareConfiguration().getLeftLabel(root));
        cc.setLeftImage(getCompareConfiguration().getLeftImage(root));
        cc.setRightLabel(getCompareConfiguration().getRightLabel(root));
        cc.setRightImage(getCompareConfiguration().getRightImage(root));
    }

    /**
     * Update the presentation of the diff tree.
     */
    protected void updateTree() {
        if (getViewer() != null && !getViewer().getControl().isDisposed())
            getViewer().refresh(true);
    }

    /**
     * Build the diff tree.
     */
    protected void buildTree() {

        // Reset the input node so it is empty
        if (getRoot().hasChildren()) {
            resetRoot();
        }
        // Reset the input of the viewer so the old state is no longer used
        getViewer().setInput(getRoot());

        // Refresh the patcher state
        getPatcher().refresh();

        // Build the diff tree
        if (getPatcher().isWorkspacePatch()) {
            processProjects(getPatcher().getDiffProjects());
        } else {
            processDiffs(getPatcher().getDiffs());
        }

        // Refresh the viewer
        getViewer().refresh();
    }

    private void processDiffs(FilePatch2[] diffs) {
        for (int i = 0; i < diffs.length; i++) {
            processDiff(diffs[i], getRoot());
        }
    }

    private void processProjects(DiffProject[] diffProjects) {
        //create diffProject nodes
        for (int i = 0; i < diffProjects.length; i++) {
            PatchProjectDiffNode projectNode = new PatchProjectDiffNode(getRoot(), diffProjects[i],
                    getPatcher().getConfiguration());
            FilePatch2[] diffs = diffProjects[i].getFileDiffs();
            for (int j = 0; j < diffs.length; j++) {
                FilePatch2 fileDiff = diffs[j];
                processDiff(fileDiff, projectNode);
            }
        }
    }

    private void processDiff(FilePatch2 diff, DiffNode parent) {
        FileDiffResult diffResult = getPatcher().getDiffResult(diff);
        PatchFileDiffNode node = PatchFileDiffNode.createDiffNode(parent, diffResult);
        HunkResult[] hunkResults = diffResult.getHunkResults();
        for (int i = 0; i < hunkResults.length; i++) {
            HunkResult hunkResult = hunkResults[i];
            if (!hunkResult.isOK()) {
                HunkDiffNode hunkNode = HunkDiffNode.createDiffNode(node, hunkResult, true);
                Object left = hunkNode.getLeft();
                if (left instanceof UnmatchedHunkTypedElement) {
                    UnmatchedHunkTypedElement element = (UnmatchedHunkTypedElement) left;
                    element.addContentChangeListener(new IContentChangeListener() {
                        public void contentChanged(IContentChangeNotifier source) {
                            if (getViewer() == null || getViewer().getControl().isDisposed())
                                return;
                            getViewer().refresh(true);
                        }
                    });
                }
            } else if (showMatched) {
                HunkDiffNode.createDiffNode(node, hunkResult, false, true, false);
            }
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.compare.CompareEditorInput#createDiffViewer(org.eclipse.swt.widgets.Composite)
     */
    public Viewer createDiffViewer(Composite parent) {
        viewer = new DiffTreeViewer(parent, getCompareConfiguration()) {
            protected void fillContextMenu(IMenuManager manager) {
                PatchCompareEditorInput.this.fillContextMenu(manager);
            }
        };

        viewer.setLabelProvider(new PatcherCompareEditorLabelProvider((ILabelProvider) viewer.getLabelProvider()));
        viewer.getTree().setData(CompareUI.COMPARE_VIEWER_TITLE,
                PatchMessages.PatcherCompareEditorInput_PatchContents);
        viewer.addOpenListener(new IOpenListener() {
            public void open(OpenEvent event) {
                IStructuredSelection sel = (IStructuredSelection) event.getSelection();
                Object obj = sel.getFirstElement();
                if (obj instanceof HunkDiffNode) {
                    if (((HunkDiffNode) obj).getHunkResult().isOK()) {
                        getCompareConfiguration().setLeftLabel(PatchMessages.PatcherCompareEditorInput_LocalCopy);
                        getCompareConfiguration().setRightLabel(PatchMessages.PreviewPatchPage2_MatchedHunk);
                    } else {
                        getCompareConfiguration().setLeftLabel(PatchMessages.PreviewPatchPage2_PatchedLocalFile);
                        getCompareConfiguration().setRightLabel(PatchMessages.PreviewPatchPage2_OrphanedHunk);
                    }
                } else {
                    getCompareConfiguration().setLeftLabel(PatchMessages.PatcherCompareEditorInput_LocalCopy);
                    getCompareConfiguration().setRightLabel(PatchMessages.PatcherCompareEditorInput_AfterPatch);
                }
            }

        });
        viewer.setFilters(getFilters());
        viewer.setInput(root);
        return viewer;
    }

    private ViewerFilter[] getFilters() {
        return new ViewerFilter[] { new ViewerFilter() {
            public boolean select(Viewer v, Object parentElement, Object element) {
                if (element instanceof PatchDiffNode) {
                    PatchDiffNode node = (PatchDiffNode) element;
                    return node.isEnabled() || isShowAll();
                }
                return false;
            }
        } };
    }

    protected boolean isShowAll() {
        return fShowAll;
    }

    protected void setShowAll(boolean show) {
        fShowAll = show;
    }

    public boolean isShowMatched() {
        return showMatched;
    }

    protected void setShowMatched(boolean show) {
        showMatched = show;
    }

    public void contributeDiffViewerToolbarItems(Action[] actions, boolean workspacePatch) {
        ToolBarManager tbm = CompareViewerPane.getToolBarManager(viewer.getControl().getParent());
        if (tbm != null) {
            tbm.removeAll();

            tbm.add(new Separator("contributed")); //$NON-NLS-1$

            for (int i = 0; i < actions.length; i++) {
                tbm.appendToGroup("contributed", actions[i]); //$NON-NLS-1$
            }

            tbm.update(true);
        }
    }

    public TreeViewer getViewer() {
        return viewer;
    }

    public DiffNode getRoot() {
        return root;
    }

    public void resetRoot() {
        IDiffElement[] children = root.getChildren();
        for (int i = 0; i < children.length; i++) {
            IDiffElement child = children[i];
            root.remove(child);
        }
    }

    public WorkspacePatcher getPatcher() {
        return patcher;
    }

    public boolean confirmRebuild(String message) {
        if (getPatcher().hasCachedContents()) {
            if (promptToDiscardCachedChanges(message)) {
                getPatcher().clearCachedContents();
                return true;
            }
            return false;
        }
        return true;
    }

    private boolean promptToDiscardCachedChanges(String message) {
        return MessageDialog.openConfirm(viewer.getControl().getShell(), PatchMessages.PatcherCompareEditorInput_0,
                message);
    }

    /**
     * Return whether this input has a result to apply. The input
     * has a result to apply if at least one hunk is selected for inclusion.
     * @return whether this input has a result to apply
     */
    public boolean hasResultToApply() {
        boolean atLeastOneIsEnabled = false;
        if (getViewer() != null) {
            IDiffElement[] elements = getRoot().getChildren();
            for (int i = 0; i < elements.length; i++) {
                IDiffElement element = elements[i];
                if (isEnabled(element)) {
                    atLeastOneIsEnabled = true;
                    break;
                }
            }
        }
        return atLeastOneIsEnabled;
    }

    private boolean isEnabled(IDiffElement element) {
        if (element instanceof PatchDiffNode) {
            PatchDiffNode node = (PatchDiffNode) element;
            return node.isEnabled();
        }
        return false;
    }

    protected abstract void fillContextMenu(IMenuManager manager);

    public Viewer findStructureViewer(Viewer oldViewer, ICompareInput input, Composite parent) {
        if (org.eclipse.compare.internal.Utilities.isHunk(input))
            return null;
        return super.findStructureViewer(oldViewer, input, parent);
    }
}