/***************************************************************************** * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. *****************************************************************************/ package org.eclipse.buckminster.ui; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.cspec.model.CSpec; import org.eclipse.buckminster.core.metadata.MetadataSynchronizer; import org.eclipse.buckminster.core.metadata.WorkspaceInfo; import org.eclipse.buckminster.runtime.AttachableProgressMonitor; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IObjectActionDelegate; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; /** * Operate on the selected object adapted to CSpec.class. * * @author Thomas Hallgren * @author Henrik Lindberg */ public abstract class AbstractCSpecAction implements IObjectActionDelegate { protected IWorkbenchPart activePart; private CSpec selectedComponent; private IAdaptable selection; /** * tries to obtain a CSpec from the current selection. This operation is * potentially long running if {@link WorkspaceInfo} has not been * initialized yet. * * @param progressMonitor * @return the cspec for the given component or <code>null</code> if not * available * @see WorkspaceInfo#isFullyInitialized() */ public CSpec fetchCSpec(final IProgressMonitor progressMonitor) { if (selectedComponent != null) { return selectedComponent; } else if (selection != null) { if (WorkspaceInfo.isFullyInitialized() || Job.getJobManager().isSuspended()) { // Query the cspec directly if the WorkspaceInfo is already // initialized or fall back to // blocking mode if the job manager is currently suspended. selectedComponent = selection.getAdapter(CSpec.class); progressMonitor.done(); } else { // if WorkspaceInfo has not been initialized and the JobManager // is not suspended we try to attach the // given progress monitor to the CatchUpWorkspaceJob IJobChangeListener listener = new JobListener(progressMonitor); Job.getJobManager().addJobChangeListener(listener); selectedComponent = selection.getAdapter(CSpec.class); Job.getJobManager().removeJobChangeListener(listener); } } return selectedComponent; } protected abstract void run(CSpec cspec, Shell shell); @Override public void run(IAction action) { if (activePart == null) return; IWorkbenchPartSite site = activePart.getSite(); final Shell shell = site.getShell(); if (selectedComponent == null) { run(shell); } else { run(selectedComponent, shell); } } protected void run(Shell shell) { MessageDialog.openInformation(shell, null, Messages.no_component_is_selected); } @Override public void selectionChanged(IAction action, ISelection _selection) { selectedComponent = null; if (!(_selection instanceof IStructuredSelection)) return; IStructuredSelection s = (IStructuredSelection) _selection; if (s.size() != 1) return; Object first = s.getFirstElement(); // If the selected object is a CSpec, or adaptable to CSpec, use it. if (first instanceof IAdaptable) { // if the WorkspaceInfo is already initialized, it's safe to query // directly for the adapter if (WorkspaceInfo.isFullyInitialized()) { selectedComponent = ((IAdaptable) first).getAdapter(CSpec.class); action.setEnabled(selectedComponent != null); } else { action.setEnabled(true); } selection = (IAdaptable) first; } } @Override public void setActivePart(IAction action, IWorkbenchPart targetPart) { activePart = targetPart; } protected void setSelectedComponent(CSpec cspec) { selectedComponent = cspec; } } /** * Monitors the jobs that are changed to running and scheduled state until it * finds the WorkspaceCatchUpJob. Once this job is found, it is asked for an * {@link AttachableProgressMonitor}. The given {@link IProgressMonitor} will be * attached to the # {@link AttachableProgressMonitor} and the listener removes * itself from the {@link IJobManager} * * * @see AttachableProgressMonitor * @see IJobManager#removeJobChangeListener(IJobChangeListener) * @author Johannes Utzig * */ class JobListener extends JobChangeAdapter { private static final QualifiedName QN_ATTACHABLE_PROGRESS_MONITOR = new QualifiedName(CorePlugin.getID(), "attachableProgressMonitor"); //$NON-NLS-1$ private IProgressMonitor monitorToAttach; public JobListener(IProgressMonitor monitorToAttach) { super(); this.monitorToAttach = monitorToAttach; } private void handleEvent(IJobChangeEvent event) { if (event.getJob().belongsTo(MetadataSynchronizer.class)) { Job job = event.getJob(); Object o = job.getProperty(QN_ATTACHABLE_PROGRESS_MONITOR); if (o instanceof AttachableProgressMonitor) { // that we got here means that we found the CatchUpWorkspaceJob // so the listener can deregister itself // now AttachableProgressMonitor monitor = (AttachableProgressMonitor) o; Job.getJobManager().removeJobChangeListener(this); monitor.attachProgressMonitor(monitorToAttach); } } } @Override public void running(IJobChangeEvent event) { handleEvent(event); } @Override public void scheduled(IJobChangeEvent event) { handleEvent(event); } }