org.eclipse.team.ui.synchronize.AbstractSynchronizeLabelProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.team.ui.synchronize.AbstractSynchronizeLabelProvider.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2010 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.ui.synchronize;

import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.mapping.ModelProvider;
import org.eclipse.core.resources.mapping.ResourceMapping;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.graphics.*;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.diff.IThreeWayDiff;
import org.eclipse.team.core.mapping.ISynchronizationContext;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.internal.ui.*;
import org.eclipse.team.internal.ui.mapping.ResourceDiffCompareInput;
import org.eclipse.team.internal.ui.synchronize.ImageManager;
import org.eclipse.team.ui.ISharedImages;
import org.eclipse.team.ui.TeamUI;
import org.eclipse.team.ui.mapping.*;

/**
 * A label provider wrapper that adds synchronization image and/or text decorations
 * to the image and label obtained from the delegate provider.
 * 
 * @since 3.2
 */
public abstract class AbstractSynchronizeLabelProvider implements ILabelProvider {

    private ImageManager localImageManager;

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
     */
    public Image getImage(Object element) {
        Image base = getDelegateImage(element);
        if (isDecorationEnabled() && base != null) {
            Image decorateImage = decorateImage(base, element);
            base = decorateImage;
        }
        if (isIncludeOverlays() && base != null) {
            base = addOverlays(base, element);
        }
        return base;
    }

    /**
     * Decorate the image with the appropriate diff decorations.
     * By default, this method uses the diff associated with
     * the given element to determine how to decorate the image.
     * It then uses the {@link CompareConfiguration#getImage(Image, int)}
     * method to apply the decoration to the base image.
     * @param base the base image to be decorated.
     * @param element the element
     * @return the image decorated appropriately using the diff associated with
     * the element
     * @see #getDiff(Object)
     * @see CompareConfiguration#getImage(Image, int)
     */
    protected Image decorateImage(Image base, Object element) {
        Image decoratedImage;
        if (element instanceof ICompareInput) {
            ICompareInput ci = (ICompareInput) element;
            decoratedImage = getCompareImage(base, ci.getKind());
        } else {
            IDiff node = getDiff(element);
            decoratedImage = getCompareImage(base, node);
        }
        // The reason we still overlay the compare image is to
        // ensure that the image width for all images shown in the viewer
        // are consistent.
        return decoratedImage;
    }

    /**
     * Return the image for the item from the delegate label provider.
     * @param element the element
     * @return the image for the item from the delegate label provider
     */
    protected Image getDelegateImage(Object element) {
        ILabelProvider modelLabelProvider = getDelegateLabelProvider();
        Image base = modelLabelProvider.getImage(internalGetElement(element));
        if (base == null && element instanceof ModelProvider) {
            ModelProvider mp = (ModelProvider) element;
            base = getImageManager().getImage(getImageDescriptor(mp));
        }
        return base;
    }

    private ImageDescriptor getImageDescriptor(ModelProvider provider) {
        ITeamContentProviderManager manager = TeamUI.getTeamContentProviderManager();
        ITeamContentProviderDescriptor desc = manager.getDescriptor(provider.getId());
        return desc.getImageDescriptor();
    }

    private Object internalGetElement(Object element) {
        if (element instanceof TreePath) {
            TreePath tp = (TreePath) element;
            element = tp.getLastSegment();
        }
        return element;
    }

    private Image getCompareImage(Image base, IDiff node) {
        int compareKind = getCompareKind(node);
        return getCompareImage(base, compareKind);
    }

    /**
     * Returns an image showing the specified change kind applied to a given base image.
     * 
     * @nooverride This method is not intended to be re-implemented or extended by clients.
     * @noreference This method is not intended to be referenced by clients.
     */
    protected Image getCompareImage(Image base, int compareKind) {
        return getImageManager().getImage(base, compareKind);
    }

