Java tutorial
/******************************************************************************* * 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; } }