/*******************************************************************************
* Copyright (c) 2006 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
* IBM Research
*******************************************************************************/
package com.ibm.research.tagging.resource.actions;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
import org.eclipse.team.internal.ccvs.ui.ICVSUIConstants;
import org.eclipse.ui.IDecoratorManager;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.progress.UIJob;
import com.ibm.research.tagging.core.IWaypoint;
import com.ibm.research.tagging.core.ui.waypoints.WaypointView;
import com.ibm.research.tagging.resource.ResourceWaypointPlugin;
import com.ibm.research.tagging.resource.decorators.IDecoratableResourceContributor;
import com.ibm.research.tagging.resource.decorators.ResourceWaypointDecorator;
public class LinkResourceWaypointActionDelegate implements IViewActionDelegate {
private static final String DECORATOR_ID = "com.ibm.research.tagging.resource.decorator";
private static final String EXTENSION_ID = ResourceWaypointPlugin.PLUGIN_ID + ".decoratableResource";
private WaypointView fView;
private IAction fAction;
private List<IDecoratableResourceContributor> fContributors = new ArrayList<IDecoratableResourceContributor>();
private boolean fLastChecked=false;
private int fLastCount=0;
private Boolean fCVSFontPref=null;
public void init(IViewPart view) {
fView = (WaypointView) view;
fView.getWaypointTableViewer().getTable().addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
if ( fAction!=null )
updatePackageExplorer((Table) e.widget);
}
});
fView.getWaypointTableViewer().getTable().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
// in case workbench gets shutdown and user never toggles off this button - need to restore the CVS font preference if it was changed by us
if ( fCVSFontPref!=null )
{
// @tag hack cvs tagsea resource : restore CVS font decorator if it was enabled previously
IPreferenceStore cvsUiPrefStore = CVSUIPlugin.getPlugin().getPreferenceStore();
cvsUiPrefStore.setValue(ICVSUIConstants.PREF_USE_FONT_DECORATORS, fCVSFontPref.booleanValue());
}
}
});
// setup extensions
setupContributors();
}
private void setupContributors() {
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint extensionPt = registry.getExtensionPoint(EXTENSION_ID);
IExtension[] extensions = extensionPt.getExtensions();
if ( extensions!=null )
{
for (int i=0; i<extensions.length; i++)
{
IExtension extension = extensions[i];
IConfigurationElement[] config = extension.getConfigurationElements();
for (int j=0; j<config.length; j++)
{
try
{
IDecoratableResourceContributor contributor = (IDecoratableResourceContributor) config[j].createExecutableExtension("class");
// @tag debug tagsea extension-point model : comment out when no longer need to verify extensions are loading correctly
System.out.println("adding decoratable resource extension : name=" + config[j].getName() + " id=" + config[j].getAttribute("id"));
fContributors.add(contributor);
}
catch (RuntimeException e)
{
ResourceWaypointPlugin.log("unable to instantiate decoratable resource extension : " + config[j].getName() + " ... skipping",e);
}
catch (CoreException e)
{
ResourceWaypointPlugin.log("unable to instantiate decoratable resource extension : " + config[j].getName() + " ... skipping",e);
}
}
}
}
}
public void run(IAction action) {
fAction = action;
updatePackageExplorer(fView.getWaypointTableViewer().getTable());
}
public void selectionChanged(IAction action, ISelection selection) {
fAction = action;
}
private Set<IAdaptable> findSelectedResources(PackageExplorerPart view)
{
Set<IAdaptable> resources = new HashSet<IAdaptable>();
int count = fView.getWaypointTableViewer().getTable().getItemCount();
for (int i=0; i<count; i++)
{
Object o = fView.getWaypointTableViewer().getElementAt(i);
if ( o instanceof IWaypoint )
{
IWaypoint waypoint = (IWaypoint) o;
for (IDecoratableResourceContributor contributor : fContributors)
{
IResource resource = null;
try {
resource = contributor.getResource(waypoint);
} catch (RuntimeException e) {
ResourceWaypointPlugin.log("error processing IDecoratableResourceContributor " + contributor + " with waypoint " + waypoint,e);
}
if ( resource!=null )
{
resources.add(resource);
// walk up parent hierarchy
IContainer parent = resource.getParent();
while ( parent!=null )
{
resources.add(parent);
parent = parent.getParent();
}
IProject project = resource.getProject();
if ( project!=null )
{
// look for associated working sets
IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
IWorkingSet[] workingSets = workingSetManager.getAllWorkingSets();
if ( workingSets!=null )
{
for (IWorkingSet set : workingSets)
{
IAdaptable[] elements = set.getElements();
for (IAdaptable element : elements)
{
IProject workingSetProject = null;
if ( element instanceof IProject )
workingSetProject = (IProject) element;
else
workingSetProject = (IProject) element.getAdapter(IProject.class);
if ( project.equals(workingSetProject) )
resources.add(set);
}
}
}
}
continue;
}
}
}
}
return resources;
}
private void updatePackageExplorer(Table table) {
if ( !fAction.isChecked() && !fLastChecked )
return; // no longer need to update UI if this feature is turned off
if ( fAction.isChecked()!=fLastChecked ) // only enable/disable via decoratorManager if something has changed
{
IDecoratorManager decoratorManager = PlatformUI.getWorkbench().getDecoratorManager();
if ( fAction.isChecked() )
{
// @tag hack cvs tagsea resource : this is a hack - disable CVS font decorator - because it overrides our decorator! this won't prevent any other coloring decorator from stopping us...
IPreferenceStore cvsUiPrefStore = CVSUIPlugin.getPlugin().getPreferenceStore();
fCVSFontPref = new Boolean(cvsUiPrefStore.getBoolean(ICVSUIConstants.PREF_USE_FONT_DECORATORS)); // save previous pref setting to restore later
cvsUiPrefStore.setValue(ICVSUIConstants.PREF_USE_FONT_DECORATORS, false);
// force enablement of decorator if button is selected
try {
decoratorManager.setEnabled(DECORATOR_ID, true);
} catch (CoreException e) {
ResourceWaypointPlugin.log("error while trying to set enablement on decorator " + DECORATOR_ID + " to " + fAction.isChecked(),e);
}
}
else
{
// toggle off
ResourceWaypointDecorator decorator = (ResourceWaypointDecorator) decoratorManager.getBaseLabelProvider(DECORATOR_ID);
if ( decorator==null )
ResourceWaypointPlugin.log("unable to retrieve decorator for id=" + DECORATOR_ID + " in order to toggle off resource waypoint decorator");
decorator.setResources(null);
decorator.refresh();
// @tag hack cvs tagsea resource : restore CVS font decorator if it was enabled previously
IPreferenceStore cvsUiPrefStore = CVSUIPlugin.getPlugin().getPreferenceStore();
cvsUiPrefStore.setValue(ICVSUIConstants.PREF_USE_FONT_DECORATORS, fCVSFontPref.booleanValue());
}
}
boolean toggledOn = fAction.isChecked() && !fLastChecked; // keep track if the user flipped the toggle on (from off)
fLastChecked = fAction.isChecked();
// check count of items in the table - if it changed, then we need a refresh
TableItem[] items = table.getItems();
int count = 0;
if ( items!=null )
count = items.length;
if ( count==fLastCount && !toggledOn )
return;
fLastCount = count;
UIJob job = new UIJob("update decorators") {
public IStatus runInUIThread(IProgressMonitor monitor) {
IDecoratorManager decoratorManager = PlatformUI.getWorkbench().getDecoratorManager();
ResourceWaypointDecorator decorator = (ResourceWaypointDecorator) decoratorManager.getBaseLabelProvider(DECORATOR_ID);
if ( decorator==null && fAction.isChecked() )
{
// decorator thread not completed yet - we'll wait a bit before giving up
int nTries = 0;
while ( decorator==null )
{
if ( monitor.isCanceled() )
return Status.CANCEL_STATUS;
decorator = (ResourceWaypointDecorator) decoratorManager.getBaseLabelProvider(DECORATOR_ID);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
return Status.CANCEL_STATUS;
}
nTries++;
if ( nTries>10 || !fAction.isChecked() )
{
break;
}
}
}
if ( decorator==null )
{
ResourceWaypointPlugin.log("error - unable to retrieve decorator id=" + DECORATOR_ID + " from decoratorManager");
return Status.OK_STATUS;
}
PackageExplorerPart view = PackageExplorerPart.getFromActivePerspective();
if ( view==null )
view = PackageExplorerPart.openInActivePerspective();
if ( monitor.isCanceled() )
return Status.CANCEL_STATUS;
Set<IAdaptable> found = findSelectedResources(view);
if ( monitor.isCanceled() )
return Status.CANCEL_STATUS;
if ( decorator!=null && found!=null )
{
decorator.setResources(found);
decorator.refresh();
}
fView.setFocus();
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
}