blob: 8db8cbaaa7ae38ab7d2a0cca1f7ed26b40ba8f74 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2019 Mia-Software and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.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.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.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.facet.util.core.Logger;
import org.eclipse.modisco.infra.browser.Messages;
import org.eclipse.modisco.infra.browser.MoDiscoBrowserPlugin;
import org.eclipse.modisco.infra.browser.actions.LoadFacetsAction;
import org.eclipse.modisco.infra.browser.core.DragAndDropOnLinkCommand;
import org.eclipse.modisco.infra.browser.core.DragAndDropOnModelElementCommand;
import org.eclipse.modisco.infra.browser.core.InstancesForMetaclass;
import org.eclipse.modisco.infra.browser.core.InstancesForMetaclasses;
import org.eclipse.modisco.infra.browser.core.MetaclassList;
import org.eclipse.modisco.infra.browser.core.ModelElementItemEx;
import org.eclipse.modisco.infra.browser.core.QueryItem;
import org.eclipse.modisco.infra.browser.core.SearchResults;
import org.eclipse.modisco.infra.browser.core.InstancesForMetaclasses.MetaclassesChangeListener;
import org.eclipse.modisco.infra.browser.custom.MetamodelView;
import org.eclipse.modisco.infra.browser.custom.core.CustomizationsCatalog;
import org.eclipse.modisco.infra.browser.dialogs.ErrorsDialog;
import org.eclipse.modisco.infra.browser.extensions.LoadingDepthRegistry;
import org.eclipse.modisco.infra.browser.extensions.listeners.DoubleClickListener;
import org.eclipse.modisco.infra.browser.preferences.PreferenceConstants;
import org.eclipse.modisco.infra.browser.queries.SelectedQueriesManager;
import org.eclipse.modisco.infra.browser.queries.SelectedQuery;
import org.eclipse.modisco.infra.browser.uicore.ChangeListener;
import org.eclipse.modisco.infra.browser.uicore.UnwrappingSelectionProvider;
import org.eclipse.modisco.infra.browser.uicore.internal.Activator;
import org.eclipse.modisco.infra.browser.uicore.internal.AppearanceConfiguration;
import org.eclipse.modisco.infra.browser.uicore.internal.CustomTreePainter;
import org.eclipse.modisco.infra.browser.uicore.internal.customization.CustomizationEngine;
import org.eclipse.modisco.infra.browser.uicore.internal.model.AttributeItem;
import org.eclipse.modisco.infra.browser.uicore.internal.model.BigListItem;
import org.eclipse.modisco.infra.browser.uicore.internal.model.ITreeElement;
import org.eclipse.modisco.infra.browser.uicore.internal.model.LinkItem;
import org.eclipse.modisco.infra.browser.uicore.internal.model.ModelElementItem;
import org.eclipse.modisco.infra.browser.uicore.internal.util.EMFUtil;
import org.eclipse.modisco.infra.browser.uicore.internal.util.ImageProvider;
import org.eclipse.modisco.infra.common.core.internal.builder.AbstractMoDiscoCatalog.ModiscoCatalogChangeListener;
import org.eclipse.modisco.infra.common.core.logging.MoDiscoLogger;
import org.eclipse.modisco.infra.common.ui.internal.controls.FormStyleSashForm;
import org.eclipse.modisco.infra.common.ui.internal.controls.Tooltip;
import org.eclipse.modisco.infra.common.ui.internal.editorInputs.IResourceEditorInput;
import org.eclipse.modisco.infra.common.ui.internal.util.DialogUtils;
import org.eclipse.modisco.infra.facet.Facet;
import org.eclipse.modisco.infra.facet.FacetSet;
import org.eclipse.modisco.infra.facet.core.FacetSetCatalog;
import org.eclipse.modisco.infra.facet.core.adapters.instances.MetaclassInstancesAdapterFactoryWithFacet;
import org.eclipse.modisco.infra.facet.core.adapters.instances.MetaclassInstancesAdapterWithFacet;
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.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.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.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;
}
}