/******************************************************************************* | |
* Copyright (c) 2008, 2015 Mia-Software. | |
* 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: | |
* Nicolas Bros (Mia-Software) - initial API and implementation | |
* Nicolas Payneau (Mia-Software) - Enable editability | |
* Nicolas Guyomar (Mia-Software) - Code Synchronization | |
* Nicolas Guyomar (Mia_software) - Bug 333651 Remove of the MoDisco EPackage view and of the metamodel browsing button | |
* Gregoire Dupe (Mia-Software) - Bug 404263 - EditingDomainProvider does not work when using IResourceEditorInput | |
* Grégoire Dupé (Mia-Software) - Bug 471096 - MetaclassInstance features have to be moved to an EMF dedicated plug-in | |
* Gregoire Dupe (Mia-Software) - Bug 472182 - Missing debug information in EcoreBrowser.handleChangedResources(2636) | |
*******************************************************************************/ | |
package org.eclipse.gmt.modisco.infra.browser.editors; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.EventObject; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.LinkedHashMap; | |
import java.util.List; | |
import java.util.ListIterator; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.concurrent.CancellationException; | |
import org.eclipse.core.resources.IFile; | |
import org.eclipse.core.resources.IMarker; | |
import org.eclipse.core.resources.IResourceChangeEvent; | |
import org.eclipse.core.resources.IResourceChangeListener; | |
import org.eclipse.core.resources.IStorage; | |
import org.eclipse.core.resources.ResourcesPlugin; | |
import org.eclipse.core.runtime.CoreException; | |
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.IPath; | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import org.eclipse.core.runtime.IStatus; | |
import org.eclipse.core.runtime.NullProgressMonitor; | |
import org.eclipse.core.runtime.Platform; | |
import org.eclipse.core.runtime.Status; | |
import org.eclipse.core.runtime.jobs.Job; | |
import org.eclipse.emf.common.command.BasicCommandStack; | |
import org.eclipse.emf.common.command.Command; | |
import org.eclipse.emf.common.command.CommandStack; | |
import org.eclipse.emf.common.command.CommandStackListener; | |
import org.eclipse.emf.common.command.CommandWrapper; | |
import org.eclipse.emf.common.command.CompoundCommand; | |
import org.eclipse.emf.common.notify.Adapter; | |
import org.eclipse.emf.common.notify.Notification; | |
import org.eclipse.emf.common.notify.impl.AdapterImpl; | |
import org.eclipse.emf.common.ui.MarkerHelper; | |
import org.eclipse.emf.common.ui.viewer.IViewerProvider; | |
import org.eclipse.emf.common.util.BasicDiagnostic; | |
import org.eclipse.emf.common.util.Diagnostic; | |
import org.eclipse.emf.common.util.EList; | |
import org.eclipse.emf.common.util.TreeIterator; | |
import org.eclipse.emf.common.util.URI; | |
import org.eclipse.emf.ecore.EClass; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.EPackage; | |
import org.eclipse.emf.ecore.EStructuralFeature; | |
import org.eclipse.emf.ecore.EValidator; | |
import org.eclipse.emf.ecore.plugin.EcorePlugin; | |
import org.eclipse.emf.ecore.resource.Resource; | |
import org.eclipse.emf.ecore.resource.ResourceSet; | |
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; | |
import org.eclipse.emf.ecore.util.EContentAdapter; | |
import org.eclipse.emf.ecore.util.EcoreUtil; | |
import org.eclipse.emf.edit.command.AddCommand; | |
import org.eclipse.emf.edit.command.CreateChildCommand; | |
import org.eclipse.emf.edit.command.DeleteCommand; | |
import org.eclipse.emf.edit.command.RemoveCommand; | |
import org.eclipse.emf.edit.command.SetCommand; | |
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; | |
import org.eclipse.emf.edit.domain.EditingDomain; | |
import org.eclipse.emf.edit.domain.IEditingDomainProvider; | |
import org.eclipse.emf.edit.provider.ComposedAdapterFactory; | |
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor; | |
import org.eclipse.emf.edit.provider.IItemPropertySource; | |
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; | |
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory; | |
import org.eclipse.emf.edit.ui.dnd.EditingDomainViewerDropAdapter; | |
import org.eclipse.emf.edit.ui.dnd.LocalTransfer; | |
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider; | |
import org.eclipse.emf.edit.ui.provider.PropertyDescriptor; | |
import org.eclipse.emf.edit.ui.provider.PropertySource; | |
import org.eclipse.emf.edit.ui.util.EditUIMarkerHelper; | |
import org.eclipse.emf.edit.ui.util.EditUIUtil; | |
import org.eclipse.emf.edit.ui.view.ExtendedPropertySheetPage; | |
import org.eclipse.emf.facet.util.core.Logger; | |
import org.eclipse.gmt.modisco.infra.browser.Messages; | |
import org.eclipse.gmt.modisco.infra.browser.MoDiscoBrowserPlugin; | |
import org.eclipse.gmt.modisco.infra.browser.actions.LoadFacetsAction; | |
import org.eclipse.gmt.modisco.infra.browser.core.DragAndDropOnLinkCommand; | |
import org.eclipse.gmt.modisco.infra.browser.core.DragAndDropOnModelElementCommand; | |
import org.eclipse.gmt.modisco.infra.browser.core.InstancesForMetaclass; | |
import org.eclipse.gmt.modisco.infra.browser.core.InstancesForMetaclasses; | |
import org.eclipse.gmt.modisco.infra.browser.core.InstancesForMetaclasses.MetaclassesChangeListener; | |
import org.eclipse.gmt.modisco.infra.browser.core.MetaclassList; | |
import org.eclipse.gmt.modisco.infra.browser.core.ModelElementItemEx; | |
import org.eclipse.gmt.modisco.infra.browser.core.QueryItem; | |
import org.eclipse.gmt.modisco.infra.browser.core.SearchResults; | |
import org.eclipse.gmt.modisco.infra.browser.custom.MetamodelView; | |
import org.eclipse.gmt.modisco.infra.browser.custom.core.CustomizationsCatalog; | |
import org.eclipse.gmt.modisco.infra.browser.dialogs.ErrorsDialog; | |
import org.eclipse.gmt.modisco.infra.browser.extensions.LoadingDepthRegistry; | |
import org.eclipse.gmt.modisco.infra.browser.extensions.listeners.DoubleClickListener; | |
import org.eclipse.gmt.modisco.infra.browser.preferences.PreferenceConstants; | |
import org.eclipse.gmt.modisco.infra.browser.queries.SelectedQueriesManager; | |
import org.eclipse.gmt.modisco.infra.browser.queries.SelectedQuery; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.ChangeListener; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.UnwrappingSelectionProvider; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.Activator; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.AppearanceConfiguration; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.CustomTreePainter; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.customization.CustomizationEngine; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.model.AttributeItem; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.model.BigListItem; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.model.ITreeElement; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.model.LinkItem; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.model.ModelElementItem; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.util.EMFUtil; | |
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.util.ImageProvider; | |
import org.eclipse.gmt.modisco.infra.common.core.internal.builder.AbstractMoDiscoCatalog.ModiscoCatalogChangeListener; | |
import org.eclipse.gmt.modisco.infra.common.core.logging.MoDiscoLogger; | |
import org.eclipse.gmt.modisco.infra.common.ui.internal.controls.FormStyleSashForm; | |
import org.eclipse.gmt.modisco.infra.common.ui.internal.controls.Tooltip; | |
import org.eclipse.gmt.modisco.infra.common.ui.internal.editorInputs.IResourceEditorInput; | |
import org.eclipse.gmt.modisco.infra.common.ui.internal.util.DialogUtils; | |
import org.eclipse.gmt.modisco.infra.facet.Facet; | |
import org.eclipse.gmt.modisco.infra.facet.FacetSet; | |
import org.eclipse.gmt.modisco.infra.facet.core.FacetSetCatalog; | |
import org.eclipse.gmt.modisco.infra.facet.core.adapters.instances.MetaclassInstancesAdapterFactoryWithFacet; | |
import org.eclipse.gmt.modisco.infra.facet.core.adapters.instances.MetaclassInstancesAdapterWithFacet; | |
import org.eclipse.jface.action.IMenuListener; | |
import org.eclipse.jface.action.IMenuManager; | |
import org.eclipse.jface.action.IStatusLineManager; | |
import org.eclipse.jface.action.MenuManager; | |
import org.eclipse.jface.dialogs.IDialogSettings; | |
import org.eclipse.jface.dialogs.MessageDialog; | |
import org.eclipse.jface.dialogs.ProgressMonitorDialog; | |
import org.eclipse.jface.preference.IPreferenceStore; | |
import org.eclipse.jface.resource.FontDescriptor; | |
import org.eclipse.jface.resource.JFaceResources; | |
import org.eclipse.jface.util.IPropertyChangeListener; | |
import org.eclipse.jface.util.PropertyChangeEvent; | |
import org.eclipse.jface.viewers.ISelection; | |
import org.eclipse.jface.viewers.ISelectionChangedListener; | |
import org.eclipse.jface.viewers.ISelectionProvider; | |
import org.eclipse.jface.viewers.IStructuredSelection; | |
import org.eclipse.jface.viewers.ITreeContentProvider; | |
import org.eclipse.jface.viewers.ITreeSelection; | |
import org.eclipse.jface.viewers.SelectionChangedEvent; | |
import org.eclipse.jface.viewers.StructuredSelection; | |
import org.eclipse.jface.viewers.StructuredViewer; | |
import org.eclipse.jface.viewers.TreePath; | |
import org.eclipse.jface.viewers.TreeSelection; | |
import org.eclipse.jface.viewers.TreeViewer; | |
import org.eclipse.jface.viewers.Viewer; | |
import org.eclipse.modisco.util.emf.core.internal.allinstances.MetaclassInstances; | |
import org.eclipse.osgi.util.NLS; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.dnd.DND; | |
import org.eclipse.swt.dnd.Transfer; | |
import org.eclipse.swt.events.FocusEvent; | |
import org.eclipse.swt.events.FocusListener; | |
import org.eclipse.swt.events.KeyAdapter; | |
import org.eclipse.swt.events.KeyEvent; | |
import org.eclipse.swt.events.MouseAdapter; | |
import org.eclipse.swt.events.MouseEvent; | |
import org.eclipse.swt.events.SelectionAdapter; | |
import org.eclipse.swt.events.SelectionEvent; | |
import org.eclipse.swt.graphics.Font; | |
import org.eclipse.swt.graphics.Point; | |
import org.eclipse.swt.layout.FillLayout; | |
import org.eclipse.swt.layout.GridData; | |
import org.eclipse.swt.layout.GridLayout; | |
import org.eclipse.swt.widgets.Button; | |
import org.eclipse.swt.widgets.Composite; | |
import org.eclipse.swt.widgets.Control; | |
import org.eclipse.swt.widgets.Display; | |
import org.eclipse.swt.widgets.Event; | |
import org.eclipse.swt.widgets.Listener; | |
import org.eclipse.swt.widgets.Menu; | |
import org.eclipse.swt.widgets.Shell; | |
import org.eclipse.swt.widgets.Text; | |
import org.eclipse.swt.widgets.Tree; | |
import org.eclipse.swt.widgets.TreeItem; | |
import org.eclipse.ui.IActionBars; | |
import org.eclipse.ui.IEditorInput; | |
import org.eclipse.ui.IEditorPart; | |
import org.eclipse.ui.IEditorSite; | |
import org.eclipse.ui.INavigationLocation; | |
import org.eclipse.ui.INavigationLocationProvider; | |
import org.eclipse.ui.IPartListener; | |
import org.eclipse.ui.IStorageEditorInput; | |
import org.eclipse.ui.IWorkbench; | |
import org.eclipse.ui.IWorkbenchPart; | |
import org.eclipse.ui.PartInitException; | |
import org.eclipse.ui.PlatformUI; | |
import org.eclipse.ui.actions.WorkspaceModifyOperation; | |
import org.eclipse.ui.contexts.IContextActivation; | |
import org.eclipse.ui.contexts.IContextService; | |
import org.eclipse.ui.dialogs.SaveAsDialog; | |
import org.eclipse.ui.forms.widgets.ExpandableComposite; | |
import org.eclipse.ui.forms.widgets.Form; | |
import org.eclipse.ui.forms.widgets.FormToolkit; | |
import org.eclipse.ui.forms.widgets.Section; | |
import org.eclipse.ui.ide.IGotoMarker; | |
import org.eclipse.ui.part.EditorPart; | |
import org.eclipse.ui.part.FileEditorInput; | |
import org.eclipse.ui.progress.IWorkbenchSiteProgressService; | |
import org.eclipse.ui.views.properties.IPropertyDescriptor; | |
import org.eclipse.ui.views.properties.IPropertySheetPage; | |
import org.eclipse.ui.views.properties.IPropertySource; | |
import org.eclipse.ui.views.properties.PropertySheet; | |
import org.eclipse.ui.views.properties.PropertySheetPage; | |
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; | |
/** | |
* MoDisco model editor: a two pane editor. The left pane shows the list of | |
* metaclasses and the right pane shows the list of instances of the metaclass | |
* selected in the left pane. | |
* <p> | |
* The following pop-up menus can be contributed to this part: | |
* <ul> | |
* <li>{@link EcoreBrowser#MENU_ID} | |
* <li>{@link MetaclassViewer#MENU_ID} | |
* </ul> | |
*/ | |
public class EcoreBrowser extends EditorPart implements ISelectionProvider, IMenuListener, | |
IViewerProvider, INavigationLocationProvider, MetaclassesChangeListener, | |
IEditingDomainProvider, IGotoMarker { | |
public static final String MENU_ID = EcoreBrowser.EDITOR_ID + ".menu"; //$NON-NLS-1$ | |
private static final int MAIN_FORM_MARGIN_HEIGHT = 6; | |
private static final int MAIN_FORM_MARGIN_WIDTH = 4; | |
private static final int RIGHT_PANE_SASH_WEIGHT = 65; | |
private static final int LEFT_PANE_SASH_WEIGHT = 35; | |
private static final int SASH_WIDTH = 4; | |
public static final String EDITOR_ID = "org.eclipse.gmt.modisco.infra.browser.editorID"; //$NON-NLS-1$ | |
private static final String PROPERTY_VIEW_ID = "org.eclipse.ui.views.PropertySheet"; //$NON-NLS-1$ | |
private ResourceSet fResourceSet; | |
private Resource model; | |
/** An adapter factory that uses the registry */ | |
private ComposedAdapterFactory adapterFactoryWithRegistry; | |
/** The property sheet page. */ | |
private IPropertySheetPage propertySheetPage; | |
/** The tree part of the model editor. */ | |
private TreeViewer treeViewer; | |
private BrowserContentProvider fContentProvider; | |
private BrowserLabelProvider fLabelProvider; | |
/** The tree component (instances pane) */ | |
private Tree fTree; | |
/** The list of metaclasses that appears in the left pane of the editor */ | |
private MetaclassViewer metaclassViewer; | |
/** This listens to the tree viewer's selection. */ | |
private ISelectionChangedListener selectionChangedListener; | |
/** | |
* This keeps track of all the | |
* {@link org.eclipse.jface.viewers.ISelectionChangedListener}s that are | |
* listening to this editor. | |
*/ | |
private final Collection<ISelectionChangedListener> selectionChangedListeners = new ArrayList<ISelectionChangedListener>(); | |
/** This keeps track of the selection of the editor as a whole. */ | |
private ISelection editorSelection = StructuredSelection.EMPTY; | |
/** | |
* Resources that have been removed since last activation. | |
*/ | |
private final Collection<Resource> removedResources = new ArrayList<Resource>(); | |
/** | |
* Resources that have been changed since last activation. | |
*/ | |
private final Collection<Resource> changedResources = new ArrayList<Resource>(); | |
private final Collection<Resource> savedResources = new ArrayList<Resource>(); | |
/** This listens for workspace changes. */ | |
private final IResourceChangeListener resourceChangeListener; | |
private Job openModelJob = null; | |
/** | |
* Controls whether the problem indication should be updated. | |
*/ | |
private boolean updateProblemIndication = true; | |
/** | |
* Map to store the diagnostic associated with a resource. | |
*/ | |
private final Map<Resource, Diagnostic> resourceToDiagnosticMap = new LinkedHashMap<Resource, Diagnostic>(); | |
/** | |
* The MarkerHelper is responsible for creating workspace resource markers | |
* presented in Eclipse's Problems View. | |
*/ | |
private final MarkerHelper markerHelper = new EditUIMarkerHelper(); | |
/** Whether the Browser has finished loading */ | |
private boolean loaded = false; | |
/** List of actions that must be done once the browser is loaded */ | |
private final List<Runnable> doWhenLoaded = new ArrayList<Runnable>(); | |
private Collection<EPackage> referencedEPackages = null; | |
private Composite typesPaneComposite; | |
private Composite instancesPaneComposite; | |
private Button errorsButton; | |
/** | |
* This keeps track of the editing domain that is used to track all changes | |
* to the model. | |
*/ | |
private AdapterFactoryEditingDomain editingDomain; | |
/** | |
* The configuration of this editor, which is passed to the adapters, so | |
* that they can use it to change their behavior accordingly | |
*/ | |
private final BrowserConfiguration browserConfiguration; | |
/** The composite in which the editor is displayed */ | |
private Composite parentComposite; | |
/** The search box */ | |
private Text searchBox; | |
/** The search job, to allow cancellation in case of a big model */ | |
private Job searchJob = null; | |
/** | |
* The input of the tree viewer, saved before filtering by search, and | |
* restored afterwards | |
*/ | |
private Object savedInput; | |
/** A listener on changes to fonts settings */ | |
private IPropertyChangeListener fontChangeListener; | |
/** Listens to changes in the loaded customizations, and updates the viewers */ | |
private ChangeListener fCustomizationEngineChangeListener = null; | |
/** Listens to changes in the Facet catalog, and updates the viewers */ | |
private ModiscoCatalogChangeListener fFacetsChangeListener = null; | |
/** Allows optimized refreshes of the viewer */ | |
private Job refreshJob = null; | |
private FormStyleSashForm sashForm; | |
// Initialize to HORIZONTAL representation | |
private int styleSashForm = SWT.HORIZONTAL; | |
private CustomTreePainter customTreePainter; | |
private FormToolkit fFormToolkit; | |
private Form form; | |
private LeftPane leftPane; | |
private TreeToolBar instancesToolBar; | |
private BrowserSettingsPersistence settingsPersistence; | |
/** Indicates the editor is being disposed */ | |
private boolean disposing = false; | |
private BasicDiagnostic fDiagnostic; | |
/** | |
* This listens for when the Properties view becomes active | |
*/ | |
private final IPartListener partListener = new IPartListener() { | |
public void partActivated(final IWorkbenchPart p) { | |
if (p instanceof PropertySheet) { | |
if (((PropertySheet) p).getCurrentPage() == EcoreBrowser.this | |
.getPropertySheetPage()) { | |
getActionBarContributor().setActiveEditor(EcoreBrowser.this); | |
handleActivate(); | |
} | |
} else if (p == EcoreBrowser.this) { | |
handleActivate(); | |
} | |
} | |
public void partBroughtToTop(final IWorkbenchPart p) { | |
// Ignore. | |
} | |
public void partClosed(final IWorkbenchPart p) { | |
// Ignore. | |
} | |
public void partDeactivated(final IWorkbenchPart p) { | |
// Ignore. | |
} | |
public void partOpened(final IWorkbenchPart p) { | |
// Ignore. | |
} | |
}; | |
/** Create the Mia Ecore model editor. */ | |
public EcoreBrowser() { | |
super(); | |
this.browserConfiguration = new BrowserConfiguration(this); | |
// load user settings | |
this.browserConfiguration.getAppearanceConfiguration().load(); | |
this.resourceChangeListener = new WorkspaceChangeListener(this); | |
} | |
/** Set the selection into the tree viewer */ | |
public void setSelectionToViewer(final Collection<?> selection) { | |
final Collection<?> theSelection = selection; | |
if (theSelection != null && !theSelection.isEmpty()) { | |
Runnable runnable = new Runnable() { | |
public void run() { | |
if (EcoreBrowser.this.treeViewer != null) { | |
EcoreBrowser.this.treeViewer.setSelection(new StructuredSelection( | |
theSelection.toArray()), true); | |
} | |
} | |
}; | |
getSite().getShell().getDisplay().asyncExec(runnable); | |
} | |
} | |
/** @return the viewer as required by the {@link IViewerProvider} interface. */ | |
public Viewer getViewer() { | |
return this.treeViewer; | |
} | |
public MetaclassViewer getMetaclassViewer() { | |
return this.metaclassViewer; | |
} | |
/** | |
* Create a context menu for the viewer, add a listener, and register the | |
* menu for extension. | |
*/ | |
protected void createContextMenuFor(final StructuredViewer viewer) { | |
final MenuManager contextMenu = new MenuManager("#PopUp"); //$NON-NLS-1$ | |
contextMenu.setRemoveAllWhenShown(true); | |
contextMenu.addMenuListener(this); | |
final Menu menu = contextMenu.createContextMenu(viewer.getControl()); | |
viewer.getControl().setMenu(menu); | |
getSite().registerContextMenu(EcoreBrowser.MENU_ID, contextMenu, | |
new UnwrappingSelectionProvider(viewer)); | |
} | |
/** Load a resource based on the editor's input. */ | |
protected Resource createModel() { | |
Resource result = null; | |
Exception exception = null; | |
// this.fResourceSet.setURIConverter(createURIConverter()); | |
this.fResourceSet.getURIConverter().getURIMap().putAll(EcorePlugin.computePlatformURIMap()); | |
final URI resourceURI = EditUIUtil.getURI(getEditorInput()); | |
try { | |
final IEditorInput editorInput = getEditorInput(); | |
if (editorInput instanceof FileEditorInput) { | |
// Load the resource | |
ResourceSet resourceSet = this.editingDomain.getResourceSet(); | |
synchronized (resourceSet) { | |
result = resourceSet.getResource(resourceURI, true); | |
} | |
this.fResourceSet = this.editingDomain.getResourceSet(); | |
} else if (editorInput instanceof IResourceEditorInput) { | |
IResourceEditorInput resourceEditorInput = (IResourceEditorInput) editorInput; | |
result = resourceEditorInput.getResource(); | |
// this.fResourceSet.getResources().add(result); | |
ResourceSet resourceSet = result.getResourceSet(); | |
if (resourceSet != null) { | |
this.fResourceSet = resourceSet; | |
} | |
setPartName(resourceEditorInput.getName()); | |
} else if (editorInput instanceof IStorageEditorInput) { | |
IStorageEditorInput storageEditorInput = (IStorageEditorInput) editorInput; | |
IStorage storage = storageEditorInput.getStorage(); | |
InputStream inputStream = storage.getContents(); | |
Resource resource = this.fResourceSet.createResource(URI.createURI(resourceURI | |
.toString())); | |
resource.load(inputStream, Collections.emptyMap()); | |
result = resource; | |
} else { | |
final String resolveURI = resourceURI.toString(); | |
final EPackage ePackage = this.fResourceSet.getPackageRegistry().getEPackage( | |
resolveURI); | |
if (ePackage != null) { | |
result = ePackage.eResource(); | |
if (result != null) { | |
this.fResourceSet.getResources().add(result); | |
setPartName(ePackage.getName()); | |
} | |
} else { | |
Display.getDefault().asyncExec(new Runnable() { | |
public void run() { | |
MessageDialog.openWarning(getSite().getShell(), | |
Messages.EcoreBrowser_cannotOpenModelFromURI, NLS.bind( | |
Messages.EcoreBrowser_cannotFindEPackageWithThatURI, | |
resolveURI)); | |
} | |
}); | |
} | |
} | |
initializeEditingDomain(this.fResourceSet); | |
} catch (final Exception e) { | |
exception = e; | |
MoDiscoBrowserPlugin.logException(e); | |
Display.getDefault().asyncExec(new Runnable() { | |
public void run() { | |
MessageDialog.openError(EcoreBrowser.this.parentComposite.getShell(), | |
Messages.EcoreBrowser_errorLoadingModel, e.toString()); | |
} | |
}); | |
this.fResourceSet.getResource(resourceURI, false); | |
} | |
this.fResourceSet.setURIConverter(BrowserUtils.createURIConverter()); | |
// look for errors in the Resource | |
if (result != null) { | |
Diagnostic diagnostic = analyzeResourceProblems(result, exception); | |
if (diagnostic.getSeverity() != Diagnostic.OK) { | |
this.resourceToDiagnosticMap.put(result, diagnostic); | |
} | |
} | |
this.editingDomain.getResourceSet().eAdapters().add(this.problemIndicationAdapter); | |
return result; | |
} | |
@Override | |
protected void setPartName(final String partName) { | |
Display.getDefault().syncExec(new Runnable() { | |
public void run() { | |
EcoreBrowser.super.setPartName(partName); | |
} | |
}); | |
} | |
protected static final String LOADING_MESSAGE = Messages.EcoreBrowser_loadingModelPlaceholder; | |
public static final String HUMAN_READABLE_NAME = Messages.EcoreBrowser_MoDisco_Model_Browser; | |
/** Create the editor composite. */ | |
@Override | |
public void createPartControl(final Composite parent) { | |
this.fFormToolkit = new FormToolkit(parent.getDisplay()); | |
this.form = this.fFormToolkit.createForm(parent); | |
this.parentComposite = parent; | |
parent.setLayout(new FillLayout()); | |
initializeEditingDomain(); | |
final FillLayout fillLayout = new FillLayout(); | |
fillLayout.marginWidth = EcoreBrowser.MAIN_FORM_MARGIN_WIDTH; | |
fillLayout.marginHeight = EcoreBrowser.MAIN_FORM_MARGIN_HEIGHT; | |
this.form.getBody().setLayout(fillLayout); | |
// use an adapter factory that looks in the registry | |
this.browserConfiguration.getAppearanceConfiguration().setAdapterFactory( | |
this.adapterFactoryWithRegistry); | |
this.browserConfiguration.setSelectedQueriesManager(new SelectedQueriesManager()); | |
this.sashForm = new FormStyleSashForm(this.form.getBody(), this.styleSashForm, | |
this.fFormToolkit) { | |
@Override | |
protected void createContents() { | |
createLeftPane(this); | |
createTreePane(this); | |
} | |
}; | |
this.sashForm.setSashWidth(EcoreBrowser.SASH_WIDTH); | |
setupInitialTreeFont(); | |
this.sashForm.setWeights(new int[] { EcoreBrowser.LEFT_PANE_SASH_WEIGHT, | |
EcoreBrowser.RIGHT_PANE_SASH_WEIGHT }); | |
// keep track of the selection, to be able to restore it when using the | |
// "back" button | |
addSelectionChangedListener(new ISelectionChangedListener() { | |
public void selectionChanged(final SelectionChangedEvent event) { | |
markNavigationLocation(); | |
} | |
}); | |
createContextMenuFor(this.treeViewer); | |
DragAdapter.create(this.treeViewer); | |
int dndOperations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK; | |
Transfer[] transfers = new Transfer[] { LocalTransfer.getInstance() }; | |
EditingDomainViewerDropAdapter editingDomainViewerDropAdapter = new EditingDomainViewerDropAdapter( | |
this.editingDomain, this.treeViewer); | |
this.treeViewer.addDropSupport(dndOperations, transfers, editingDomainViewerDropAdapter); | |
getMetaclassViewer().setInput(EcoreBrowser.LOADING_MESSAGE); | |
this.treeViewer.setInput(EcoreBrowser.LOADING_MESSAGE); | |
createAttributeItemTooltip(); | |
} | |
private void createAttributeItemTooltip() { | |
Tooltip tooltip = new Tooltip() { | |
@Override | |
protected String getText(final TreeItem item) { | |
Object data = item.getData(); | |
if (data instanceof AttributeItem) { | |
AttributeItem attributeItem = (AttributeItem) data; | |
if (!attributeItem.getText().contains(attributeItem.getValueText())) { | |
return attributeItem.getValueText(); | |
} | |
} | |
return null; | |
} | |
@Override | |
protected void positionTooltip(final TreeItem treeItem, final Point pt, | |
final Point tooltipSize) { | |
Point point = EcoreBrowser.this.treeViewer.getTree().toDisplay( | |
treeItem.getBounds().x, treeItem.getBounds().y); | |
pt.x = point.x; | |
pt.y = point.y; | |
} | |
}; | |
tooltip.installOn(this.treeViewer.getTree()); | |
} | |
/** | |
* Load the model in the background, to avoid freezing the UI during this | |
* long-running operation. | |
* <p> | |
* <b>see</b>: Bug 325120 - [Model Browser] don't freeze UI while loading | |
* model | |
* | |
* @param monitor | |
*/ | |
protected boolean backgroundOpenModel(final IProgressMonitor monitor) { | |
try { | |
checkCancelled(monitor); | |
initResourceSet(); | |
checkCancelled(monitor); | |
checkResourceSet(); | |
if (this.model == null) { | |
return false; | |
} | |
Display.getDefault().syncExec(new Runnable() { | |
public void run() { | |
getMetaclassViewer().setInput( | |
getBrowserConfiguration().getInstancesForMetaclasses()); | |
/* | |
* Select the metaclass corresponding to the 'root' element | |
* (that is, the 'model' element). This in turn sets the | |
* input of the treeview. | |
*/ | |
getMetaclassViewer().selectRootElement(); | |
} | |
}); | |
loadDefaultFacetSets(this.model); | |
IDialogSettings settingsForCurrentMetamodel = getSettingsPersistence() | |
.loadLastSettingsForCurrentMetamodel(); | |
List<Facet> lastFacets = getSettingsPersistence().getLastFacets( | |
settingsForCurrentMetamodel); | |
LoadFacetsAction.loadFacets(lastFacets, this); | |
// for (Facet facet : lastFacets) { | |
// this.browserConfiguration.getAppearanceConfiguration().loadFacet(facet); | |
// checkCancelled(monitor); | |
// } | |
checkCancelled(monitor); | |
List<MetamodelView> lastCustomizations = getSettingsPersistence() | |
.getLastCustomizations(settingsForCurrentMetamodel); | |
if (lastCustomizations.size() > 0) { | |
loadCustomizations(lastCustomizations); | |
} else { | |
loadDefaultCustomizations(); | |
} | |
checkCancelled(monitor); | |
// note: must be done after adding or removing facets too | |
this.browserConfiguration.getInstancesForMetaclasses().buildDerivationTree(); | |
// add a listener to reload when Facets are modified | |
reloadOnFacetChange(); | |
checkCancelled(monitor); | |
} catch (CancellationException e) { | |
// canceled : nothing more to do | |
return false; | |
} catch (ThreadDeath e) { | |
// canceled : nothing more to do | |
return false; | |
} | |
finishedLoading(); | |
return true; | |
} | |
private void checkResourceSet() { | |
for (Resource resource : this.fResourceSet.getResources()) { | |
if (resource.getURI() == null) { | |
MoDiscoLogger.logError( | |
"The ResourceSet opened in the browser contains a Resource with a null URI. " //$NON-NLS-1$ | |
+ "This can be the cause of NullPointerExceptions.", //$NON-NLS-1$ | |
MoDiscoBrowserPlugin.getPlugin()); | |
} | |
} | |
} | |
private void finishedLoading() { | |
for (Runnable runnable : this.doWhenLoaded) { | |
try { | |
Display.getDefault().syncExec(runnable); | |
} catch (Exception e) { | |
MoDiscoLogger.logError(e, Activator.getDefault()); | |
} | |
} | |
this.getSite().getShell().getDisplay().asyncExec(new Runnable() { | |
public void run() { | |
firePropertyChange(PROP_INPUT); | |
} | |
}); | |
} | |
private void checkCancelled(final IProgressMonitor monitor) { | |
if (monitor.isCanceled() || this.treeViewer.getTree().isDisposed()) { | |
throw new CancellationException(); | |
} | |
} | |
public BrowserSettingsPersistence getSettingsPersistence() { | |
if (this.settingsPersistence == null) { | |
this.settingsPersistence = new BrowserSettingsPersistence(getMetamodelURI(), this, | |
this.browserConfiguration); | |
} | |
return this.settingsPersistence; | |
} | |
/** | |
* @return the URI of the EPackage corresponding to the EClass of the main | |
* resource's root element | |
*/ | |
public String getMetamodelURI() { | |
if (this.model == null) { | |
return ""; //$NON-NLS-1$ | |
} | |
try { | |
EList<EObject> contents = this.model.getContents(); | |
if (contents.size() > 0) { | |
EObject eObject = contents.get(0); | |
EClass eClass = eObject.eClass(); | |
if (eClass != null) { | |
return eClass.getEPackage().getNsURI(); | |
} | |
} | |
} catch (Exception e) { | |
MoDiscoLogger.logError(e, MoDiscoBrowserPlugin.getPlugin()); | |
} | |
return ""; //$NON-NLS-1$ | |
} | |
/** | |
* @return {@link EPackage}s of {@link EClass}es from the model's main | |
* {@link Resource} | |
*/ | |
public Collection<EPackage> getReferencedEPackages() { | |
if (this.referencedEPackages != null) { | |
return this.referencedEPackages; | |
} | |
Set<EPackage> ePackages = new HashSet<EPackage>(); | |
try { | |
if (this.model != null) { | |
TreeIterator<EObject> allContents = this.model.getAllContents(); | |
while (allContents.hasNext()) { | |
EObject eObject = allContents.next(); | |
EClass eClass = eObject.eClass(); | |
if (eClass != null) { | |
EPackage ePackage = eClass.getEPackage(); | |
if (ePackage != null) { | |
ePackages.add(ePackage); | |
} | |
} | |
} | |
} | |
} catch (Exception e) { | |
MoDiscoLogger.logError(e, MoDiscoBrowserPlugin.getPlugin()); | |
} | |
this.referencedEPackages = ePackages; | |
return ePackages; | |
} | |
protected void initResourceSet() { | |
// create an empty resource set | |
this.fResourceSet = createResourceSet(); | |
HashSet<Resource> browsedResources = new HashSet<Resource>(); | |
Resource mainResource; | |
this.model = createModel(); | |
mainResource = this.model; | |
if (mainResource != null) { | |
browsedResources.add(mainResource); | |
} | |
this.browserConfiguration.setResourceSet(this.fResourceSet); | |
addReferencedResources(mainResource, browsedResources); | |
this.browserConfiguration.setBrowsedResources(browsedResources); | |
this.browserConfiguration.getAppearanceConfiguration().getFacetContext() | |
.setResources(browsedResources); | |
final InstancesForMetaclasses instancesForMetaclasses = createInstancesForMetaclasses(browsedResources); | |
this.browserConfiguration.setInstancesForMetaclasses(instancesForMetaclasses); | |
instancesForMetaclasses.addListener(this); | |
// see Bug 322985 - resources lazy loading and dynamic type panel | |
// completion | |
// watch ResourceSet to be notified when a Resource is lazy-loaded | |
// when that happens, add its elements to the Types panel | |
this.fResourceSet.eAdapters().add(new AdapterImpl() { | |
@Override | |
public void notifyChanged(final Notification notification) { | |
if (notification.getFeatureID(ResourceSet.class) == ResourceSet.RESOURCE_SET__RESOURCES) { | |
int eventType = notification.getEventType(); | |
if (eventType == Notification.ADD) { | |
Object newValue = notification.getNewValue(); | |
if (newValue instanceof Resource) { | |
Resource resource = (Resource) newValue; | |
EcoreBrowser.this.browserConfiguration.addBrowsedResource(resource); | |
instancesForMetaclasses.watchResource(resource); | |
EcoreBrowser.this.browserConfiguration.getAppearanceConfiguration() | |
.touch(); | |
refreshDelayed(true); | |
} | |
} | |
if (eventType == Notification.REMOVE) { | |
Object oldValue = notification.getOldValue(); | |
if (oldValue instanceof Resource) { | |
Resource resource = (Resource) oldValue; | |
EcoreBrowser.this.browserConfiguration.removeBrowsedResource(resource); | |
instancesForMetaclasses.unwatchResource(resource); | |
EcoreBrowser.this.browserConfiguration.getAppearanceConfiguration() | |
.touch(); | |
refreshDelayed(true); | |
} | |
} | |
} | |
} | |
}); | |
} | |
protected InstancesForMetaclasses createInstancesForMetaclasses( | |
final Set<Resource> browsedResources) { | |
return new InstancesForMetaclasses(this.browserConfiguration, browsedResources); | |
} | |
/** | |
* Create the resourceSet. This method can be overridden by subclasses. | |
* | |
* @return The ResourceSet. | |
*/ | |
protected ResourceSet createResourceSet() { | |
return new ResourceSetImpl(); | |
} | |
/** | |
* Load FacetSet defined as default for the root EPackage of root elements | |
* in the given resource | |
*/ | |
private void loadDefaultFacetSets(final Resource resource) { | |
synchronized (resource) { | |
for (EObject root : resource.getContents()) { | |
EPackage rootEPackage = root.eClass().getEPackage(); | |
Set<FacetSet> defaultFacetSets = FacetSetCatalog.getSingleton() | |
.getDefaultFacetSets(rootEPackage); | |
if (defaultFacetSets != null) { | |
Set<Facet> facetsToLoad = new HashSet<Facet>(); | |
for (FacetSet facetSet : defaultFacetSets) { | |
if (facetSet != null) { | |
facetsToLoad.addAll(facetSet.getFacets()); | |
} | |
} | |
} | |
} | |
} | |
} | |
/** | |
* If proxies are found, ask the user whether to load resources referenced | |
* by proxies found in the given resource, and up to which depth. | |
* | |
* @param resource | |
* the resource in which to look for proxies to resolve | |
* @param allResources | |
* the set of resources to which to add resources referenced by | |
* proxies | |
*/ | |
private void addReferencedResources(final Resource resource, final Set<Resource> allResources) { | |
IPreferenceStore preferenceStore = MoDiscoBrowserPlugin.getPlugin().getPreferenceStore(); | |
// only walk through the resource contents if necessary | |
int registryLoadingDepth = LoadingDepthRegistry.getInstance().getLoadingDepth( | |
getMetamodelURI()); | |
if (preferenceStore.getInt(PreferenceConstants.P_BROWSER_LOADING_DEPTH) != 0 | |
|| preferenceStore.getBoolean(PreferenceConstants.P_BROWSER_ASK_LOADING_DEPTH) | |
|| (registryLoadingDepth != LoadingDepthRegistry.UNDEFINED && registryLoadingDepth != 0)) { | |
addReferencedResourcesInternal(resource, allResources, 1); | |
} | |
} | |
/** | |
* Adds resources referenced by proxies found in the given resources to the | |
* set <code>allResources</code> | |
* | |
* @param resource | |
* the resource in which to look for proxies to resolve | |
* @param allResources | |
* the set of resources to which to add resources referenced by | |
* proxies | |
* @param currentDepth | |
* the current depth | |
* | |
* @see EcoreBrowser#addReferencedResources(Resource, Set) | |
*/ | |
private void addReferencedResourcesInternal(final Resource resource, | |
final Set<Resource> allResources, final int currentDepth) { | |
final Set<Resource> directReferencedResources = new HashSet<Resource>(); | |
synchronized (resource) { | |
for (EObject root : resource.getContents()) { | |
Map<EObject, Collection<EStructuralFeature.Setting>> externalReferences = EcoreUtil.ExternalCrossReferencer | |
.find(root); | |
if (!externalReferences.isEmpty()) { | |
int loadingDepth = this.browserConfiguration | |
.getReferencedResourcesLoadingDepth(); | |
if (loadingDepth == BrowserConfiguration.NOT_YET_ASKED) { | |
int registryLoadingDepth = LoadingDepthRegistry.getInstance() | |
.getLoadingDepth(getMetamodelURI()); | |
// whether user settings override registry settings | |
boolean overridden = MoDiscoBrowserPlugin | |
.getPlugin() | |
.getPreferenceStore() | |
.getBoolean( | |
PreferenceConstants.P_BROWSER_OVERRIDE_METAMODEL_SPECIFIC_SETTINGS); | |
if (registryLoadingDepth == LoadingDepthRegistry.UNDEFINED || overridden) { | |
final int defaultLoadingDepth = MoDiscoBrowserPlugin.getPlugin() | |
.getPreferenceStore() | |
.getInt(PreferenceConstants.P_BROWSER_LOADING_DEPTH); | |
if (MoDiscoBrowserPlugin.getPlugin().getPreferenceStore() | |
.getBoolean(PreferenceConstants.P_BROWSER_ASK_LOADING_DEPTH)) { | |
// get shell on UI thread | |
final Shell[] shell = new Shell[1]; | |
Display.getDefault().syncExec(new Runnable() { | |
public void run() { | |
shell[0] = getSite().getShell(); | |
} | |
}); | |
loadingDepth = BrowserUtils | |
.askUserForDepthToLoadReferencedResources( | |
defaultLoadingDepth, shell[0]); | |
} else { | |
loadingDepth = defaultLoadingDepth; | |
if (loadingDepth < -1) { | |
loadingDepth = 0; | |
} | |
} | |
} else { | |
loadingDepth = registryLoadingDepth; | |
} | |
this.browserConfiguration.setReferencedResourcesLoadingDepth(loadingDepth); | |
} | |
if (loadingDepth != -1 && loadingDepth < currentDepth) { | |
return; | |
} | |
for (EObject external : externalReferences.keySet()) { | |
Resource externalResource; | |
if (external.eIsProxy()) { | |
externalResource = EcoreUtil.resolve(external, root).eResource(); | |
} else { | |
externalResource = external.eResource(); | |
} | |
if (externalResource != null) { | |
directReferencedResources.add(externalResource); | |
} else { | |
MoDiscoLogger | |
.logError( | |
"Failed to load an external element: " + external.eClass().getName() //$NON-NLS-1$ | |
+ " " + EcoreUtil.getURI(external), //$NON-NLS-1$ | |
MoDiscoBrowserPlugin.getPlugin()); | |
} | |
} | |
} | |
} | |
} | |
int loadingDepth = this.browserConfiguration.getReferencedResourcesLoadingDepth(); | |
// recurse on sub-resources | |
for (Resource directlyReferencedResource : directReferencedResources) { | |
if (directlyReferencedResource == null) { | |
continue; | |
} | |
// avoid infinite recursion in the case of mutually referencing | |
// resources | |
if (!allResources.contains(directlyReferencedResource)) { | |
allResources.add(directlyReferencedResource); | |
if (loadingDepth == -1 || currentDepth + 1 <= loadingDepth) { | |
addReferencedResourcesInternal(directlyReferencedResource, allResources, | |
currentDepth + 1); | |
} | |
} | |
} | |
} | |
/** | |
* Create the left pane, containing the metaclass viewer. | |
* | |
* @param parent | |
* the parent composite | |
*/ | |
protected void createLeftPane(final Composite parent) { | |
final Section section = this.fFormToolkit.createSection(parent, | |
ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED); | |
section.setText(Messages.EcoreBrowser_metaclasses); | |
this.typesPaneComposite = this.fFormToolkit.createComposite(section); | |
section.setClient(this.typesPaneComposite); | |
this.leftPane = initLeftPane(section, this.fFormToolkit); | |
final Composite toolBar = this.leftPane.getToolBarComposite(); | |
section.setTextClient(toolBar); | |
this.typesPaneComposite.setLayout(new FillLayout()); | |
this.metaclassViewer = this.leftPane.getMetaclassViewer(); | |
this.metaclassViewer | |
.addSelectionChangedListener(new MetaclassListViewerSelectionChangedListener()); | |
} | |
protected LeftPane initLeftPane(final Section section, final FormToolkit formToolkit) { | |
return new LeftPane(section, (Composite) section.getClient(), this.browserConfiguration, | |
formToolkit, getSite()); | |
} | |
/** | |
* Create the tree and its viewer | |
* | |
* @param parent | |
* the parent composite of the tree | |
*/ | |
protected void createTreePane(final Composite parent) { | |
final Section section = this.fFormToolkit.createSection(parent, | |
ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED); | |
section.setText(Messages.EcoreBrowser_instances); | |
this.instancesPaneComposite = this.fFormToolkit.createComposite(section, SWT.NONE); | |
section.setClient(this.instancesPaneComposite); | |
final GridLayout layout = new GridLayout(); | |
layout.marginHeight = 0; | |
layout.marginWidth = 0; | |
this.instancesPaneComposite.setLayout(layout); | |
final Composite treeToolBar = createTreeToolBar(section); | |
section.setTextClient(treeToolBar); | |
this.errorsButton = new Button(this.instancesPaneComposite, SWT.PUSH); | |
this.errorsButton.setText(Messages.EcoreBrowser_errorsAndWarnings); | |
this.errorsButton.setToolTipText(Messages.EcoreBrowser_errorsAndWarnings); | |
this.errorsButton.setImage(ImageProvider.getInstance().getErrorIcon()); | |
this.errorsButton.addSelectionListener(new SelectionAdapter() { | |
@Override | |
public void widgetSelected(final SelectionEvent e) { | |
final ErrorsDialog errorsDialog = new ErrorsDialog(getSite().getShell(), | |
EcoreBrowser.this.fDiagnostic); | |
errorsDialog.open(); | |
} | |
}); | |
this.errorsButton.setVisible(false); | |
final GridData errorsButtonGridData = new GridData(); | |
errorsButtonGridData.exclude = true; | |
this.errorsButton.setLayoutData(errorsButtonGridData); | |
createSearchPanel(this.instancesPaneComposite); | |
this.fTree = this.fFormToolkit.createTree(this.instancesPaneComposite, SWT.MULTI | |
| SWT.BORDER); | |
final GridData treeGridData = new GridData(); | |
treeGridData.grabExcessHorizontalSpace = true; | |
treeGridData.grabExcessVerticalSpace = true; | |
treeGridData.horizontalAlignment = SWT.FILL; | |
treeGridData.verticalAlignment = SWT.FILL; | |
this.fTree.setLayoutData(treeGridData); | |
this.fTree.addKeyListener(new KeyAdapter() { | |
@Override | |
public void keyPressed(final KeyEvent e) { | |
if (e.keyCode == SWT.ESC) { | |
// Escape on the tree: restore view (after search) | |
EcoreBrowser.this.searchBox.setText(""); //$NON-NLS-1$ | |
search(); | |
} else if (e.keyCode == SWT.CR) { | |
// Enter: browse selected item | |
handleEnter(); | |
} else if (e.keyCode == 'c' && e.stateMask == SWT.CTRL) { | |
// Ctrl+C : copy element text to clipboard | |
BrowserUtils.handleCopyToClipboard(getEditorSelection()); | |
} else if (e.keyCode == SWT.DEL) { | |
handleDel(); | |
} | |
} | |
}); | |
this.customTreePainter = new CustomTreePainter(this.fTree, | |
this.browserConfiguration.getAppearanceConfiguration()); | |
// create a tooltip to show facet names | |
FacetTooltip.create(this.fTree, this.customTreePainter); | |
this.treeViewer = new TreeViewer(this.fTree); | |
// speeds up all operations on a big model | |
this.treeViewer.setUseHashlookup(true); | |
hookViewerToSelection(this.treeViewer); | |
this.fContentProvider = new BrowserContentProvider(this); | |
this.treeViewer.setContentProvider(this.fContentProvider); | |
this.fLabelProvider = new BrowserLabelProvider(this); | |
this.treeViewer.setLabelProvider(this.fLabelProvider); | |
registerShowPropertyViewOnDblClick(this.fTree); | |
} | |
/** | |
* The user pressed the "Enter" key : if selected element is a model | |
* element, then browse to it. If it is an attribute, then open properties | |
* view. | |
*/ | |
protected void handleEnter() { | |
final ISelection selection = getEditorSelection(); | |
if (selection instanceof ITreeSelection) { | |
final ITreeSelection treeSelection = (ITreeSelection) selection; | |
final Object selectedElement = treeSelection.getFirstElement(); | |
if (selectedElement instanceof ModelElementItem) { | |
browse(); | |
} else if (selectedElement instanceof AttributeItem | |
|| selectedElement instanceof LinkItem) { | |
openPropertiesView(); | |
} else if (selectedElement instanceof QueryItem) { | |
QueryItem queryItem = (QueryItem) selectedElement; | |
SelectedQuery query = queryItem.getQuery(); | |
query.executeQuery(); | |
} | |
} | |
} | |
/** The user pressed the "Delete" key */ | |
protected void handleDel() { | |
final ISelection selection = getEditorSelection(); | |
if (selection instanceof ITreeSelection) { | |
final ITreeSelection treeSelection = (ITreeSelection) selection; | |
Iterator<?> iterator = treeSelection.iterator(); | |
while (iterator.hasNext()) { | |
Object selectedElement = iterator.next(); | |
if (selectedElement instanceof QueryItem) { | |
QueryItem queryItem = (QueryItem) selectedElement; | |
this.browserConfiguration.getSelectedQueriesManager().remove( | |
queryItem.getQuery()); | |
} | |
} | |
} | |
} | |
/** | |
* Set the initial font using saved user preferences, and add a listener to | |
* be notified of changes in the preferences | |
*/ | |
private void setupInitialTreeFont() { | |
setupPreferredFont(); | |
this.fontChangeListener = new IPropertyChangeListener() { | |
public void propertyChange(final PropertyChangeEvent event) { | |
if (event.getProperty().equals(JFaceResources.DIALOG_FONT)) { | |
setupPreferredFont(); | |
} | |
} | |
}; | |
JFaceResources.getFontRegistry().addListener(this.fontChangeListener); | |
} | |
/** Set the user preferred font on the editor */ | |
private void setupPreferredFont() { | |
FontDescriptor descriptor = FontDescriptor.createFrom(JFaceResources.getDialogFont()); | |
descriptor = descriptor.increaseHeight(this.browserConfiguration | |
.getAppearanceConfiguration().getFontSizeDelta()); | |
final Font customFont = descriptor.createFont(Display.getDefault()); | |
descriptor = descriptor.setStyle(SWT.ITALIC); | |
final Font customItalicFont = descriptor.createFont(Display.getDefault()); | |
this.browserConfiguration.getAppearanceConfiguration().setCustomFont(customFont); | |
this.browserConfiguration.getAppearanceConfiguration() | |
.setCustomItalicFont(customItalicFont); | |
this.fTree.setFont(customFont); | |
this.treeViewer.refresh(); | |
this.metaclassViewer.setFont(customFont); | |
this.metaclassViewer.refresh(); | |
} | |
protected Composite createTreeToolBar(final Composite parent) { | |
final Composite treeToolBarComposite = new Composite(parent, SWT.WRAP); | |
this.instancesToolBar = TreeToolBar.create(treeToolBarComposite, this); | |
return treeToolBarComposite; | |
} | |
/** | |
* Register a listener to show the property view or execute a query when the | |
* tree is double-clicked | |
*/ | |
private void registerShowPropertyViewOnDblClick(final Tree tree) { | |
tree.addMouseListener(new MouseAdapter() { | |
@Override | |
public void mouseDoubleClick(final MouseEvent event) { | |
boolean handled = false; | |
if (event.button == 1) { | |
TreeItem[] selection = tree.getSelection(); | |
for (TreeItem treeItem : selection) { | |
Object element = treeItem.getData(); | |
if (element instanceof QueryItem) { | |
QueryItem queryItem = (QueryItem) element; | |
SelectedQuery query = queryItem.getQuery(); | |
query.executeQuery(); | |
handled = true; | |
} | |
// If the user has activated the code synchronization | |
if (EcoreBrowser.this.browserConfiguration.getAppearanceConfiguration() | |
.isSynchronizeSourceCode()) { | |
EObject eObject = (EObject) Platform.getAdapterManager().getAdapter( | |
element, EObject.class); | |
IStatusLineManager statusLineManager = getActionBars() | |
.getStatusLineManager(); | |
if (eObject != null) { | |
// Look for an extension declaring the | |
// doubleClickListener extension point | |
IExtensionRegistry registry = Platform.getExtensionRegistry(); | |
IExtensionPoint extPointDblClick = registry | |
.getExtensionPoint("org.eclipse.gmt.modisco.infra.browser.doubleClickListener"); //$NON-NLS-1$ | |
if (extPointDblClick != null) { | |
for (IExtension ext : extPointDblClick.getExtensions()) { | |
for (IConfigurationElement configElt : ext | |
.getConfigurationElements()) { | |
String classAttribute = configElt.getAttribute("class"); //$NON-NLS-1$ | |
if (classAttribute != null) { | |
try { | |
DoubleClickListener listener = (DoubleClickListener) configElt | |
.createExecutableExtension("class"); //$NON-NLS-1$ | |
// Synchronize this eObject | |
// with its source code | |
listener.synchronizeEObject(eObject, | |
statusLineManager); | |
} catch (CoreException e) { | |
MoDiscoLogger.logError(e, | |
MoDiscoBrowserPlugin.getPlugin()); | |
} finally { | |
handled = true; | |
} | |
} | |
} | |
} | |
} else { | |
if (statusLineManager != null) { | |
statusLineManager | |
.setErrorMessage(Messages.EcoreBrowser_noSynchronisationExtensionFound); | |
} else { | |
MoDiscoLogger | |
.logWarning( | |
Messages.EcoreBrowser_noSynchronisationExtensionFound, | |
MoDiscoBrowserPlugin.getPlugin()); | |
} | |
} | |
} | |
} | |
} | |
if (!handled) { | |
openPropertiesView(); | |
} | |
} | |
} | |
}); | |
} | |
public boolean isSynchronizeSourceCode() { | |
return this.browserConfiguration.getAppearanceConfiguration().isSynchronizeSourceCode(); | |
} | |
public void setSynchronizeSourceCode(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setSynchronizeSourceCode(value); | |
internalRefreshTree(); | |
} | |
/** | |
* Create the search panel, containing a label and search field. | |
* | |
* @param parent | |
* the parent composite, which must have a GridLayout | |
*/ | |
protected void createSearchPanel(final Composite parent) { | |
final Composite searchPanel = new Composite(parent, SWT.NONE); | |
searchPanel.setLayout(new GridLayout()); | |
searchPanel.setLayout(new FillLayout()); | |
final GridData searchPanelGridData = new GridData(); | |
searchPanelGridData.grabExcessHorizontalSpace = true; | |
searchPanelGridData.horizontalAlignment = SWT.FILL; | |
searchPanel.setLayoutData(searchPanelGridData); | |
// Label searchLabel = new Label(searchPanel, SWT.NONE); | |
// searchLabel.setText("&Search:"); | |
this.searchBox = new Text(searchPanel, SWT.SEARCH); | |
this.searchBox.addKeyListener(new KeyAdapter() { | |
@Override | |
public void keyPressed(final KeyEvent e) { | |
if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { | |
// ENTER: start a search | |
search(); | |
} else if (e.keyCode == SWT.ESC) { | |
// ESCAPE: restore the view after a search | |
EcoreBrowser.this.searchBox.setText(""); //$NON-NLS-1$ | |
search(); | |
} | |
} | |
}); | |
this.searchBox.setMessage(Messages.EcoreBrowser_typeFilterText); | |
this.searchBox.setData("org.eclipse.swtbot.widget.key", "EcoreBrowser.searchBox"); //$NON-NLS-1$//$NON-NLS-2$ | |
fixClipboardCommands(this.searchBox); | |
} | |
/** | |
* Called when the user initiates a search. Find the list of all the | |
* instances of the selected metaclass that have a name containing the | |
* search string (entered by the user in the search box), in a case | |
* insensitive way. Set this list as input of the tree viewer. | |
* <p> | |
* Do the search in a Job that can be canceled by the user. | |
* <p> | |
* If the search box is empty, then restore the previous tree viewer input. | |
*/ | |
protected void search() { | |
final String searchText = this.searchBox.getText().toLowerCase(); | |
if (searchText.trim().length() == 0) { | |
if (this.savedInput != null && this.savedInput != this.treeViewer.getInput()) { | |
this.treeViewer.setInput(this.savedInput); | |
} | |
return; | |
} | |
final List<EClass> selectedMetaclasses = findSelectedEClasses(); | |
if (selectedMetaclasses.isEmpty()) { | |
return; | |
} | |
this.searchJob = new Job(Messages.EcoreBrowser_jobName_SearchInModelEditor) { | |
@Override | |
protected IStatus run(final IProgressMonitor monitor) { | |
final ResourceSet resourceSet = EcoreBrowser.this.fResourceSet; | |
final EList<Resource> resources = resourceSet.getResources(); | |
if (resources.size() < 1) { | |
return Status.OK_STATUS; | |
} | |
// the search results : will become the input of the tree viewer | |
final SearchResults searchResults = new SearchResults( | |
EcoreBrowser.this.browserConfiguration); | |
InstancesForMetaclasses instancesForMetaclasses = EcoreBrowser.this.browserConfiguration | |
.getInstancesForMetaclasses(); | |
for (EClass eClass : selectedMetaclasses) { | |
ArrayList<EObject> elements = instancesForMetaclasses.getInstancesForMetaclass( | |
eClass).getElements(); | |
for (EObject eObject : elements) { | |
final ModelElementItem modelElementItem = new ModelElementItemEx(eObject, | |
null, EcoreBrowser.this.browserConfiguration); | |
final String objectText = modelElementItem.getName().toLowerCase(); | |
if (objectText.contains(searchText)) { | |
searchResults.add(eObject); | |
} | |
// if the user canceled the search | |
if (monitor.isCanceled()) { | |
return Status.CANCEL_STATUS; | |
} | |
} | |
} | |
// do only the minimum amount of work in the UI thread | |
Display.getDefault().syncExec(new Runnable() { | |
public void run() { | |
// do not try to restore selection | |
EcoreBrowser.this.treeViewer.setSelection(null); | |
EcoreBrowser.this.treeViewer.setInput(searchResults); | |
} | |
}); | |
return Status.OK_STATUS; | |
} | |
}; | |
this.searchJob.setUser(true); | |
this.searchJob.setPriority(Job.LONG); | |
this.searchJob.schedule(); | |
} | |
/** | |
* @return the {@link EClass}es corresponding to the metaclasses selected in | |
* the metaclass list (empty list if none) | |
*/ | |
private List<EClass> findSelectedEClasses() { | |
final ArrayList<EClass> selectedMetaclasses = new ArrayList<EClass>(); | |
final ISelection selection = this.metaclassViewer.getSelection(); | |
if (selection instanceof IStructuredSelection) { | |
final IStructuredSelection structuredSelection = (IStructuredSelection) selection; | |
final Iterator<?> iterator = structuredSelection.iterator(); | |
while (iterator.hasNext()) { | |
final Object element = iterator.next(); | |
if (element instanceof EClass) { | |
final EClass eClass = (EClass) element; | |
addMetaclassToSelection(eClass, selectedMetaclasses, this.browserConfiguration | |
.getAppearanceConfiguration().isDisplayInstancesOfSubclasses()); | |
} | |
} | |
} | |
return selectedMetaclasses; | |
} | |
/** | |
* Adds the given metaclass to the given selection. | |
* | |
* @param addSubclasses | |
* also adds subclasses | |
*/ | |
private void addMetaclassToSelection(final EClass eClass, | |
final ArrayList<EClass> selectedMetaclasses, final boolean addSubclasses) { | |
selectedMetaclasses.add(eClass); | |
// add subclasses recursively | |
if (addSubclasses) { | |
InstancesForMetaclasses instancesForMetaclasses = this.browserConfiguration | |
.getInstancesForMetaclasses(); | |
InstancesForMetaclass instancesForMetaclass = instancesForMetaclasses | |
.getInstancesForMetaclass(eClass); | |
if (instancesForMetaclass != null) { | |
InstancesForMetaclass[] subclasses = instancesForMetaclass.getSubclasses(); | |
for (InstancesForMetaclass subclass : subclasses) { | |
addMetaclassToSelection(subclass.getEClass(), selectedMetaclasses, | |
addSubclasses); | |
} | |
} else { | |
MoDiscoLogger.logError("Could not find subclasses of '" + eClass.getName() + "'", //$NON-NLS-1$ //$NON-NLS-2$ | |
MoDiscoBrowserPlugin.getPlugin()); | |
} | |
} | |
} | |
/** | |
* Listen to selection changes in the metaclass list viewer, and update the | |
* tree viewer accordingly. | |
*/ | |
private final class MetaclassListViewerSelectionChangedListener implements | |
ISelectionChangedListener { | |
/** Memorize the tree selection for each metaclass */ | |
private final HashMap<EClass, ITreeSelection> selections = new HashMap<EClass, ITreeSelection>(); | |
/** The metaclass that was selected before the selection changed */ | |
private EClass lastSelectedMetaclass = null; | |
/** | |
* Get the selected entries corresponding to the given selection in the | |
* metaclass viewer (may be empty) | |
*/ | |
private InstancesForMetaclass[] getEntriesForSelection(final ISelection selection) { | |
final ArrayList<InstancesForMetaclass> instancesForMetaclasses = new ArrayList<InstancesForMetaclass>(); | |
if (selection instanceof IStructuredSelection) { | |
final IStructuredSelection structuredSelection = (IStructuredSelection) selection; | |
for (final Iterator<?> iterator = structuredSelection.iterator(); iterator | |
.hasNext();) { | |
final Object element = iterator.next(); | |
if (element instanceof InstancesForMetaclass) { | |
final InstancesForMetaclass instancesForMetaclass = (InstancesForMetaclass) element; | |
instancesForMetaclasses.add(instancesForMetaclass); | |
} | |
} | |
} | |
return instancesForMetaclasses | |
.toArray(new InstancesForMetaclass[instancesForMetaclasses.size()]); | |
} | |
/** | |
* Updates the tree viewer when the selection changes in the metaclass | |
* viewer. Keeps track of the tree selection for each metaclass, and | |
* restores it when possible. | |
*/ | |
public void selectionChanged(final SelectionChangedEvent event) { | |
// save the selection | |
if (this.lastSelectedMetaclass != null) { | |
this.selections.put(this.lastSelectedMetaclass, | |
(ITreeSelection) EcoreBrowser.this.treeViewer.getSelection()); | |
} | |
final ISelection metaclassSelection = event.getSelection(); | |
final InstancesForMetaclass[] entries = getEntriesForSelection(metaclassSelection); | |
ITreeSelection savedSelection = null; | |
Object input = null; | |
if (entries.length > 0) { | |
savedSelection = this.selections.get(entries[0].getEClass()); | |
final EClass[] selectedMetaclasses = new EClass[entries.length]; | |
int i = 0; | |
for (final InstancesForMetaclass entry : entries) { | |
selectedMetaclasses[i++] = entry.getEClass(); | |
} | |
input = new MetaclassList(EcoreBrowser.this.browserConfiguration, | |
selectedMetaclasses); | |
this.lastSelectedMetaclass = entries[0].getEClass(); | |
} else { | |
this.lastSelectedMetaclass = null; | |
} | |
try { | |
// speedup and avoid flickering | |
EcoreBrowser.this.treeViewer.getTree().setRedraw(false); | |
if (EcoreBrowser.this.searchBox != null) { | |
EcoreBrowser.this.searchBox.setText(""); //$NON-NLS-1$ | |
} | |
// do not restore selection twice | |
EcoreBrowser.this.treeViewer.setSelection(null); | |
// set the list of model elements as the input of the treeview | |
EcoreBrowser.this.treeViewer.setInput(input); | |
EcoreBrowser.this.savedInput = input; | |
EcoreBrowser.this.treeViewer.setSelection(savedSelection, true); | |
} finally { | |
EcoreBrowser.this.treeViewer.getTree().setRedraw(true); | |
} | |
markNavigationLocation(); | |
} | |
} | |
public void setShowEmptyLinks(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowEmptyLinks(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowEmptyLinks() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowEmptyLinks(); | |
} | |
public void setSortInstances(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setSortInstances(value); | |
internalRefreshTree(); | |
} | |
public boolean isSortInstances() { | |
return this.browserConfiguration.getAppearanceConfiguration().isSortInstances(); | |
} | |
public void setShowDerivedLinks(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowDerivedLinks(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowDerivedLinks() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowDerivedLinks(); | |
} | |
public void setShowFullQualifiedNames(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowFullQualifiedNames(value); | |
internalRefreshTree(); | |
this.metaclassViewer.refresh(); | |
} | |
public boolean isShowFullQualifiedNames() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowFullQualifiedNames(); | |
} | |
public void setShowMultiplicity(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowMultiplicity(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowMultiplicity() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowMultiplicity(); | |
} | |
public void setShowOppositeLinks(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowOppositeLinks(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowOppositeLinks() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowOppositeLinks(); | |
} | |
public void setShowContainer(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowContainer(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowContainer() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowContainer(); | |
} | |
public void setSortLinks(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setSortLinks(value); | |
internalRefreshTree(); | |
} | |
public boolean isSortLinks() { | |
return this.browserConfiguration.getAppearanceConfiguration().isSortLinks(); | |
} | |
public void setSortLinksByType(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setSortLinksByType(value); | |
internalRefreshTree(); | |
} | |
public boolean isSortLinksByType() { | |
return this.browserConfiguration.getAppearanceConfiguration().isSortLinksByType(); | |
} | |
public void setShowAttributes(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowAttributes(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowAttributes() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowAttributes(); | |
} | |
public void setShowEmptyAttributes(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowEmptyAttributes(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowEmptyAttributes() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowEmptyAttributes(); | |
} | |
public void setFontSizeDelta(final int value) { | |
this.browserConfiguration.getAppearanceConfiguration().setFontSizeDelta(value); | |
setupPreferredFont(); | |
} | |
public int getFontSizeDelta() { | |
return this.browserConfiguration.getAppearanceConfiguration().getFontSizeDelta(); | |
} | |
public void setShowOrdering(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowOrdering(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowOrdering() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowOrdering(); | |
} | |
public void setShowTypeOfLinks(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowTypeOfLinks(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowTypeOfLinks() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowTypeOfLinks(); | |
} | |
public void setShowElementIDs(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowElementIDs(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowElementIDs() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowElementIDs(); | |
} | |
public void setShowURI(final boolean value) { | |
this.browserConfiguration.getAppearanceConfiguration().setShowURI(value); | |
internalRefreshTree(); | |
} | |
public boolean isShowURI() { | |
return this.browserConfiguration.getAppearanceConfiguration().isShowURI(); | |
} | |
public void showOnlyInstancesPanel() { | |
this.sashForm.setSashWidth(0); | |
this.sashForm.setWeights(new int[] { 0, 1 }); | |
} | |
public void showOnlyTypesPanel() { | |
this.sashForm.setSashWidth(0); | |
this.sashForm.setWeights(new int[] { 1, 0 }); | |
} | |
public void showBothPanels() { | |
this.sashForm.setSashWidth(EcoreBrowser.SASH_WIDTH); | |
this.sashForm.setWeights(new int[] { EcoreBrowser.LEFT_PANE_SASH_WEIGHT, | |
EcoreBrowser.RIGHT_PANE_SASH_WEIGHT }); | |
} | |
/** This is how the framework determines which interfaces we implement. */ | |
@SuppressWarnings("unchecked") | |
@Override | |
public Object getAdapter(final Class key) { | |
if (key.equals(IPropertySheetPage.class)) { | |
// Store the propertySheetPage to be able to call dispose() on it. | |
if (this.propertySheetPage == null) { | |
this.propertySheetPage = getPropertySheetPage(); | |
} | |
return getPropertySheetPage(); | |
} | |
return super.getAdapter(key); | |
} | |
/** This accesses a cached version of the property sheet page. */ | |
public IPropertySheetPage getPropertySheetPage() { | |
if (this.propertySheetPage == null) { | |
this.propertySheetPage = new ExtendedPropertySheetPage(this.editingDomain) { | |
@Override | |
public void setSelectionToViewer(final List<?> selection) { | |
EcoreBrowser.this.setSelectionToViewer(selection); | |
EcoreBrowser.this.setFocus(); | |
} | |
@Override | |
public void setActionBars(final IActionBars actionBars) { | |
super.setActionBars(actionBars); | |
getActionBarContributor().shareGlobalActions(this, actionBars); | |
} | |
@Override | |
public void selectionChanged(final IWorkbenchPart part, final ISelection selection0) { | |
ISelection selection = EcoreBrowser.this.getEditorSelection(); | |
boolean selectionNotified = false; | |
if (selection instanceof IStructuredSelection) { | |
if (((IStructuredSelection) selection).toArray().length == 1) { | |
Object objSelected = ((IStructuredSelection) selection) | |
.getFirstElement(); | |
if (objSelected instanceof ModelElementItem) { | |
ModelElementItem modelElementItem = (ModelElementItem) objSelected; | |
super.selectionChanged(part, new StructuredSelection( | |
modelElementItem.getEObject())); | |
selectionNotified = true; | |
} else if (objSelected instanceof AttributeItem) { | |
super.selectionChanged(part, new StructuredSelection( | |
((AttributeItem) objSelected).getAttribute())); | |
selectionNotified = true; | |
} else if (objSelected instanceof LinkItem) { | |
super.selectionChanged(part, new StructuredSelection( | |
((LinkItem) objSelected).getReference())); | |
selectionNotified = true; | |
} | |
} | |
} | |
if (!selectionNotified) { | |
super.selectionChanged(part, StructuredSelection.EMPTY); | |
} | |
} | |
}; | |
if (this.propertySheetPage instanceof PropertySheetPage) { | |
((PropertySheetPage) this.propertySheetPage) | |
.setPropertySourceProvider(new AdapterFactoryContentProvider( | |
this.adapterFactoryWithRegistry) { | |
@Override | |
protected IPropertySource createPropertySource(final Object object, | |
final IItemPropertySource itemPropertySource) { | |
return new PropertySource(object, itemPropertySource) { | |
@Override | |
protected IPropertyDescriptor createPropertyDescriptor( | |
final IItemPropertyDescriptor itemPropertyDescriptor) { | |
return new PropertyDescriptor(this.object, | |
itemPropertyDescriptor); | |
} | |
}; | |
} | |
}); | |
} | |
} | |
return this.propertySheetPage; | |
} | |
@Override | |
public boolean isDirty() { | |
if (isReadOnly()) { | |
return false; | |
} | |
return ((BasicCommandStack) this.editingDomain.getCommandStack()).isSaveNeeded(); | |
} | |
/** | |
* This is for implementing {@link org.eclipse.ui.IEditorPart} : saves the | |
* model file. | |
*/ | |
@Override | |
public void doSave(final IProgressMonitor progressMonitor) { | |
if (isReadOnly()) { | |
return; | |
} | |
// Save only resources that have actually changed. | |
final Map<Object, Object> saveOptions = new HashMap<Object, Object>(); | |
saveOptions.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED, | |
Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER); | |
// Do the work within an operation because this is a long running | |
// activity that modifies the workbench. | |
WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { | |
// This is the method that gets invoked when the operation runs. | |
@Override | |
public void execute(final IProgressMonitor monitor) { | |
// Save the resources to the file system. | |
boolean first = true; | |
for (Resource resource : EcoreBrowser.this.editingDomain.getResourceSet() | |
.getResources()) { | |
// see Bug 311005 - UnknownServiceException when trying to | |
// save a UML model | |
synchronized (resource) { | |
URI uri = resource.getURI(); | |
if ((first || !resource.getContents().isEmpty() || isPersisted(resource)) | |
&& !EcoreBrowser.this.editingDomain.isReadOnly(resource) | |
&& uri != null && (uri.isPlatformResource() || uri.isFile())) { | |
try { | |
long timeStamp = resource.getTimeStamp(); | |
resource.save(saveOptions); | |
if (resource.getTimeStamp() != timeStamp) { | |
EcoreBrowser.this.savedResources.add(resource); | |
} | |
} catch (final Exception e) { | |
MoDiscoLogger.logError(e, MoDiscoBrowserPlugin.getPlugin()); | |
DialogUtils.openErrorDialog(getSite().getShell(), e, | |
Messages.EcoreBrowser_errorSavingResource); | |
EcoreBrowser.this.resourceToDiagnosticMap.put(resource, | |
analyzeResourceProblems(resource, e)); | |
} | |
first = false; | |
} | |
} | |
} | |
} | |
}; | |
this.updateProblemIndication = false; | |
try { | |
// This runs the options, and shows progress. | |
new ProgressMonitorDialog(getSite().getShell()).run(true, false, operation); | |
// Refresh the necessary state. | |
((BasicCommandStack) this.editingDomain.getCommandStack()).saveIsDone(); | |
firePropertyChange(IEditorPart.PROP_DIRTY); | |
} catch (Exception exception) { | |
// Something went wrong that shouldn't. | |
MoDiscoBrowserPlugin.getPlugin().log(exception); | |
} | |
this.updateProblemIndication = true; | |
updateProblemIndication(); | |
} | |
@Override | |
public void doSaveAs() { | |
SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell()); | |
saveAsDialog.open(); | |
IPath path = saveAsDialog.getResult(); | |
if (path != null) { | |
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); | |
if (file != null) { | |
doSaveAs(URI.createPlatformResourceURI(file.getFullPath().toString(), true), | |
new FileEditorInput(file)); | |
} | |
} | |
} | |
protected void doSaveAs(final URI uri, final IEditorInput editorInput) { | |
this.editingDomain.getResourceSet().getResources().get(0).setURI(uri); | |
setInputWithNotify(editorInput); | |
setPartName(editorInput.getName()); | |
IProgressMonitor progressMonitor; | |
IStatusLineManager statusLineManager = getActionBars().getStatusLineManager(); | |
if (statusLineManager != null) { | |
progressMonitor = statusLineManager.getProgressMonitor(); | |
} else { | |
progressMonitor = new NullProgressMonitor(); | |
} | |
doSave(progressMonitor); | |
} | |
@Override | |
public boolean isSaveAsAllowed() { | |
return !isReadOnly(); | |
} | |
/** | |
* This returns whether something has been persisted to the URI of the | |
* specified resource. The implementation uses the URI converter from the | |
* editor's resource set to try to open an input stream. | |
*/ | |
protected boolean isPersisted(final Resource resource) { | |
boolean result = false; | |
try { | |
InputStream stream = this.editingDomain.getResourceSet().getURIConverter() | |
.createInputStream(resource.getURI()); | |
if (stream != null) { | |
result = true; | |
stream.close(); | |
} | |
} catch (IOException e) { | |
result = false; | |
} | |
return result; | |
} | |
/** | |
* This is called during startup to initialize the editor with its site and | |
* input. | |
*/ | |
@Override | |
public void init(final IEditorSite site, final IEditorInput editorInput) { | |
// TODO: check input is of expected type | |
try { | |
setSite(site); | |
setInputWithNotify(editorInput); | |
setPartName(editorInput.getName()); | |
site.setSelectionProvider(this); | |
site.getPage().addPartListener(this.partListener); | |
ResourcesPlugin.getWorkspace().addResourceChangeListener(this.resourceChangeListener, | |
IResourceChangeEvent.POST_CHANGE); | |
} catch (final Exception e) { | |
MoDiscoLogger.logError(e, MoDiscoBrowserPlugin.getPlugin()); | |
} | |
} | |
/** Focus the tree viewer when the editor is focused */ | |
@Override | |
public void setFocus() { | |
// Done in setFocus because we don't want the job to start until the | |
// editor is visible. Otherwise it still hangs the UI. | |
if (this.openModelJob == null) { | |
this.openModelJob = new Job(Messages.EcoreBrowser_jobOpeningModelInMoDiscoBrowser) { | |
@Override | |
protected IStatus run(final IProgressMonitor monitor) { | |
boolean result = backgroundOpenModel(monitor); | |
EcoreBrowser.this.loaded = result; | |
if (result) { | |
return Status.OK_STATUS; | |
} | |
return Status.CANCEL_STATUS; | |
} | |
}; | |
this.openModelJob.setPriority(Job.LONG); | |
getProgressService().schedule(this.openModelJob); | |
} else if (this.treeViewer != null) { | |
this.treeViewer.getTree().setFocus(); | |
} | |
} | |
/** This implements {@link org.eclipse.jface.viewers.ISelectionProvider}. */ | |
public void addSelectionChangedListener(final ISelectionChangedListener listener) { | |
this.selectionChangedListeners.add(listener); | |
} | |
/** This implements {@link org.eclipse.jface.viewers.ISelectionProvider}. */ | |
public void removeSelectionChangedListener(final ISelectionChangedListener listener) { | |
this.selectionChangedListeners.remove(listener); | |
} | |
/** | |
* Returns the "unwrapped" selection of the editor, with Ecore elements | |
* instead of the proxies used internally | |
*/ | |
public ISelection getSelection() { | |
return BrowserUtils.unwrapSelection(this.editorSelection); | |
} | |
/** @return the "real" selection, with proxy objects (ModelElementItem, etc.) */ | |
public ISelection getEditorSelection() { | |
return this.editorSelection; | |
} | |
/** | |
* This implements {@link org.eclipse.jface.viewers.ISelectionProvider} to | |
* set this editor's overall selection. Calling this result will notify the | |
* listeners. | |
*/ | |
public void setSelection(final ISelection selection) { | |
this.editorSelection = selection; | |
for (final ISelectionChangedListener listener : this.selectionChangedListeners) { | |
// depending on the listener type, unwrap the selection | |
if (listener instanceof IBrowserSelectionChangedListener) { | |
// expose the proxy objects | |
listener.selectionChanged(new SelectionChangedEvent(this, selection)); | |
} else { | |
// expose the underlying Ecore elements | |
listener.selectionChanged(new SelectionChangedEvent(this, BrowserUtils | |
.unwrapSelection(selection))); | |
} | |
} | |
setStatusLineMessage(selection); | |
} | |
/** Connect the given viewer to the editor's selection */ | |
private void hookViewerToSelection(final Viewer viewer) { | |
if (viewer == null) { | |
return; | |
} | |
if (this.selectionChangedListener == null) { | |
// Create the listener on demand | |
this.selectionChangedListener = new ISelectionChangedListener() { | |
// This just notifies those things that are affected by the | |
// selection | |
public void selectionChanged(final SelectionChangedEvent selectionChangedEvent) { | |
setSelection(selectionChangedEvent.getSelection()); | |
} | |
}; | |
} | |
viewer.addSelectionChangedListener(this.selectionChangedListener); | |
// Set the editor's selection based on the viewer's selection | |
setSelection(viewer.getSelection()); | |
} | |
/** Set the status line message depending on the given selection */ | |
public void setStatusLineMessage(final ISelection selection) { | |
// TODO: maybe display more useful information? | |
final IStatusLineManager statusLineManager = getActionBars().getStatusLineManager(); | |
if (statusLineManager != null) { | |
if (selection instanceof IStructuredSelection) { | |
final Collection<?> collection = ((IStructuredSelection) selection).toList(); | |
switch (collection.size()) { | |
case 0: | |
statusLineManager.setMessage(Messages.EcoreBrowser_noObjectSelected); | |
break; | |
case 1: | |
final Object object = collection.iterator().next(); | |
if (object instanceof ITreeElement) { | |
final ITreeElement treeElement = (ITreeElement) object; | |
statusLineManager.setMessage(NLS.bind( | |
Messages.EcoreBrowser_singleObjectSelected, treeElement.getText())); | |
} | |
break; | |
default: | |
statusLineManager.setMessage(NLS.bind( | |
Messages.EcoreBrowser_multiObjectSelected, | |
Integer.toString(collection.size()))); | |
break; | |
} | |
} else { | |
statusLineManager.setMessage(""); //$NON-NLS-1$ | |
} | |
} | |
} | |
/** | |
* This implements {@link org.eclipse.jface.action.IMenuListener} to help | |
* fill the context menus with contributions from the Edit menu. | |
*/ | |
public void menuAboutToShow(final IMenuManager menuManager) { | |
((IMenuListener) getEditorSite().getActionBarContributor()).menuAboutToShow(menuManager); | |
} | |
public BrowserActionBarContributor getActionBarContributor() { | |
return (BrowserActionBarContributor) getEditorSite().getActionBarContributor(); | |
} | |
public IActionBars getActionBars() { | |
return getActionBarContributor().getActionBars(); | |
} | |
/** Clean up */ | |
@Override | |
public void dispose() { | |
stopOpeningModel(); | |
this.disposing = true; | |
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this.resourceChangeListener); | |
getSite().getPage().removePartListener(this.partListener); | |
this.adapterFactoryWithRegistry.dispose(); | |
this.sashForm.dispose(); | |
if (getActionBarContributor().getActiveEditor() == this) { | |
getActionBarContributor().setActiveEditor(null); | |
} | |
if (this.propertySheetPage != null) { | |
this.propertySheetPage.dispose(); | |
} | |
if (this.treeViewer != null && this.selectionChangedListener != null) { | |
this.treeViewer.removeSelectionChangedListener(this.selectionChangedListener); | |
this.selectionChangedListener = null; | |
} | |
// dispose fonts | |
this.browserConfiguration.getAppearanceConfiguration().setCustomFont(null); | |
this.browserConfiguration.getAppearanceConfiguration().setCustomItalicFont(null); | |
// avoid leaking editor | |
this.browserConfiguration.dispose(); | |
JFaceResources.getFontRegistry().removeListener(this.fontChangeListener); | |
this.customTreePainter.dispose(); | |
// dispose the customization engine, which removes listeners too | |
this.browserConfiguration.getAppearanceConfiguration().getCustomizationEngine().dispose(); | |
this.fCustomizationEngineChangeListener = null; | |
FacetSetCatalog.getSingleton().removeChangeListener(this.fFacetsChangeListener); | |
this.fFormToolkit.dispose(); | |
// avoid memory leak for EMF registry resources since a new | |
// adapter is created each time the same resource is opened | |
// in a different editor | |
Set<Resource> browsedResources = this.browserConfiguration.getBrowsedResources(); | |
if (browsedResources != null) { | |
for (Resource resource : browsedResources) { | |
ListIterator<Adapter> listIterator = resource.eAdapters().listIterator(); | |
while (listIterator.hasNext()) { | |
Adapter adapter = listIterator.next(); | |
if (adapter instanceof MetaclassInstancesAdapterWithFacet) { | |
MetaclassInstancesAdapterWithFacet adapterWithFacet = (MetaclassInstancesAdapterWithFacet) adapter; | |
if (adapterWithFacet.getFacetContext() == getBrowserConfiguration() | |
.getAppearanceConfiguration().getFacetContext()) { | |
listIterator.remove(); | |
} | |
} | |
} | |
} | |
} | |
// let the FacetContext be GCed | |
MetaclassInstancesAdapterFactoryWithFacet.getInstance().setFacetContext(null); | |
// if (!isReadOnly()) { | |
// // unload all resources | |
// final EList<Resource> resources = this.fResourceSet.getResources(); | |
// final Job cleanupJob = new | |
// Job(Messages.EcoreBrowser_jobName_UnloadResources) { | |
// @Override | |
// protected IStatus run(final IProgressMonitor monitor) { | |
// for (final Resource resource : resources) { | |
// resource.unload(); | |
// } | |
// return Status.OK_STATUS; | |
// } | |
// }; | |
// cleanupJob.setPriority(Job.DECORATE); | |
// cleanupJob.setSystem(true); | |
// cleanupJob.schedule(); | |
// } | |
super.dispose(); | |
} | |
@SuppressWarnings("deprecation") | |
private void stopOpeningModel() { | |
if (this.openModelJob != null && this.openModelJob.getState() == Job.RUNNING) { | |
this.openModelJob.cancel(); | |
Thread thread = this.openModelJob.getThread(); | |
if (thread != null) { | |
thread.stop(); | |
} | |
} | |
} | |
/** Open the selected element in the list of elements of the same metaclass */ | |
public void browse() { | |
final ISelection selection = getEditorSelection(); | |
if (selection instanceof ITreeSelection) { | |
final ITreeSelection treeSelection = (ITreeSelection) selection; | |
final Object selectedElement = treeSelection.getFirstElement(); | |
if (selectedElement instanceof ModelElementItem) { | |
final ModelElementItem modelElementItem = (ModelElementItem) selectedElement; | |
browseTo(modelElementItem); | |
} | |
} | |
} | |
/** Open the given element in the list of elements of the same metaclass */ | |
public void browseTo(final ModelElementItem modelElementItem) { | |
final EObject modelElement = modelElementItem.getEObject(); | |
browseTo(modelElement); | |
} | |
/** Open the given element in the list of elements of the same metaclass */ | |
public void browseTo(final EObject modelElement) { | |
browseTo(modelElement, modelElement.eClass()); | |
} | |
/** | |
* Open the given element in the list of elements of the given metaclass | |
* (which can be a Facet). | |
*/ | |
public void browseTo(final EObject modelElement, final EClass eClass) { | |
markNavigationLocation(); | |
// Select the metaclass in the metaclass list viewer | |
this.metaclassViewer.selectMetaclass(eClass); | |
TreePath treePath = findTreePathForElement(modelElement); | |
if (treePath != null) { | |
// deselect any previously selected elements | |
this.treeViewer.setSelection(null); | |
this.treeViewer.setSelection(new TreeSelection(treePath), true); | |
if (this.treeViewer.getSelection().isEmpty()) { | |
delayedBrowseTo(modelElement); | |
} else { | |
markNavigationLocation(); | |
} | |
} else { | |
delayedBrowseTo(modelElement); | |
} | |
} | |
/** | |
* delayed because the browser doesn't always update synchronously | |
* (temporary "loading..." nodes) | |
*/ | |
private void delayedBrowseTo(final EObject modelElement) { | |
Listener refreshListener = new Listener() { | |
public void handleEvent(final Event event) { | |
removeRefreshListener(this); | |
Display.getDefault().asyncExec(new Runnable() { | |
public void run() { | |
TreePath treePath2 = findTreePathForElement(modelElement); | |
EcoreBrowser.this.treeViewer.setSelection(null); | |
EcoreBrowser.this.treeViewer.setSelection(new TreeSelection(treePath2), | |
true); | |
markNavigationLocation(); | |
} | |
}); | |
} | |
}; | |
addRefreshListener(refreshListener); | |
} | |
public boolean browseToByURI(final String uriFragment) { | |
EObject eObject = EMFUtil.findElementByURI(uriFragment, this.fResourceSet); | |
if (eObject != null) { | |
browseTo(eObject); | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Finds the path of the given element in the tree viewer. The element is | |
* looked for at the root and under BigListItemProviders in the case the | |
* elements are split. | |
* | |
* @return the path or <code>null</code> if the element was not found | |
*/ | |
private TreePath findTreePathForElement(final EObject eObject) { | |
final Object input = this.treeViewer.getInput(); | |
if (input instanceof MetaclassList) { | |
final MetaclassList metaclassListItemProvider = (MetaclassList) input; | |
final Collection<?> elements = metaclassListItemProvider.getElements(); | |
for (final Object element : elements) { | |
// if the elements are split | |
if (element instanceof BigListItem) { | |
final BigListItem bigListItemProvider = (BigListItem) element; | |
final Collection<?> subElements = bigListItemProvider.getChildren(); | |
for (final Object subElement : subElements) { | |
if (subElement instanceof ModelElementItem) { | |
final ModelElementItem other = (ModelElementItem) subElement; | |
if (other.getEObject().equals(eObject)) { | |
return new TreePath(new Object[] { subElement }); | |
} | |
} | |
} | |
} | |
if (element instanceof ModelElementItem) { | |
final ModelElementItem other = (ModelElementItem) element; | |
if (other.getEObject().equals(eObject)) { | |
return new TreePath(new Object[] { element }); | |
} | |
} | |
} | |
} | |
return null; | |
} | |
/** Implements {@link INavigationLocationProvider} */ | |
public INavigationLocation createEmptyNavigationLocation() { | |
return new BrowserNavigationLocation(this); | |
} | |
/** | |
* Implements {@link INavigationLocationProvider}. Create a location that | |
* can be navigated back to, using the "back" button | |
*/ | |
public INavigationLocation createNavigationLocation() { | |
// navigation to the first element of the selection | |
final EClass firstSelectedMetaclass = this.metaclassViewer.getFirstSelectedMetaclass(); | |
return new BrowserNavigationLocation(this, firstSelectedMetaclass, | |
(ITreeSelection) this.treeViewer.getSelection()); | |
} | |
/** Mark a location that can be navigated back to, using the "back" button */ | |
protected void markNavigationLocation() { | |
getSite().getPage().getNavigationHistory().markLocation(this); | |
} | |
/** | |
* Restore a location (used for implementing history). | |
* | |
* @param eClass | |
* the metaclass viewer's selection | |
* @param selection | |
* the tree viewer's selection | |
*/ | |
public void restoreLocation(final EClass eClass, final ITreeSelection selection) { | |
this.metaclassViewer.selectMetaclass(eClass); | |
this.treeViewer.setSelection(selection); | |
} | |
private final List<Listener> refreshListeners = new ArrayList<Listener>(); | |
public void addRefreshListener(final Listener refreshListener) { | |
if (!this.refreshListeners.contains(refreshListener)) { | |
this.refreshListeners.add(refreshListener); | |
} | |
} | |
public void removeRefreshListener(final Listener refreshListener) { | |
this.refreshListeners.remove(refreshListener); | |
} | |
public void notifyRefresh() { | |
for (Listener listener : new ArrayList<Listener>(this.refreshListeners)) { | |
listener.handleEvent(new Event()); | |
} | |
} | |
/** | |
* Refresh the editor | |
* | |
* @param metaclassViewerToo | |
* whether the metaclass view must be refreshed too, or only the | |
* tree viewer | |
*/ | |
public void refreshDelayed(final boolean metaclassViewerToo) { | |
if (this.disposing) { | |
return; | |
} | |
if (this.refreshJob == null) { | |
this.refreshJob = new Job(Messages.EcoreBrowser_refreshingModelViewers) { | |
@Override | |
protected IStatus run(final IProgressMonitor monitor) { | |
Display.getDefault().syncExec(new Runnable() { | |
public void run() { | |
internalRefreshTree(); | |
if (metaclassViewerToo) { | |
getMetaclassViewer().refresh(); | |
} | |
notifyRefresh(); | |
} | |
}); | |
return Status.OK_STATUS; | |
} | |
}; | |
} else { | |
/* | |
* If refreshTreeDelayed is called again before the job delay | |
* passed, then cancel the job and re-schedule a new one. | |
*/ | |
this.refreshJob.cancel(); | |
} | |
// we don't want to keep refreshing while computing children, | |
// because it slows down the computation | |
if (this.fContentProvider.isComputing()) { | |
final int delay = 100; | |
this.refreshJob.setPriority(Job.DECORATE); | |
this.refreshJob.schedule(delay); | |
} else { | |
this.refreshJob.setPriority(Job.INTERACTIVE); | |
this.refreshJob.schedule(); | |
} | |
} | |
public void clearInstancesCache() { | |
AppearanceConfiguration appearanceConfiguration = this.browserConfiguration | |
.getAppearanceConfiguration(); | |
MetaclassInstancesAdapterFactoryWithFacet.getInstance().setFacetContext( | |
appearanceConfiguration.getFacetContext()); | |
Set<Resource> browsedResources = this.browserConfiguration.getBrowsedResources(); | |
if (browsedResources != null) { | |
for (Resource resource : browsedResources) { | |
MetaclassInstances instances = (MetaclassInstances) MetaclassInstancesAdapterFactoryWithFacet | |
.getInstance().adapt(resource, MetaclassInstances.class); | |
instances.clearCache(); | |
} | |
} | |
} | |
private void internalRefreshTree() { | |
if (!this.treeViewer.getTree().isDisposed()) { | |
try { | |
this.treeViewer.getTree().setRedraw(false); | |
this.treeViewer.refresh(); | |
} finally { | |
this.treeViewer.getTree().setRedraw(true); | |
} | |
} | |
} | |
public BrowserConfiguration getBrowserConfiguration() { | |
return this.browserConfiguration; | |
} | |
private void openPropertiesView() { | |
try { | |
getEditorSite().getPage().showView(EcoreBrowser.PROPERTY_VIEW_ID); | |
} catch (final PartInitException e) { | |
MoDiscoBrowserPlugin.logException(e); | |
} | |
} | |
public ResourceSet getResourceSet() { | |
return this.fResourceSet; | |
// return getEditingDomain().getResourceSet(); | |
} | |
public void loadCustomizations(final Collection<MetamodelView> customizationsToLoad) { | |
final CustomizationEngine customizationEngine = this.browserConfiguration | |
.getAppearanceConfiguration().getCustomizationEngine(); | |
if (this.fCustomizationEngineChangeListener == null) { | |
this.fCustomizationEngineChangeListener = new ChangeListener() { | |
public void changed() { | |
Display.getDefault().asyncExec(new Runnable() { | |
public void run() { | |
refreshDelayed(true); | |
} | |
}); | |
} | |
}; | |
customizationEngine.addChangeListener(this.fCustomizationEngineChangeListener); | |
} | |
customizationEngine.clear(); | |
for (final MetamodelView customizationToLoad : customizationsToLoad) { | |
customizationEngine.registerCustomization(customizationToLoad); | |
} | |
customizationEngine.loadCustomizations(); | |
} | |
private void loadDefaultCustomizations() { | |
Collection<MetamodelView> customizations = CustomizationsCatalog.filterForMetamodel( | |
CustomizationsCatalog.getInstance().getRegistryDefaultCustomizations(), | |
getReferencedEPackages()); | |
if (customizations.size() > 0) { | |
loadCustomizations(customizations); | |
} | |
} | |
/** used by unit tests */ | |
protected TreeToolBar getInstancesToolBar() { | |
return this.instancesToolBar; | |
} | |
protected void reloadOnFacetChange() { | |
if (this.fFacetsChangeListener == null) { | |
this.fFacetsChangeListener = new ModiscoCatalogChangeListener() { | |
private void changed() { | |
if (!EcoreBrowser.this.loaded) { | |
return; | |
} | |
Job reloadFacetsJob = new Job(Messages.EcoreBrowser_ReloadingFacets) { | |
@Override | |
protected IStatus run(final IProgressMonitor monitor) { | |
// reloading Facets by name, since the elements are | |
// different after a FacetSet model reload | |
List<String> facetsToReload = new ArrayList<String>(); | |
Collection<Facet> loadedFacets = getBrowserConfiguration() | |
.getAppearanceConfiguration().getLoadedFacets(); | |
for (Facet facet : loadedFacets) { | |
FacetSet facetSet = facet.getFacetSet(); | |
facetsToReload.add(facetSet.getName() + "#" + facet.getName()); //$NON-NLS-1$ | |
} | |
getBrowserConfiguration().getAppearanceConfiguration().clearFacets(); | |
Collection<FacetSet> allFacetSets = FacetSetCatalog.getSingleton() | |
.getAllFacetSets(); | |
for (FacetSet facetSet : allFacetSets) { | |
EList<Facet> facets = facetSet.getFacets(); | |
for (Facet facet : facets) { | |
for (String fullname : facetsToReload) { | |
if (fullname.equals(facetSet.getName() + "#" //$NON-NLS-1$ | |
+ facet.getName())) { | |
getBrowserConfiguration().getAppearanceConfiguration() | |
.loadFacet(facet); | |
break; | |
} | |
} | |
} | |
} | |
// for modified facets | |
getBrowserConfiguration().getInstancesForMetaclasses() | |
.buildDerivationTree(); | |
return Status.OK_STATUS; | |
} | |
}; | |
reloadFacetsJob.setPriority(Job.DECORATE); | |
reloadFacetsJob.schedule(); | |
} | |
public void removed(final IFile file) { | |
changed(); | |
} | |
public void changed(final EObject eObject, final IFile file) { | |
changed(); | |
} | |
public void added(final EObject eObject, final IFile file) { | |
changed(); | |
} | |
}; | |
FacetSetCatalog.getSingleton().addChangeListener(this.fFacetsChangeListener); | |
} | |
} | |
public void modelChanged() { | |
getBrowserConfiguration().getAppearanceConfiguration().touch(); | |
refreshDelayed(true); | |
} | |
/** | |
* Handles activation of the editor or it's associated views. | |
*/ | |
protected void handleActivate() { | |
// Recompute the read only state. | |
if (this.editingDomain.getResourceToReadOnlyMap() != null) { | |
this.editingDomain.getResourceToReadOnlyMap().clear(); | |
// Refresh any actions that may become enabled or disabled. | |
setSelection(getEditorSelection()); | |
} | |
if (!this.removedResources.isEmpty()) { | |
if (handleDirtyConflict()) { | |
getSite().getPage().closeEditor(EcoreBrowser.this, false); | |
} else { | |
this.removedResources.clear(); | |
this.changedResources.clear(); | |
this.savedResources.clear(); | |
} | |
} else if (!this.changedResources.isEmpty()) { | |
this.changedResources.removeAll(this.savedResources); | |
handleChangedResources(); | |
this.changedResources.clear(); | |
this.savedResources.clear(); | |
} | |
} | |
/** | |
* Shows a dialog that asks if conflicting changes should be discarded. | |
*/ | |
protected boolean handleDirtyConflict() { | |
return MessageDialog.openQuestion(getSite().getShell(), Messages.UI_FileConflict_label, | |
Messages.WARN_FileConflict); | |
} | |
/** | |
* Handles what to do with changed resources on activation. | |
*/ | |
protected void handleChangedResources() { | |
if (!this.changedResources.isEmpty() && (!isDirty() || handleDirtyConflict())) { | |
if (isDirty()) { | |
this.changedResources.addAll(this.editingDomain.getResourceSet().getResources()); | |
} | |
this.editingDomain.getCommandStack().flush(); | |
this.updateProblemIndication = false; | |
for (Resource resource : this.changedResources) { | |
if (resource.isLoaded()) { | |
resource.unload(); | |
try { | |
resource.load(Collections.EMPTY_MAP); | |
} catch (IOException e) { | |
final URI uri = resource.getURI(); | |
final String uristr = uri.toString(); | |
final String logMsg = String.format( | |
"The MoDisco browser failed to reload the resource %s.", //$NON-NLS-1$ | |
uristr); | |
Logger.logError( | |
e, logMsg , MoDiscoBrowserPlugin.getPlugin()); | |
final String userMsg = String.format( | |
"%s, cf. %s", //$NON-NLS-1$ | |
Messages.EcoreBrowser_errorLoadingResource, | |
uristr); | |
DialogUtils.openErrorDialog(getSite().getShell(), e, | |
userMsg); | |
if (!this.resourceToDiagnosticMap.containsKey(resource)) { | |
this.resourceToDiagnosticMap.put(resource, | |
analyzeResourceProblems(resource, e)); | |
} | |
} | |
} | |
} | |
if (AdapterFactoryEditingDomain.isStale(this.editorSelection)) { | |
setSelection(StructuredSelection.EMPTY); | |
} | |
this.updateProblemIndication = true; | |
updateProblemIndication(); | |
} | |
} | |
/** | |
* Updates the problems indication with the information described in the | |
* specified diagnostic. | |
*/ | |
protected void updateProblemIndication() { | |
if (this.updateProblemIndication) { | |
BasicDiagnostic diagnostic = new BasicDiagnostic(Diagnostic.OK, | |
MoDiscoBrowserPlugin.PLUGIN_ID, 0, null, | |
new Object[] { this.editingDomain.getResourceSet() }); | |
int nWarnings = 0; | |
int nErrors = 0; | |
int nInfo = 0; | |
for (Diagnostic childDiagnostic : this.resourceToDiagnosticMap.values()) { | |
if (childDiagnostic.getSeverity() != Diagnostic.OK) { | |
diagnostic.add(childDiagnostic); | |
if (childDiagnostic.getSeverity() == Diagnostic.WARNING) { | |
nWarnings++; | |
} else if (childDiagnostic.getSeverity() == Diagnostic.ERROR) { | |
nErrors++; | |
} else if (childDiagnostic.getSeverity() == Diagnostic.INFO) { | |
nInfo++; | |
} | |
} | |
} | |
StringBuilder builder = new StringBuilder(); | |
if (nErrors == 1) { | |
builder.append(NLS.bind(Messages.EcoreBrowser_error, nErrors)); | |
} else if (nErrors > 1) { | |
builder.append(NLS.bind(Messages.EcoreBrowser_errors, nErrors)); | |
} | |
if (nWarnings == 1) { | |
if (builder.length() > 0) { | |
builder.append(Messages.EcoreBrowser_separator); | |
} | |
builder.append(NLS.bind(Messages.EcoreBrowser_warning, nWarnings)); | |
} else if (nWarnings > 1) { | |
if (builder.length() > 0) { | |
builder.append(Messages.EcoreBrowser_separator); | |
} | |
builder.append(NLS.bind(Messages.EcoreBrowser_warnings, nWarnings)); | |
} | |
if (nInfo == 1) { | |
if (builder.length() > 0) { | |
builder.append(Messages.EcoreBrowser_separator); | |
} | |
builder.append(NLS.bind(Messages.EcoreBrowser_info, nInfo)); | |
} else if (nInfo > 1) { | |
if (builder.length() > 0) { | |
builder.append(Messages.EcoreBrowser_separator); | |
} | |
builder.append(NLS.bind(Messages.EcoreBrowser_infos, nInfo)); | |
} | |
if (!this.errorsButton.isDisposed()) { | |
if (builder.length() > 0) { | |
this.errorsButton.setText(builder.toString()); | |
this.errorsButton.setVisible(true); | |
} else { | |
this.errorsButton.setVisible(false); | |
} | |
final GridData errorsButtonGridData = new GridData(); | |
if (this.errorsButton.isVisible()) { | |
this.errorsButton.setSize(this.errorsButton.computeSize(SWT.DEFAULT, | |
SWT.DEFAULT)); | |
errorsButtonGridData.exclude = false; | |
} else { | |
errorsButtonGridData.exclude = true; | |
} | |
this.errorsButton.setLayoutData(errorsButtonGridData); | |
this.errorsButton.getParent().layout(); | |
} | |
this.fDiagnostic = diagnostic; | |
if (this.markerHelper.hasMarkers(this.editingDomain.getResourceSet())) { | |
this.markerHelper.deleteMarkers(this.editingDomain.getResourceSet()); | |
if (diagnostic.getSeverity() != Diagnostic.OK) { | |
try { | |
this.markerHelper.createMarkers(diagnostic); | |
} catch (CoreException exception) { | |
MoDiscoBrowserPlugin.getPlugin().log(exception); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Returns a diagnostic describing the errors and warnings listed in the | |
* resource and the specified exception (if any). | |
*/ | |
public Diagnostic analyzeResourceProblems(final Resource resource, final Exception exception) { | |
if (!resource.getErrors().isEmpty() || !resource.getWarnings().isEmpty()) { | |
Object errorData; | |
if (exception == null) { | |
errorData = resource; | |
} else { | |
errorData = exception; | |
} | |
BasicDiagnostic basicDiagnostic = new BasicDiagnostic(Diagnostic.ERROR, | |
MoDiscoBrowserPlugin.PLUGIN_ID, 0, NLS.bind(Messages.UI_ErrorFile_message, | |
resource.getURI()), new Object[] { errorData }); | |
basicDiagnostic.merge(EcoreUtil.computeDiagnostic(resource, true)); | |
return basicDiagnostic; | |
} else if (exception != null) { | |
return new BasicDiagnostic(Diagnostic.ERROR, MoDiscoBrowserPlugin.PLUGIN_ID, 0, | |
NLS.bind(Messages.UI_ErrorFile_message, resource.getURI()), | |
new Object[] { exception }); | |
} else { | |
return Diagnostic.OK_INSTANCE; | |
} | |
} | |
class BrowserAdapterFactory extends ComposedAdapterFactory implements IEditingDomainProvider { | |
public BrowserAdapterFactory(final ComposedAdapterFactory.Descriptor.Registry registry) { | |
super(registry); | |
} | |
public EditingDomain getEditingDomain() { | |
return EcoreBrowser.this.getEditingDomain(); | |
} | |
} | |
/** | |
* This sets up the editing domain for the model editor | |
*/ | |
protected void initializeEditingDomain() { | |
if (this.fResourceSet == null) { | |
initializeEditingDomain(new ResourceSetImpl()); | |
} | |
} | |
protected void initializeEditingDomain(final ResourceSet resourceSet) { | |
// Create an adapter factory that yields item providers. | |
this.adapterFactoryWithRegistry = new BrowserAdapterFactory( | |
ComposedAdapterFactory.Descriptor.Registry.INSTANCE); | |
this.adapterFactoryWithRegistry | |
.addAdapterFactory(new ResourceItemProviderAdapterFactory()); | |
this.adapterFactoryWithRegistry | |
.addAdapterFactory(new ReflectiveItemProviderAdapterFactory()); | |
final CommandStack commandStack = createCommandStack(); | |
// Create the editing domain with a special command stack. | |
final BrowserEditingDomain newEditingDomain = new BrowserEditingDomain( | |
this.adapterFactoryWithRegistry, commandStack, resourceSet, this); | |
setEditingDomain(newEditingDomain); | |
} | |
private CommandStack createCommandStack() { | |
// Create the command stack that will notify this editor as commands | |
// are executed. | |
CommandStack commandStack; | |
if (isReadOnly()) { | |
commandStack = new ReadOnlyCommandStack(); | |
} else { | |
commandStack = new BasicCommandStack(); | |
} | |
commandStack.addCommandStackListener(new CommandStackListener() { | |
public void commandStackChanged(final EventObject event) { | |
getParentComposite().getDisplay().asyncExec(new Runnable() { | |
public void run() { | |
firePropertyChange(IEditorPart.PROP_DIRTY); | |
// Try to select the affected objects. | |
final Command mostRecentCommand = ((CommandStack) event.getSource()) | |
.getMostRecentCommand(); | |
if (mostRecentCommand != null) { | |
// asyncExec is to make it happen after the | |
// refresh | |
Display.getDefault().asyncExec(new Runnable() { | |
public void run() { | |
try { | |
// avoid the view jumping around as | |
// the selection changes | |
// several times | |
EcoreBrowser.this.treeViewer.getTree().setRedraw(false); | |
selectAffectedElements(mostRecentCommand); | |
} finally { | |
EcoreBrowser.this.treeViewer.getTree().setRedraw(true); | |
} | |
} | |
}); | |
} | |
IPropertySheetPage page = EcoreBrowser.this.getPropertySheetPage(); | |
if (page != null && page.getControl() != null | |
&& !page.getControl().isDisposed()) { | |
if (page instanceof PropertySheetPage) { | |
PropertySheetPage propertyPage = (PropertySheetPage) page; | |
propertyPage.refresh(); | |
} else if (page instanceof TabbedPropertySheetPage) { | |
TabbedPropertySheetPage tabbedPropertyPage = (TabbedPropertySheetPage) page; | |
if (tabbedPropertyPage.getCurrentTab() != null) { | |
tabbedPropertyPage.refresh(); | |
} | |
} | |
} | |
} | |
}); | |
} | |
}); | |
return commandStack; | |
} | |
/** added for integration into Papyrus */ | |
protected void setEditingDomain(final AdapterFactoryEditingDomain editingDomain) { | |
this.editingDomain = editingDomain; | |
} | |
/** This is here for the listener to be able to call it. */ | |
@Override | |
protected void firePropertyChange(final int action) { | |
super.firePropertyChange(action); | |
} | |
/** | |
* Implements {@link IGotoMarker}. Select the EObject corresponding to the | |
* given marker | |
*/ | |
public void gotoMarker(final IMarker marker) { | |
try { | |
if (marker.getType().equals(EValidator.MARKER)) { | |
String uriAttribute = marker.getAttribute(EValidator.URI_ATTRIBUTE, null); | |
if (uriAttribute != null) { | |
URI uri = URI.createURI(uriAttribute); | |
EObject eObject = this.fResourceSet.getEObject(uri, true); | |
if (eObject != null) { | |
browseTo(eObject); | |
} | |
} | |
} | |
} catch (Exception e) { | |
MoDiscoLogger.logError(e, MoDiscoBrowserPlugin.getPlugin()); | |
} | |
} | |
public Composite getParentComposite() { | |
return this.parentComposite; | |
} | |
public EditingDomain getEditingDomain() { | |
return this.editingDomain; | |
} | |
public Collection<Resource> getSavedResources() { | |
return this.savedResources; | |
} | |
public Collection<Resource> getChangedResources() { | |
return this.changedResources; | |
} | |
public Collection<Resource> getRemovedResources() { | |
return this.removedResources; | |
} | |
/** | |
* If <code>true</code>, prevent modification or save. For example, if the | |
* resource being viewed comes from the package registry, it must not be | |
* saved. | |
*/ | |
public boolean isReadOnly() { | |
return !(getEditorInput() instanceof FileEditorInput); | |
} | |
public TreeViewer getTreeViewer() { | |
return this.treeViewer; | |
} | |
public void setStyleSashForm(final int styleSashForm) { | |
this.styleSashForm = styleSashForm; | |
} | |
protected void selectAffectedElements(final Command command) { | |
if (command instanceof DragAndDropOnLinkCommand) { | |
DragAndDropOnLinkCommand dragAndDropOnLinkCommand = (DragAndDropOnLinkCommand) command; | |
Command dropCommand = dragAndDropOnLinkCommand.getDropCommand(); | |
selectAffectedElements(dropCommand, null, dragAndDropOnLinkCommand.getLinkItem()); | |
} else if (command instanceof DragAndDropOnModelElementCommand) { | |
DragAndDropOnModelElementCommand dragAndDropOnModelElementCommand = (DragAndDropOnModelElementCommand) command; | |
Command dropCommand = dragAndDropOnModelElementCommand.getDropCommand(); | |
selectAffectedElements(dropCommand, | |
dragAndDropOnModelElementCommand.getModelElementItem(), null); | |
} else if (this.editingDomain instanceof BrowserEditingDomain) { | |
BrowserEditingDomain browserEditingDomain = (BrowserEditingDomain) this.editingDomain; | |
Object selectedElementForCommand = browserEditingDomain | |
.getEditorSelectionForCommand(command); | |
if (selectedElementForCommand instanceof ModelElementItem) { | |
ModelElementItem selectedModelElementItem = (ModelElementItem) selectedElementForCommand; | |
selectAffectedElements(command, selectedModelElementItem, null); | |
} else if (selectedElementForCommand instanceof LinkItem) { | |
LinkItem linkItem = (LinkItem) selectedElementForCommand; | |
selectAffectedElements(command, (ModelElementItem) linkItem.getTreeParent(), | |
linkItem); | |
} | |
} | |
} | |
private void selectAffectedElements(final Command command, | |
final ModelElementItem contextModelElementItem, final LinkItem contextLinkItem) { | |
if (command instanceof AddCommand) { | |
AddCommand addCommand = (AddCommand) command; | |
if (contextLinkItem != null) { | |
boolean result = selectElements(contextLinkItem, addCommand.getCollection()); | |
if (!result) { | |
setSelection(Collections.singletonList(contextLinkItem), true); | |
this.treeViewer.expandToLevel(contextLinkItem, 1); | |
} | |
} else if (contextModelElementItem != null) { | |
selectElements(contextModelElementItem, addCommand.getFeature(), | |
addCommand.getCollection()); | |
} else { | |
selectElements(addCommand.getOwner(), addCommand.getFeature(), | |
addCommand.getCollection()); | |
} | |
} else if (command instanceof SetCommand) { | |
SetCommand setCommand = (SetCommand) command; | |
if (contextModelElementItem != null) { | |
boolean result = selectElements(contextModelElementItem, setCommand.getFeature(), | |
Collections.singleton(setCommand.getValue())); | |
if (!result) { | |
ITreeElement treeParent = contextModelElementItem.getTreeParent(); | |
setSelection(Collections.singletonList(treeParent), true); | |
this.treeViewer.expandToLevel(treeParent, 1); | |
} | |
} else { | |
selectElements(setCommand.getOwner(), setCommand.getFeature(), | |
Collections.singleton(setCommand.getValue())); | |
} | |
} else if (command instanceof CreateChildCommand) { | |
CreateChildCommand createChildCommand = (CreateChildCommand) command; | |
Command command2 = createChildCommand.getCommand(); | |
selectAffectedElements(command2, contextModelElementItem, contextLinkItem); | |
} else if (command instanceof DeleteCommand) { | |
DeleteCommand deleteCommand = (DeleteCommand) command; | |
List<Command> commandList = deleteCommand.getCommandList(); | |
if (commandList.size() > 0) { | |
selectAffectedElements(commandList.get(0), contextModelElementItem, contextLinkItem); | |
} | |
} else if (command instanceof RemoveCommand) { | |
RemoveCommand removeCommand = (RemoveCommand) command; | |
LinkItem linkItem = null; | |
if (contextModelElementItem != null) { | |
ITreeElement parent = contextModelElementItem.getTreeParent(); | |
if (parent instanceof LinkItem) { | |
linkItem = (LinkItem) parent; | |
} else if (parent instanceof ModelElementItem) { | |
// ↑ possible with "collapse" customization | |
ModelElementItem modelElementItem = (ModelElementItem) parent; | |
setSelection(Collections.singletonList(modelElementItem), true); | |
return; | |
} | |
} | |
if (linkItem == null) { | |
browseTo(removeCommand.getOwner()); | |
ModelElementItem modelElementItem = getSelectedModelElementItem(); | |
linkItem = getLink(modelElementItem, removeCommand.getFeature()); | |
} | |
if (linkItem != null) { | |
this.treeViewer.expandToLevel(linkItem, 1); | |
setSelection(Collections.singletonList(linkItem), true); | |
} | |
} else if (command instanceof CompoundCommand) { | |
CompoundCommand compoundCommand = (CompoundCommand) command; | |
List<Command> commandList = compoundCommand.getCommandList(); | |
if (commandList.size() > 0) { | |
selectAffectedElements(commandList.get(commandList.size() - 1), | |
contextModelElementItem, contextLinkItem); | |
} | |
} else if (command instanceof CommandWrapper) { | |
CommandWrapper commandWrapper = (CommandWrapper) command; | |
selectAffectedElements(commandWrapper.getCommand(), contextModelElementItem, | |
contextLinkItem); | |
} | |
// PasteFromClipboardCommand : deliberately not handled, to let the user | |
// paste multiple times, without having to reselect the parent element | |
// each time | |
} | |
protected void selectElements(final EObject owner, final EStructuralFeature feature, | |
final Collection<?> collection) { | |
// TreePath treePath = findTreePathForElement(owner); | |
// Object lastSegment = treePath.getLastSegment(); | |
browseTo(owner); | |
ModelElementItem modelElementItem = getSelectedModelElementItem(); | |
selectElements(modelElementItem, feature, collection); | |
} | |
protected boolean selectElements(final ModelElementItem modelElementItem, | |
final EStructuralFeature feature, final Collection<?> collection) { | |
if (modelElementItem != null) { | |
LinkItem linkItem = getLink(modelElementItem, feature); | |
if (linkItem != null) { | |
boolean result = selectElements(linkItem, collection); | |
if (!result) { | |
setSelection(Collections.singletonList(linkItem), true); | |
this.treeViewer.expandToLevel(linkItem, 1); | |
} | |
return true; | |
} | |
} | |
return false; | |
} | |
protected boolean selectElements(final LinkItem linkItem, final Collection<?> collection) { | |
List<ModelElementItem> elementItems = new ArrayList<ModelElementItem>(); | |
for (Object object : collection) { | |
if (object instanceof EObject) { | |
EObject eObject = (EObject) object; | |
ModelElementItem elementItem = getElement(linkItem, eObject); | |
if (elementItem != null) { | |
elementItems.add(elementItem); | |
} | |
} | |
} | |
if (!elementItems.isEmpty()) { | |
setSelection(elementItems, true); | |
return true; | |
} | |
return false; | |
} | |
protected void setSelection(final List<? extends ITreeElement> treeElements, | |
final boolean reveal) { | |
List<TreePath> treePaths = new ArrayList<TreePath>(); | |
for (ITreeElement treeElement : treeElements) { | |
List<ITreeElement> segments = new ArrayList<ITreeElement>(); | |
ITreeElement current = treeElement; | |
while (current != null) { | |
segments.add(current); | |
current = current.getTreeParent(); | |
} | |
if (segments.size() > 0) { | |
ITreeElement[] segmentsArray = new ITreeElement[segments.size()]; | |
for (int i = 0; i < segments.size(); i++) { | |
segmentsArray[i] = segments.get(segments.size() - i - 1); | |
} | |
treePaths.add(new TreePath(segmentsArray)); | |
} | |
} | |
if (!treePaths.isEmpty()) { | |
this.treeViewer.setSelection( | |
new TreeSelection(treePaths.toArray(new TreePath[treePaths.size()])), reveal); | |
} | |
} | |
protected LinkItem getLink(final ModelElementItem selectedModelElementItem, | |
final EStructuralFeature feature) { | |
ITreeContentProvider contentProvider = (ITreeContentProvider) this.treeViewer | |
.getContentProvider(); | |
Object[] children = contentProvider.getChildren(selectedModelElementItem); | |
for (Object child : children) { | |
if (child instanceof LinkItem) { | |
LinkItem linkItem = (LinkItem) child; | |
if (linkItem.getReference() == feature) { | |
return linkItem; | |
} | |
} | |
} | |
return null; | |
} | |
protected ModelElementItem getElement(final LinkItem linkItem, final EObject eObject) { | |
ITreeContentProvider contentProvider = (ITreeContentProvider) this.treeViewer | |
.getContentProvider(); | |
Object[] children = contentProvider.getChildren(linkItem); | |
for (Object child : children) { | |
if (child instanceof ModelElementItem) { | |
ModelElementItem modelElementItem = (ModelElementItem) child; | |
if (EcoreUtil.getURI(modelElementItem.getEObject()).equals( | |
EcoreUtil.getURI(eObject))) { | |
return modelElementItem; | |
} | |
} | |
} | |
return null; | |
} | |
protected ModelElementItem getSelectedModelElementItem() { | |
ITreeSelection selection = (ITreeSelection) this.treeViewer.getSelection(); | |
Object firstElement = selection.getFirstElement(); | |
if (firstElement instanceof ModelElementItemEx) { | |
ModelElementItemEx modelElementItem = (ModelElementItemEx) firstElement; | |
return modelElementItem; | |
} | |
return null; | |
} | |
public void doWhenLoaded(final Runnable runnable) { | |
if (this.loaded) { | |
Display.getDefault().syncExec(runnable); | |
} else { | |
this.doWhenLoaded.add(runnable); | |
} | |
} | |
/** | |
* Replace the default context by a dummy one when the given widget is | |
* focused. The dummy context is used to redefine the "Ctrl+X", "Ctrl+C" and | |
* "Ctrl+V" key bindings to a command which does nothing. This is useful to | |
* prevent these commands associated to the existing context from being | |
* executed when this widget is focused. | |
*/ | |
private void fixClipboardCommands(final Control control) { | |
final IWorkbench workbench = PlatformUI.getWorkbench(); | |
final IContextService contextService = (IContextService) workbench | |
.getService(IContextService.class); | |
control.addFocusListener(new FocusListener() { | |
private IContextActivation contextActivation = null; | |
public void focusGained(final FocusEvent event) { | |
this.contextActivation = contextService | |
.activateContext("org.eclipse.gmt.modisco.infra.browser.dummyContext"); //$NON-NLS-1$ | |
} | |
public void focusLost(final FocusEvent event) { | |
if (this.contextActivation != null) { | |
contextService.deactivateContext(this.contextActivation); | |
} | |
} | |
}); | |
} | |
/** | |
* * Adapter used to update the problem indication when resources are | |
* demanded loaded. | |
*/ | |
private final EContentAdapter problemIndicationAdapter = new EContentAdapter() { | |
@Override | |
public void notifyChanged(final Notification notification) { | |
if (notification.getNotifier() instanceof Resource) { | |
switch (notification.getFeatureID(Resource.class)) { | |
case Resource.RESOURCE__IS_LOADED: | |
case Resource.RESOURCE__ERRORS: | |
case Resource.RESOURCE__WARNINGS: | |
Resource resource = (Resource) notification.getNotifier(); | |
Diagnostic diagnostic = analyzeResourceProblems(resource, null); | |
if (diagnostic.getSeverity() != Diagnostic.OK) { | |
EcoreBrowser.this.resourceToDiagnosticMap.put(resource, diagnostic); | |
} else { | |
EcoreBrowser.this.resourceToDiagnosticMap.remove(resource); | |
} | |
if (EcoreBrowser.this.updateProblemIndication) { | |
getSite().getShell().getDisplay().asyncExec(new Runnable() { | |
public void run() { | |
updateProblemIndication(); | |
} | |
}); | |
} | |
break; | |
default: | |
} | |
} else { | |
super.notifyChanged(notification); | |
} | |
} | |
@Override | |
protected void setTarget(final Resource theTarget) { | |
basicSetTarget(theTarget); | |
} | |
@Override | |
protected void unsetTarget(final Resource theTarget) { | |
basicUnsetTarget(theTarget); | |
} | |
}; | |
/** | |
* Refreshes the selection (checked) state of actions in the Browser's | |
* toolbar. | |
*/ | |
public void refreshToolbar() { | |
this.instancesToolBar.refresh(); | |
} | |
protected Text getSearchBox() { | |
return this.searchBox; | |
} | |
protected void setSearchBox(final Text searchBox) { | |
this.searchBox = searchBox; | |
} | |
public IWorkbenchSiteProgressService getProgressService() { | |
IWorkbenchSiteProgressService service = null; | |
Object siteService = getSite().getAdapter(IWorkbenchSiteProgressService.class); | |
if (siteService != null) { | |
service = (IWorkbenchSiteProgressService) siteService; | |
} | |
return service; | |
} | |
public boolean isRefreshing() { | |
return this.refreshJob != null && this.refreshJob.getState() != Job.NONE; | |
} | |
} |