content: /*******************************************************************************
   * Copyright (c) 2000, 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.wst.jsdt.internal.ui.viewsupport;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  import org.eclipse.jface.resource.ColorRegistry;
  import org.eclipse.jface.resource.JFaceResources;
  import org.eclipse.jface.util.IPropertyChangeListener;
  import org.eclipse.jface.util.PropertyChangeEvent;
  import org.eclipse.jface.viewers.IBaseLabelProvider;
  import org.eclipse.jface.viewers.StructuredViewer;
  import org.eclipse.swt.events.DisposeEvent;
  import org.eclipse.swt.events.DisposeListener;
  import org.eclipse.swt.graphics.Color;
  import org.eclipse.swt.widgets.Control;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Item;
  import org.eclipse.swt.widgets.Table;
  import org.eclipse.swt.widgets.Tree;
  import org.eclipse.swt.widgets.TreeItem;
  import org.eclipse.wst.jsdt.internal.ui.preferences.AppearancePreferencePage;
  import org.eclipse.wst.jsdt.ui.PreferenceConstants;
  
  public class ColoredViewersManager implements IPropertyChangeListener {
  	
  	public static final String QUALIFIER_COLOR_NAME= "org.eclipse.wst.jsdt.ui.ColoredLabels.qualifier"; //$NON-NLS-1$
  	public static final String DECORATIONS_COLOR_NAME= "org.eclipse.wst.jsdt.ui.ColoredLabels.decorations"; //$NON-NLS-1$
  	public static final String COUNTER_COLOR_NAME= "org.eclipse.wst.jsdt.ui.ColoredLabels.counter"; //$NON-NLS-1$
  	public static final String INHERITED_COLOR_NAME= "org.eclipse.wst.jsdt.ui.ColoredLabels.inherited"; //$NON-NLS-1$
  	
  	private static ColoredViewersManager fgInstance= new ColoredViewersManager();
  	
  	private Map fManagedViewers;
  	private ColorRegistry fColorRegisty;
  	
  	public ColoredViewersManager() {
  		fManagedViewers= new HashMap();
  		fColorRegisty= JFaceResources.getColorRegistry();
  	}
  	
  	public void installColoredLabels(StructuredViewer viewer) {
  		if (fManagedViewers.containsKey(viewer)) {
  			return; // already installed
  		}
  		if (fManagedViewers.isEmpty()) {
  			// first viewer installed
  			PreferenceConstants.getPreferenceStore().addPropertyChangeListener(this);
  			fColorRegisty.addListener(this);
  		}
  		fManagedViewers.put(viewer, new ManagedViewer(viewer));
  	}
  	
  	
  	public void uninstallColoredLabels(StructuredViewer viewer) {
  		ManagedViewer mv= (ManagedViewer) fManagedViewers.remove(viewer);
  		if (mv == null)
  			return; // not installed
  		
  		if (fManagedViewers.isEmpty()) {
  			PreferenceConstants.getPreferenceStore().removePropertyChangeListener(this);
  			fColorRegisty.removeListener(this);
  			// last viewer uninstalled
  		}
  	}
  	
  	public Color getColorForName(String symbolicName) {
  		return fColorRegisty.get(symbolicName);
  	}
  	
  		
  	public void propertyChange(PropertyChangeEvent event) {
  		String property= event.getProperty();
  		if (property.equals(QUALIFIER_COLOR_NAME) || property.equals(COUNTER_COLOR_NAME) || property.equals(DECORATIONS_COLOR_NAME)
  				|| property.equals(AppearancePreferencePage.PREF_COLORED_LABELS)) {
  			Display.getDefault().asyncExec(new Runnable() {
  				public void run() {
  					refreshAllViewers();
  				}
  			});
  		}
  	}
  	
  	protected final void refreshAllViewers() {
  		for (Iterator iterator= fManagedViewers.values().iterator(); iterator.hasNext();) {
  			ManagedViewer viewer= (ManagedViewer) iterator.next();
  			viewer.refresh();
  		}
  	}
  	
  	private class ManagedViewer implements DisposeListener {
  		
  		private static final String COLORED_LABEL_KEY= "coloredlabel"; //$NON-NLS-1$
  		
  		private StructuredViewer fViewer;
  		private OwnerDrawSupport fOwnerDrawSupport;
  		
  		private ManagedViewer(StructuredViewer viewer) {
  			fViewer= viewer;
  			fOwnerDrawSupport= null;
  			fViewer.getControl().addDisposeListener(this);
  			if (showColoredLabels()) {
  				installOwnerDraw();
  			}
  		}
  		
  		/* (non-Javadoc)
  		 * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
  		 */
  		public void widgetDisposed(DisposeEvent e) {
  			uninstallColoredLabels(fViewer);
  		}
  		
  		public final void refresh() {
  			Control control= fViewer.getControl();
  			if (!control.isDisposed()) {
  				if (showColoredLabels()) {
  					installOwnerDraw();
  				} else {
  					uninstallOwnerDraw();
  				}
  			}
  		}
  		
  		protected void installOwnerDraw() {
  			if (fOwnerDrawSupport == null) {
  				// not yet installed
  				fOwnerDrawSupport= new OwnerDrawSupport(fViewer.getControl()) { // will install itself as listeners
  					public ColoredString getColoredLabel(Item item) {
  						return getColoredLabelForView(item);
  					}
  	
  					public Color getColor(String foregroundColorName, Display display) {
  						return getColorForName(foregroundColorName);
  					}
  				};
  			}
  			refreshViewer();
  		}
  		
  		protected void uninstallOwnerDraw() {
  			if (fOwnerDrawSupport == null)
  				return; // not installed
  
  			fOwnerDrawSupport.dispose(); // removes itself as listener
  			fOwnerDrawSupport= null;
  			refreshViewer();
  		}
  		
  		private void refreshViewer() {
  			Control control= fViewer.getControl();
  			if (!control.isDisposed()) {
  				if (control instanceof Tree) {
  					refresh(((Tree) control).getItems());
  				} else if (control instanceof Table) {
  					refresh(((Table) control).getItems());
  				}
  			}
  		}
  
  		private void refresh(Item[] items) {
  			for (int i= 0; i < items.length; i++) {
  				Item item= items[i];
  				item.setData(COLORED_LABEL_KEY, null);
  				String text= item.getText();
  				item.setText(""); //$NON-NLS-1$
  				item.setText(text);
  				if (item instanceof TreeItem) {
  					refresh(((TreeItem) item).getItems());
  				}
  			}
  		}
  		
  		private ColoredString getColoredLabelForView(Item item) {
  			ColoredString oldLabel= (ColoredString) item.getData(COLORED_LABEL_KEY);
  			String itemText= item.getText();
  			if (oldLabel != null && oldLabel.getString().equals(itemText)) {
  				// avoid accesses to the label provider if possible
  				return oldLabel;
  			}
  			ColoredString newLabel= null;
  			IBaseLabelProvider labelProvider= fViewer.getLabelProvider();
  			if (labelProvider instanceof IRichLabelProvider) {
  				newLabel= ((IRichLabelProvider) labelProvider).getRichTextLabel(item.getData());
  			}
  			if (newLabel == null) {
  				newLabel= new ColoredString(itemText); // fallback. Should never happen.
  			} else if (!newLabel.getString().equals(itemText)) {
  				// the decorator manager has already queued an new update 
  				newLabel= ColoredJavaElementLabels.decorateColoredString(newLabel, itemText, ColoredJavaElementLabels.DECORATIONS_STYLE);
  			}
  			item.setData(COLORED_LABEL_KEY, newLabel); // cache the result
  			return newLabel;
  		}
  
  	}
  	
  	public static boolean showColoredLabels() {
  		String preference= PreferenceConstants.getPreference(AppearancePreferencePage.PREF_COLORED_LABELS, null);
  		return preference != null && Boolean.valueOf(preference).booleanValue();
  	}
  	
  	public static void install(StructuredViewer viewer) {
  		fgInstance.installColoredLabels(viewer);
  	}
  	
  	
  }
  