    private int getCompareKind(IDiff node) {
        return ResourceDiffCompareInput.getCompareKind(node);
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
     */
    public String getText(Object element) {
        String base = getDelegateText(element);
        if (isSyncInfoInTextEnabled()) {
            return decorateText(base, element);
        }
        return base;
    }

    /**
     * Obtain the text for the object from the delegate label provider.
     * @param element the element
     * @return the text label for the element
     */
    protected String getDelegateText(Object element) {
        ILabelProvider modelLabelProvider = getDelegateLabelProvider();
        element = internalGetElement(element);
        String base = modelLabelProvider.getText(element);
        if (base == null || base.length() == 0) {
            if (element instanceof ModelProvider) {
                ModelProvider provider = (ModelProvider) element;
                base = Utils.getLabel(provider);
            }
        }
        return base;
    }

    /**
     * Decorate the text with the appropriate diff decorations.
     * By default, this method uses the diff associated with
     * the given element to determine how to decorate the text.
     * @param base the base text to be decorated.
     * @param element the element
     * @return the text decorated appropriately using the diff associated with
     * the element
     * @see #getDiff(Object)
     */
    protected String decorateText(String base, Object element) {
        IDiff node = getDiff(element);
        if (node != null && node.getKind() != IDiff.NO_CHANGE) {
            String syncKindString = node.toDiffString();
            return NLS.bind(TeamUIMessages.AbstractSynchronizationLabelProvider_0,
                    new String[] { base, syncKindString });
        }
        return base;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
     */
    public void addListener(ILabelProviderListener listener) {
        getDelegateLabelProvider().addListener(listener);
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
     */
    public void dispose() {
        if (localImageManager != null)
            localImageManager.dispose();
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
     */
    public boolean isLabelProperty(Object element, String property) {
        return getDelegateLabelProvider().isLabelProperty(internalGetElement(element), property);
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
     */
    public void removeListener(ILabelProviderListener listener) {
        getDelegateLabelProvider().removeListener(listener);
    }

    /**
     * Returns whether the synchronization state should be included in the
     * text of the label. By default, the Team preference is used to determine
     * what to return. Subclasses may override.
     * @return whether the synchronization state should be included in the
     * text of the label
     */
    protected boolean isSyncInfoInTextEnabled() {
        return isDecorationEnabled() && TeamUIPlugin.getPlugin().getPreferenceStore()
                .getBoolean(IPreferenceIds.SYNCVIEW_VIEW_SYNCINFO_IN_LABEL);
    }

    /**
     * Return the label provider that will return the text and image 
     * appropriate for the given model element. Subclasses are responsible for
     * disposing of the label provider.
     * @return the label provider that will return the text and image 
     * appropriate for the given model element
     */
    protected abstract ILabelProvider getDelegateLabelProvider();

    /**
     * Return whether the label provider should decorate with the synchronization state.
     * @return whether the label provider should decorate with the synchronization state
     */
    protected abstract boolean isDecorationEnabled();

    /**
     * Return the sync kind of the given element. This is used
     * to determine how to decorate the image and label of the
     * element. The sync kind is described in the {@link SyncInfo}
     * class. A <code>null</code> is returned by default.
     * @param element the element being tested
     * @return the sync kind of the given element
     */
    protected IDiff getDiff(Object element) {
        return null;
    }

    private Image addOverlays(Image base, Object element) {
        if (!isIncludeOverlays())
            return base;

        ImageDescriptor[] overlayImages = new ImageDescriptor[4];
        boolean hasOverlay = false;

        // Decorate with the busy indicator
        if (isBusy(element)) {
            overlayImages[IDecoration.TOP_LEFT] = TeamUIPlugin.getImageDescriptor(ISharedImages.IMG_HOURGLASS_OVR);
            hasOverlay = true;
        }
        // Decorate with propagated conflicts and problem markers
        if (!isConflicting(element)) {
            // if the folder is already conflicting then don't bother propagating
            if (hasDecendantConflicts(element)) {
                overlayImages[IDecoration.BOTTOM_RIGHT] = TeamUIPlugin
                        .getImageDescriptor(ISharedImages.IMG_CONFLICT_OVR);
                hasOverlay = true;
            }
        }
        int severity = getMarkerSeverity(element);
        if (severity == IMarker.SEVERITY_ERROR) {
            overlayImages[IDecoration.BOTTOM_LEFT] = TeamUIPlugin.getImageDescriptor(ISharedImages.IMG_ERROR_OVR);
            hasOverlay = true;
        } else if (severity == IMarker.SEVERITY_WARNING) {
            overlayImages[IDecoration.BOTTOM_LEFT] = TeamUIPlugin.getImageDescriptor(ISharedImages.IMG_WARNING_OVR);
            hasOverlay = true;
        }
        if (hasOverlay) {
            ImageDescriptor overlay = new DecorationOverlayIcon(base, overlayImages,
                    new Point(base.getBounds().width, base.getBounds().height));
            return getImageManager().getImage(overlay);
        }
        return base;
    }

    /**
     * Indicate whether the overlays provided by this class should be applied.
     * By default, <code>false</code> is returned. Subclasses may override
     * and control individual overlays by overriding the appropriate
     * query methods. Overlays provided by this class include problem marker
     * severity ({@link #getMarkerSeverity(Object)}), propagated conflicts 
     * ({@link #hasDecendantConflicts(Object)} and busy state ({@link #isBusy(Object)}).
     * @return whether the overlays provided by this class should be applied
     */
    protected boolean isIncludeOverlays() {
        return false;
    }

    /**
     * Return the marker severity (one of IMarker.SEVERITY_ERROR or
     * IMarker.SEVERITY_WARNING) to be overlayed on the given element or -1 if
     * there are no markers. By Default, the element is adapted to resource
     * mapping in order to look for markers.
     * <p>
     * Although this class handles providing the overlays, it does not react 
     * to marker changes. Subclasses must issue label updates when the markers on 
     * a logical model element change.
     * 
     * @param element
     *            the element
     * @return the marker severity
     */
    protected int getMarkerSeverity(Object element) {
        ResourceMapping mapping = Utils.getResourceMapping(internalGetElement(element));
        int result = -1;
        if (mapping != null) {
            try {
                IMarker[] markers = mapping.findMarkers(IMarker.PROBLEM, true, null);
                for (int i = 0; i < markers.length; i++) {
                    IMarker marker = markers[i];
                    Integer severity = (Integer) marker.getAttribute(IMarker.SEVERITY);
                    if (severity != null) {
                        if (severity.intValue() == IMarker.SEVERITY_ERROR) {
                            return IMarker.SEVERITY_ERROR;
                        } else if (severity.intValue() == IMarker.SEVERITY_WARNING) {
                            result = IMarker.SEVERITY_WARNING;
                        }
                    }
                }
            } catch (CoreException e) {
                // Ignore
            }
        }
        return result;
    }

    /**
     * Return whether the given element has descendant conflicts.
     * By default, <code>false</code> is returned. Subclasses 
     * may override.
     * @param element the element
     * @return whether the given element has descendant conflicts
     */
    protected boolean hasDecendantConflicts(Object element) {
        return false;
    }

    private boolean isConflicting(Object element) {
        IDiff node = getDiff(element);
        if (node != null) {
            if (node instanceof IThreeWayDiff) {
                IThreeWayDiff twd = (IThreeWayDiff) node;
                return twd.getDirection() == IThreeWayDiff.CONFLICTING;
            }
        }
        return false;
    }

    /**
     * Return whether the given element is busy (i.e. is involved
     * in an operation. By default, <code>false</code> is returned.
     * Subclasses may override.
     * @param element the element
     * @return whether the given element is busy
     */
    protected boolean isBusy(Object element) {
        return false;
    }

    /**
     * Method that provides a custom font for elements that are
     * busy. Although this label provider does not implement
     * {@link IFontProvider}, subclasses that wish to get 
     * busy indication using a font can do so.
     * @param element the element
     * @return the font to indicate that the element is busy
     */
    public Font getFont(Object element) {
        if (isBusy(internalGetElement(element))) {
            return JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT);
        }
        return null;
    }

    private ImageManager getImageManager() {
        ISynchronizationContext context = getContext();
        if (context != null) {
            return ImageManager.getImageManager(context, getConfiguration());
        }
        if (localImageManager == null) {
            localImageManager = new ImageManager();
        }
        return localImageManager;
    }

    private ISynchronizePageConfiguration getConfiguration() {
        if (this instanceof SynchronizationLabelProvider) {
            SynchronizationLabelProvider slp = (SynchronizationLabelProvider) this;
            return (ISynchronizePageConfiguration) slp.getExtensionSite().getExtensionStateModel()
                    .getProperty(ITeamContentProviderManager.P_SYNCHRONIZATION_PAGE_CONFIGURATION);
        }
        return null;
    }

    private ISynchronizationContext getContext() {
        if (this instanceof SynchronizationLabelProvider) {
            SynchronizationLabelProvider slp = (SynchronizationLabelProvider) this;
            return slp.getContext();
        }
        return null;
    }

}