diff options
Diffstat (limited to 'plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra')
105 files changed, 14551 insertions, 12 deletions
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java index 27101698e64..730eea20ada 100644 --- a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2016 CEA LIST, Christian W. Damus, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,12 +8,22 @@ *
* Contributors:
* Francois Le Fevre (CEA LIST) francois.le-fevre@cea.fr - Initial API and implementation
+ * Christian W. Damus = bug 485220
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.ui;
import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.services.spi.IContextualServiceRegistryTracker;
+import org.eclipse.papyrus.infra.tools.spi.IExecutorServiceFactory;
+import org.eclipse.papyrus.infra.ui.util.UIUtil;
+import org.eclipse.papyrus.infra.ui.util.WorkbenchPartHelper;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
/**
* The activator class controls the plug-in life cycle
@@ -33,31 +43,46 @@ public class Activator extends AbstractUIPlugin { */
public static LogHelper log;
+ private ServiceRegistration<IExecutorServiceFactory> executorFactoryReg;
+ private ServiceRegistration<IContextualServiceRegistryTracker> serviceRegistryTrackerReg;
+
/**
* The constructor
*/
public Activator() {
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
- */
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
log = new LogHelper(this);
+
+ IExecutorServiceFactory executorFactory = () -> UIUtil.createUIExecutor(Display.getDefault());
+ executorFactoryReg = context.registerService(IExecutorServiceFactory.class, executorFactory, null);
+
+ IContextualServiceRegistryTracker serviceRegistryTracker = () -> {
+ ServicesRegistry result = null;
+ IEditorPart editor = WorkbenchPartHelper.getCurrentActiveEditorPart();
+ if (editor != null) {
+ result = editor.getAdapter(ServicesRegistry.class);
+ }
+ return result;
+ };
+ serviceRegistryTrackerReg = context.registerService(IContextualServiceRegistryTracker.class, serviceRegistryTracker, null);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
- */
@Override
public void stop(BundleContext context) throws Exception {
+ if (serviceRegistryTrackerReg != null) {
+ serviceRegistryTrackerReg.unregister();
+ serviceRegistryTrackerReg = null;
+ }
+ if (executorFactoryReg != null) {
+ executorFactoryReg.unregister();
+ executorFactoryReg = null;
+ }
+
plugin = null;
super.stop(context);
}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java new file mode 100644 index 00000000000..1fb84925184 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java @@ -0,0 +1,263 @@ +/***************************************************************************** + * Copyright (c) 2008 CEA LIST. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.contentoutline; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.Platform; +import org.eclipse.papyrus.infra.core.editor.BackboneException; +import org.eclipse.papyrus.infra.core.extension.BadClassNameException; +import org.eclipse.papyrus.infra.core.extension.NotFoundException; +import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor; +import org.eclipse.papyrus.infra.ui.extension.diagrameditor.EditorDescriptorExtensionFactory; +import org.osgi.framework.Bundle; + +public class ContentOutlineRegistry { + + /** ID of the editor extension (schema filename) */ + public static final String EDITOR_EXTENSION_ID = "papyrusContentOutline"; + + private static String classAttributeName = "class"; + + private static String actionBarContributorIdPropertyName = "actionBarContributorId"; + + /** Namespace where to look for the extension points. */ + protected String extensionPointNamespace; + + /** + * The selected content outline. + */ + protected IPapyrusContentOutlinePage contentOutline; + + /** + * Associated editor. + */ + private IMultiDiagramEditor multiEditor; + + /** + * Constructor. defaultContext, input and site are explicitly required in + * order be sure that they are initialized. The multiEditor should be + * initialized. In particular, getEditorSite(), getEditorInput() and + * getDefaultContext() should return initialized values. + * + * @param multiEditor + * @param defaultContext + * @param input + * @param site + * @param extensionPointNamespace + */ + public ContentOutlineRegistry(IMultiDiagramEditor multiEditor, String extensionPointNamespace) { + this.multiEditor = multiEditor; + this.extensionPointNamespace = extensionPointNamespace; + } + + /** + * Returns the single instance of the content outline. Creates one if + * necessary. + * + * @return the contentOutline the single instance of the content outline + * @throws BackboneException + * exception thrown when the outline can not be created. + */ + public IPapyrusContentOutlinePage getContentOutline() throws BackboneException { + if (contentOutline == null) { + createContentOutline(); + } + return contentOutline; + } + + /** + * Return the {@link ContentOutlineDescriptor} with the highest priority. + * + * @return + * @throws BackboneException + * @throws NotFoundException + * If no ContentOutline can be found in extensions + */ + private ContentOutlineDescriptor getContentOutlineDescriptor() throws BackboneException { + IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPointNamespace, EDITOR_EXTENSION_ID); + ContentOutlineDescriptor found = null; + + // look for the one with the highest priority + for (IConfigurationElement ele : configElements) { + ContentOutlineDescriptor desc = new ContentOutlineDescriptor(ele); + if (desc.isHigher(found)) { + found = desc; + } + } + + // Instanciate the object + if (found == null) { + throw new NotFoundException("No ContentOutline registered."); //$NON-NLS-1$ + } + + return found; + + } + + /** + * Creates the content outline from the selected extension. + * + * @throws BackboneException + * exception thrown when the outline can not be created. + */ + private void createContentOutline() throws BackboneException { + + ContentOutlineDescriptor found = getContentOutlineDescriptor(); + // Instanciate the object + if (found != null) { + contentOutline = found.createContentOutlinePage(); + } + } + + /** + * Inner Descriptor for content outline. This class load data from Eclipse + * extension mechanism TODO Change the parent class. It is here just to have + * quick code. + */ + protected class ContentOutlineDescriptor extends EditorDescriptorExtensionFactory { + + private int priority; + + private String className; + + private String actionBarContributorID; + + private IConfigurationElement element; + + /** + * Instance is created when requested. + */ + protected IPapyrusContentOutlinePage instance = null; + + /** + * Create a descriptor backuped by the config element. + */ + protected ContentOutlineDescriptor(IConfigurationElement element) throws BackboneException { + String tagName = "contentoutline"; + checkTagName(element, tagName); + this.className = element.getAttribute(classAttributeName); + this.actionBarContributorID = element.getAttribute(actionBarContributorIdPropertyName); + try { + this.priority = Integer.parseInt(element.getAttribute("priority")); + } catch (NumberFormatException e) { + this.priority = 0; + } + + this.element = element; + // check parameters + if (className == null) { + throw new BadClassNameException("Class name must be set", "contentoutline", classAttributeName); //$NON-NLS-1$ //$NON-NLS-2$ + } + + } + + /** + * Compare priority. The highest priority win. + */ + public boolean isHigher(ContentOutlineDescriptor found) { + if (found == null) { + return true; + } + return this.getPriority() > found.getPriority(); + } + + /** + * Return the higher value of the descriptor. This value is used to + * order the contentOutline. The highest priority win. + */ + private int getPriority() { + return priority; + } + + /** + * @return the actionBarContributorID + */ + public String getActionBarContributorID() { + return actionBarContributorID; + } + + /** + * Returns the content outline page instance (lazy initialization) + * + * @return the context outline page + * @throws BackboneException + * exception thrown when a problem occurs. + */ + protected IPapyrusContentOutlinePage getContentOutline() throws BackboneException { + if (instance == null) { + instance = createContentOutlinePage(); + } + return instance; + } + + /** + * Create the class corresponding to the class attribute. + */ + private Class<IPapyrusContentOutlinePage> loadClass() throws BadClassNameException { + if (className == null || className.length() == 0) { + throw new BadClassNameException("Classname should be set.", "contentoutline", classAttributeName); //$NON-NLS-1$ //$NON-NLS-2$ + } + Class<IPapyrusContentOutlinePage> factoryClass; + try { + factoryClass = (Class<IPapyrusContentOutlinePage>) Class.forName(className); + } catch (ClassNotFoundException e) { + // try another way + try { + String declaringID = element.getContributor().getName(); + Bundle bundle = Platform.getBundle(declaringID); + factoryClass = (Class<IPapyrusContentOutlinePage>) bundle.loadClass(className); + } catch (ClassNotFoundException e1) { + throw new BadClassNameException("", "contentoutline", classAttributeName, e1); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + return factoryClass; + } + + /** + * create the outlinepage by calling constructor without parameter and + * then call init method + * + * @return the outline. + * @throws BackboneException + */ + protected IPapyrusContentOutlinePage createContentOutlinePage() throws BackboneException { + if (false) { + System.out.println("Not yet"); // FIXME : no syso + return null; + } + try { + IPapyrusContentOutlinePage outline = loadClass().newInstance(); + outline.init(multiEditor); + return outline; + + } catch (SecurityException e) { + // Lets propagate. This is an implementation problem that should + // be solved by programmer. + throw new RuntimeException(e); + } + + catch (InstantiationException e) { + // Lets propagate. This is an implementation problem that should + // be solved by programmer. + // throw new RuntimeException(e); + } catch (IllegalAccessException e) { + // Lets propagate. This is an implementation problem that should + // be solved by programmer. + throw new RuntimeException(e); + } + return null; + } + + } // end class +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java new file mode 100644 index 00000000000..15116aa267b --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java @@ -0,0 +1,34 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.contentoutline;
+
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+/**
+ * Extends the original interface to add the init method.
+ */
+public interface IPapyrusContentOutlinePage extends org.eclipse.ui.views.contentoutline.IContentOutlinePage {
+
+ /**
+ * Init the content outline.
+ *
+ * @param multiEditor
+ * the multiEditor is used to access to the context
+ * @throws BackboneException
+ * during research of the associated context.
+ */
+ void init(IMultiDiagramEditor multiEditor) throws BackboneException;
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java new file mode 100644 index 00000000000..4cf52a66930 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java @@ -0,0 +1,1098 @@ +/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and other.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437217
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.contentoutline;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.papyrus.infra.core.Activator;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IEditorPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IPageLifeCycleEventsListener;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor;
+import org.eclipse.papyrus.infra.ui.editor.reload.EditorReloadEvent;
+import org.eclipse.papyrus.infra.ui.editor.reload.IEditorReloadListener;
+import org.eclipse.papyrus.infra.ui.editor.reload.IReloadContextProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.part.IPageBookViewPage;
+import org.eclipse.ui.part.IPageSite;
+import org.eclipse.ui.part.Page;
+import org.eclipse.ui.part.PageBook;
+import org.eclipse.ui.part.PageSite;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Page for Papyrus outline when active nested editor is a GMF editor
+ */
+public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusContentOutlinePage, IPageLifeCycleEventsListener, IEditorReloadListener {
+
+ /** The editor for which I am a slave. */
+ private IMultiDiagramEditor multiEditor;
+
+ /** Sash window container to listen for page changes inside the same editor */
+ private ISashWindowsContainer sashWindowsContainer;
+
+ /** Page book in which all outline controls of nested editors will be stored and displayed one by one */
+ private PageBook sashEditorPageBook;
+
+ /**
+ * Map from papyrus pages (representing nested editors) to outline page records (key type: <code>org.eclipse.papyrus.infra.core.sasheditor.editor.IPage</code>;
+ * value type: <code>OutlinePageRec</code>).
+ */
+ private Map<IPage, OutlinePageRec> mapIPapyrusPageToOutlineRec = new HashMap<IPage, OutlinePageRec>();
+
+ /**
+ * The page rec which provided the current page or <code>null</code>
+ */
+ private OutlinePageRec activeRec;
+
+ /**
+ * Default page rec that displays a simple message
+ */
+ private OutlinePageRec defaultPageRec;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init(IMultiDiagramEditor multiEditor) {
+ this.multiEditor = multiEditor;
+
+ internalInit(multiEditor);
+
+ IReloadableEditor.Adapter.getAdapter(multiEditor).addEditorReloadListener(this);
+ }
+
+ private void internalInit(IMultiDiagramEditor multiEditor) {
+ sashWindowsContainer = (ISashWindowsContainer) multiEditor.getAdapter(ISashWindowsContainer.class);
+ sashWindowsContainer.addPageLifeCycleListener(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init(IPageSite pageSite) {
+ IViewSite viewSite = getViewSite(pageSite);
+
+ DelegatedPageSite delegatedPageSite = new DelegatedPageSite(viewSite, this);
+ super.init(delegatedPageSite);
+ }
+
+ /**
+ * /**
+ * The <code>PageBookView</code> implementation of this <code>IWorkbenchPart</code> method cleans up all the pages. Subclasses
+ * may extend.
+ */
+ @Override
+ public void dispose() {
+ if (multiEditor != null) {
+ IReloadableEditor.Adapter.getAdapter(multiEditor).removeEditorReloadListener(this);
+ }
+
+ internalDispose();
+
+ multiEditor = null;
+
+ // Run super.
+ super.dispose();
+ }
+
+ private void internalDispose() {
+ // Deref all of the pages.
+ activeRec = null;
+ if (defaultPageRec != null) {
+ // check for null since the default page may not have
+ // been created (ex. perspective never visible)
+ defaultPageRec.contentOutlinePage.dispose();
+ defaultPageRec.dispose();
+ defaultPageRec = null;
+ }
+
+ java.util.List<OutlinePageRec> records = new ArrayList<NestedEditorDelegatedOutlinePage.OutlinePageRec>(mapIPapyrusPageToOutlineRec.values());
+ Iterator<OutlinePageRec> itr = records.iterator();
+ while (itr.hasNext()) {
+ OutlinePageRec rec = itr.next();
+ removePage(rec);
+ }
+
+ // remove listener and all refs to editor
+ sashWindowsContainer.removePageLifeCycleListener(this);
+ }
+
+ /**
+ * Refreshes the global actions for the active page.
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected void refreshGlobalActionHandlers() {
+ // Clear old actions.
+ IActionBars bars = getSite().getActionBars();
+ bars.clearGlobalActionHandlers();
+
+ // Set new actions.
+ Map newActionHandlers = ((SubActionBars) activeRec.getPageSite().getActionBars()).getGlobalActionHandlers();
+ if (newActionHandlers != null) {
+ Set<?> keys = newActionHandlers.entrySet();
+ Iterator<?> iter = keys.iterator();
+ while (iter.hasNext()) {
+ Map.Entry<String, IAction> entry = (Map.Entry) iter.next();
+ bars.setGlobalActionHandler(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISelection getSelection() {
+ // nothing here
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSelection(ISelection selection) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void createControl(Composite parent) {
+ sashEditorPageBook = new PageBook(parent, SWT.BORDER);
+
+ createContents();
+ }
+
+ protected void createContents() {
+ // Create the default page rec.
+ IContentOutlinePage defaultPage = createDefaultPage(sashEditorPageBook);
+ defaultPageRec = new OutlinePageRec(null, defaultPage);
+ preparePage(defaultPageRec);
+
+ // Show the initial active page or the default page
+ IPage activePage = sashWindowsContainer.getActiveSashWindowsPage();
+ if (activePage != null) {
+ OutlinePageRec rec = getOutlinePageRec(activePage);
+ if (rec == null) {
+ rec = createPage(activePage);
+ }
+
+ // Show the page, if it was successfully created
+ if (rec != null) {
+ showOutlinePageRec(rec);
+ } else {
+ showOutlinePageRec(defaultPageRec);
+ }
+ } else {
+ showOutlinePageRec(defaultPageRec);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Control getControl() {
+ return sashEditorPageBook;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageChanged(IPage newPage) {
+ // throw new UnsupportedOperationException("pageChanged not implemented " + newPage);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageOpened(IPage page) {
+ // Activator.log.debug("Opened");
+ // create the new Outline
+ // Create a page for the part.
+ OutlinePageRec rec = getOutlinePageRec(page);
+ if (rec == null) {
+ rec = createPage(page);
+ }
+
+ // Show the page, if it was successfully created
+ if (rec != null) {
+ showOutlinePageRec(rec);
+ } else {
+ showOutlinePageRec(defaultPageRec);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageClosed(IPage papyrusPage) {
+ // Activator.log.debug("Closed");
+ // Update the active part.
+ if (activeRec != null && activeRec.papyrusPage == papyrusPage) {
+ showOutlinePageRec(defaultPageRec);
+ }
+
+ // Find and remove the part page.
+ OutlinePageRec rec = getOutlinePageRec(papyrusPage);
+ if (rec != null) {
+ removePage(rec);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageActivated(IPage page) {
+ // Activator.log.debug("Activated");
+ // Create a page for the partm, if necessary.
+ OutlinePageRec rec = getOutlinePageRec(page, true);
+
+ // Show the page, if it was successfully created
+ if (rec != null) {
+ showOutlinePageRec(rec);
+ } else {
+ showOutlinePageRec(defaultPageRec);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageDeactivated(IPage page) {
+ // throw new UnsupportedOperationException("pageDeactivated not implemented " + page);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAboutToBeOpened(IPage page) {
+ // throw new UnsupportedOperationException("pageAboutToBeOpened not implemented "+page);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAboutToBeClosed(IPage page) {
+ // throw new UnsupportedOperationException("pageAboutToBeClosed not implemented " + page);
+ }
+
+ @Override
+ public void editorAboutToReload(EditorReloadEvent event) {
+ event.putContext(new OutlineContext());
+
+ internalDispose();
+ }
+
+ @Override
+ public void editorReloaded(EditorReloadEvent event) {
+ internalInit(event.getEditor());
+ createContents();
+
+ ((OutlineContext) event.getContext()).restore();
+ }
+
+ // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MAINLY INSPIRED FROM PAGE BOOK VIEW
+ // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates and returns the default page for this view.
+ *
+ * @param book
+ * the pagebook control
+ * @return the default page
+ */
+ protected IContentOutlinePage createDefaultPage(PageBook book) {
+ MessageOutlinePage page = new MessageOutlinePage();
+ initPage(page);
+ page.createControl(book);
+ return page;
+ }
+
+ /**
+ * Creates an outline record for a given papyrus Page. Adds it to the pagebook but does not show it.
+ *
+ * @param page
+ * The nested editor we are created an outline.
+ * @return the created outline page record
+ */
+ protected OutlinePageRec createPage(IPage papyrusPage) {
+ OutlinePageRec rec = doCreatePage(papyrusPage);
+ if (rec != null) {
+ mapIPapyrusPageToOutlineRec.put(papyrusPage, rec);
+ preparePage(rec);
+ }
+ return rec;
+ }
+
+ /**
+ * Prepares the page in the given page rec for use in this view.
+ *
+ * @param rec
+ */
+ protected void preparePage(OutlinePageRec rec) {
+ IPageSite site = null;
+
+ if (!doesPageExist(rec.contentOutlinePage)) {
+ if (rec.contentOutlinePage instanceof IPageBookViewPage) {
+ site = ((IPageBookViewPage) rec.contentOutlinePage).getSite();
+ rec.setPageSite(site);
+ }
+ }
+ }
+
+ /**
+ * Initializes the given page with a page site.
+ * <p>
+ * Subclasses should call this method after the page is created but before creating its controls.
+ * </p>
+ * <p>
+ * Subclasses may override
+ * </p>
+ *
+ * @param page
+ * The page to initialize
+ */
+ protected void initPage(IPageBookViewPage page) {
+ try {
+ IPageSite site = super.getSite();
+ // try to create a specific page site for this page
+ page.init(new PageSite(getViewSite(site)));
+ } catch (PartInitException e) {
+ Activator.log.error(e);
+ }
+ }
+
+ /**
+ * @param site
+ * the page site from which parent view site is retrieved
+ * @return the retrieved page site
+ */
+ protected static IViewSite getViewSite(IPageSite site) {
+ if (site instanceof IViewSite) {
+ return ((IViewSite) site);
+ }
+ // no way to get the IViewSite from the page site.
+ if (site instanceof PageSite) {
+ try {
+ Field parentSiteField = PageSite.class.getDeclaredField("parentSite");
+ parentSiteField.setAccessible(true);
+ Object parentSite = parentSiteField.get(site);
+ if (parentSite instanceof IViewSite) {
+ return ((IViewSite) parentSite);
+ }
+ } catch (SecurityException e) {
+ Activator.log.error(e);
+ } catch (NoSuchFieldException e) {
+ Activator.log.error(e);
+ } catch (IllegalArgumentException e) {
+ Activator.log.error(e);
+ } catch (IllegalAccessException e) {
+ Activator.log.error(e);
+ }
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * Method declared on PageBookView.
+ */
+ protected OutlinePageRec doCreatePage(IPage papyrusPage) {
+ // Try to get an outline page.
+ if (papyrusPage instanceof IEditorPage) {
+ IEditorPart part = ((IEditorPage) papyrusPage).getIEditorPart();
+ Object obj = getAdapter(part, IContentOutlinePage.class, false);
+ if (obj instanceof IContentOutlinePage) {
+ IContentOutlinePage page = (IContentOutlinePage) obj;
+ if (page instanceof IPageBookViewPage) {
+ initPage((IPageBookViewPage) page);
+ }
+ page.createControl(getPageBook());
+ return new OutlinePageRec(papyrusPage, page);
+ }
+ }
+
+ // There is no content outline
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DelegatedPageSite getSite() {
+ return (DelegatedPageSite) super.getSite();
+ }
+
+ /*
+ * (non-Javadoc)
+ * Method declared on PageBookView.
+ */
+ protected void doDestroyPage(IPage papyrusPage, OutlinePageRec rec) {
+ IContentOutlinePage contentOutlinePage = rec.contentOutlinePage;
+ contentOutlinePage.dispose();
+ rec.dispose();
+ }
+
+ protected Collection<OutlinePageRec> getAllPages() {
+ return mapIPapyrusPageToOutlineRec.values();
+ }
+
+ /**
+ * Returns true if the page has already been created.
+ *
+ * @param page
+ * the page to test
+ * @return true if this page has already been created.
+ */
+ protected boolean doesPageExist(IContentOutlinePage page) {
+ return mapIPapyrusPageToOutlineRec.containsKey(page);
+ }
+
+ /**
+ * Returns the papyrus page which contributed the current outline page to this view.
+ *
+ * @return the page which contributed the current outline page or <code>null</code> if no part contributed the current page
+ */
+ protected IPage getCurrentContributingPage() {
+ if (activeRec == null) {
+ return null;
+ }
+ return activeRec.papyrusPage;
+ }
+
+ /**
+ * Returns the currently visible outline page for this view or <code>null</code> if no page is currently visible.
+ *
+ * @return the currently visible page
+ */
+ public IContentOutlinePage getCurrentOutlinePage() {
+ if (activeRec == null) {
+ return null;
+ }
+ return activeRec.contentOutlinePage;
+ }
+
+ /**
+ * Returns the view site for the given page of this view.
+ *
+ * @param page
+ * the page
+ * @return the corresponding site, or <code>null</code> if not found
+ */
+ protected IPageSite getPageSite(IPage page) {
+ OutlinePageRec rec = getOutlinePageRec(page);
+ if (rec != null) {
+ return rec.getPageSite();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the default page for this view.
+ *
+ * @return the default page
+ */
+ public IContentOutlinePage getDefaultOutlinePage() {
+ return defaultPageRec.contentOutlinePage;
+ }
+
+ /**
+ * Returns the pagebook control for this view.
+ *
+ * @return the pagebook control, or <code>null</code> if not initialized
+ */
+ protected PageBook getPageBook() {
+ return sashEditorPageBook;
+ }
+
+ /**
+ * Returns the page record for the given part.
+ *
+ * @param part
+ * the part
+ * @return the corresponding page record, or <code>null</code> if not
+ * found
+ */
+ protected OutlinePageRec getOutlinePageRec(IPage papyrusPage) {
+ return mapIPapyrusPageToOutlineRec.get(papyrusPage);
+ }
+
+ OutlinePageRec getOutlinePageRec(IPage papyrusPage, boolean create) {
+ OutlinePageRec result = getOutlinePageRec(papyrusPage);
+ if (result == null) {
+ result = createPage(papyrusPage);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the page record for the given page of this view.
+ *
+ * @param page
+ * the page
+ * @return the corresponding page record, or <code>null</code> if not
+ * found
+ */
+ protected OutlinePageRec getPageRec(IContentOutlinePage contentOutlinePage) {
+ Iterator<OutlinePageRec> itr = mapIPapyrusPageToOutlineRec.values().iterator();
+ while (itr.hasNext()) {
+ OutlinePageRec rec = itr.next();
+ if (rec.contentOutlinePage == contentOutlinePage) {
+ return rec;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes a page record.
+ *
+ * @param rec
+ * the page record to remove
+ */
+ protected void removePage(OutlinePageRec rec) {
+ mapIPapyrusPageToOutlineRec.remove(rec.papyrusPage);
+
+ Control control = rec.contentOutlinePage.getControl();
+ if (control != null && !control.isDisposed()) {
+ // Dispose the page's control so pages don't have to do this in their dispose method.
+ // The page's control is a child of this view's control so if this view is closed, the page's control will already be disposed.
+ control.dispose();
+ }
+
+ // Do this before destroying the page, otherwise we won't be able to retrieve the page site (it will be null)
+ IPageSite site = rec.getPageSite();
+ if (site instanceof PageSite) { // test null pointer and PageSite
+ ((SubActionBars) ((PageSite) site).getActionBars()).deactivate();
+ ((SubActionBars) ((PageSite) site).getActionBars()).dispose();
+ }
+
+ // Free the page
+ doDestroyPage(rec.papyrusPage, rec);
+ }
+
+ /*
+ * (non-Javadoc) Method declared on IWorkbenchPart.
+ */
+ @Override
+ public void setFocus() {
+ // first set focus on the page book, in case the page
+ // doesn't properly handle setFocus
+ if (sashEditorPageBook != null) {
+ sashEditorPageBook.setFocus();
+ }
+ // then set focus on the page, if any
+ if (activeRec != null) {
+ activeRec.contentOutlinePage.setFocus();
+ }
+ }
+
+ /**
+ * Shows page contained in the given page record in this view. The page
+ * record must be one from this pagebook view.
+ * <p>
+ * The <code>PageBookView</code> implementation of this method asks the pagebook control to show the given page's control, and records that the given page is now current. Subclasses may extend.
+ * </p>
+ *
+ * @param pageRec
+ * the page record containing the page to show
+ */
+ protected void showOutlinePageRec(OutlinePageRec pageRec) {
+ // If already showing do nothing
+ if (activeRec == pageRec) {
+ return;
+ }
+ // If the page is the same, just set activeRec to pageRec
+ if (activeRec != null && pageRec != null && activeRec.contentOutlinePage == pageRec.contentOutlinePage) {
+ activeRec = pageRec;
+ return;
+ }
+
+ activeRec = pageRec;
+ Control pageControl = activeRec.contentOutlinePage.getControl();
+ if (pageControl != null && !pageControl.isDisposed()) {
+ PageSite pageSite = (PageSite) activeRec.getPageSite();
+ // Verify that the page control is not disposed
+ // If we are closing, it may have already been disposed
+ sashEditorPageBook.showPage(pageControl);
+ getSite().setActivePageSite(pageSite);
+ }
+
+ }
+
+ /**
+ * If it is possible to adapt the given object to the given type, this
+ * returns the adapter. Performs the following checks:
+ *
+ * <ol>
+ * <li>Returns <code>sourceObject</code> if it is an instance of the adapter type.</li>
+ * <li>If sourceObject implements IAdaptable, it is queried for adapters.</li>
+ * <li>If sourceObject is not an instance of PlatformObject (which would have already done so), the adapter manager is queried for adapters</li>
+ * </ol>
+ *
+ * Otherwise returns null.
+ *
+ * @param sourceObject
+ * object to adapt, or null
+ * @param adapter
+ * type to adapt to
+ * @param activatePlugins
+ * true if IAdapterManager.loadAdapter should be used (may trigger plugin activation)
+ * @return a representation of sourceObject that is assignable to the
+ * adapter type, or null if no such representation exists
+ */
+ public static Object getAdapter(Object sourceObject, Class<?> adapter, boolean activatePlugins) {
+ Assert.isNotNull(adapter);
+ if (sourceObject == null) {
+ return null;
+ }
+ if (adapter.isInstance(sourceObject)) {
+ return sourceObject;
+ }
+
+ if (sourceObject instanceof IAdaptable) {
+ IAdaptable adaptable = (IAdaptable) sourceObject;
+
+ Object result = adaptable.getAdapter(adapter);
+ if (result != null) {
+ // Sanity-check
+ Assert.isTrue(adapter.isInstance(result));
+ return result;
+ }
+ }
+
+ if (!(sourceObject instanceof PlatformObject)) {
+ Object result;
+ if (activatePlugins) {
+ result = Platform.getAdapterManager().loadAdapter(sourceObject, adapter.getName());
+ } else {
+ result = Platform.getAdapterManager().getAdapter(sourceObject, adapter);
+ }
+ if (result != null) {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * A data structure used to store the information about the editor outline page within the papyrus outline page.
+ */
+ protected static class OutlinePageRec {
+
+ public Object subActionBars;
+
+ /** papyrus page: current editor opened as nested editor */
+ public IPage papyrusPage;
+
+ /** outline page recorded for the given papyrus page */
+ public IContentOutlinePage contentOutlinePage;
+
+ /** page site for the recorded outline page */
+ public IPageSite pageSite;
+
+ /**
+ * Creates a new page record initialized to the given papyrus page and outline page.
+ *
+ * @param papyrusPage
+ * @param contentOutlinePage
+ */
+ public OutlinePageRec(IPage papyrusPage, IContentOutlinePage contentOutlinePage) {
+ this.papyrusPage = papyrusPage;
+ this.contentOutlinePage = contentOutlinePage;
+ }
+
+ /**
+ * Sets the page site
+ *
+ * @param pageSite
+ * the page site for the recorded content outline page
+ */
+ public void setPageSite(IPageSite pageSite) {
+ this.pageSite = pageSite;
+ }
+
+ /**
+ * Sets the page site
+ *
+ * @param pageSite
+ * the page site for the recorded content outline page
+ */
+ public IPageSite getPageSite() {
+ return this.pageSite;
+ }
+
+ /**
+ * Disposes of this page record by <code>null</code>ing its fields.
+ */
+ public void dispose() {
+ papyrusPage = null;
+ contentOutlinePage = null;
+ pageSite = null;
+ }
+ }
+
+ protected static class DelegatedPageSite extends PageSite {
+
+ /** Page site of the active page in the book */
+ protected PageSite activePageSite;
+
+ private NestedEditorDelegatedOutlinePage nestedEditorDelegatedOutlinePage;
+
+ /**
+ * Constructor.
+ *
+ * @param parentViewSite
+ * @param nestedEditorDelegatedOutlinePage
+ */
+ public DelegatedPageSite(IViewSite parentViewSite, NestedEditorDelegatedOutlinePage nestedEditorDelegatedOutlinePage) {
+ super(parentViewSite);
+ this.nestedEditorDelegatedOutlinePage = nestedEditorDelegatedOutlinePage;
+ }
+
+ /**
+ * Sets the active page site
+ *
+ * @param activePageSite
+ * the activePageSite to set
+ */
+ public void setActivePageSite(PageSite activePageSite) {
+ // remove the contribution of the previous active page site
+ if (this.activePageSite != null) {
+ // update the action bars for the current page
+ getActionBars().deactivate();
+ getActionBars().clearGlobalActionHandlers();
+ getActionBars().updateActionBars();
+
+ activePageSite.deactivate();
+
+ }
+ this.activePageSite = activePageSite;
+ if (this.activePageSite != null) {
+ activePageSite.activate();
+ // update the action bars for the current page
+ getActionBars().activate();
+ getActionBars().updateActionBars();
+ }
+ }
+
+ /**
+ * Returns the active page site
+ *
+ * @return the active Page Site
+ */
+ public PageSite getActivePageSite() {
+ return activePageSite;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public SubActionBars getActionBars() {
+ if (activePageSite != null) {
+ return (SubActionBars) activePageSite.getActionBars();
+ }
+ return (SubActionBars) super.getActionBars();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void deactivate() {
+ // deactivate the action bars of the current active page
+ if (activePageSite != null) {
+ activePageSite.deactivate();
+ }
+
+ // deactivate all subcontributions
+ for (OutlinePageRec rec : nestedEditorDelegatedOutlinePage.getAllPages()) {
+ IPageSite site = rec.getPageSite();
+ IActionBars bars = site.getActionBars();
+ if (bars instanceof SubActionBars) {
+ SubActionBars subActionBars = (SubActionBars) bars;
+ subActionBars.deactivate();
+ subActionBars.clearGlobalActionHandlers();
+ subActionBars.updateActionBars();
+ }
+ }
+ super.deactivate();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void activate() {
+
+ // here, we have to desactivate all contributions of all pages of this delegating service.
+ // when the page site is activated, the pagebookview has already tried to update some action bars, even if it should not
+ // so we recompute all the active contributions items here, after desactivating all the contributions.
+ for (OutlinePageRec rec : nestedEditorDelegatedOutlinePage.getAllPages()) {
+ IPageSite site = rec.getPageSite();
+ IActionBars bars = site.getActionBars();
+ if (bars instanceof SubActionBars) {
+ SubActionBars subActionBars = (SubActionBars) bars;
+ subActionBars.deactivate();
+ subActionBars.clearGlobalActionHandlers();
+ subActionBars.updateActionBars();
+ }
+ }
+ if (this.activePageSite != null) {
+ activePageSite.activate();
+ // update the action bars for the current page
+ getActionBars().activate();
+ getActionBars().updateActionBars();
+ }
+ super.activate();
+ }
+ }
+
+ protected static class MessageOutlinePage implements IContentOutlinePage, IPageBookViewPage {
+
+ private Text label;
+
+ private IPageSite site;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void createControl(Composite parent) {
+ label = new Text(parent, SWT.NONE);
+ label.setText("No outline for this editor");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void dispose() {
+ if (label != null && label.isDisposed()) {
+ label.dispose();
+ label = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Control getControl() {
+ return label;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setActionBars(IActionBars actionBars) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setFocus() {
+ if (label != null && label.isDisposed()) {
+ label.setFocus();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISelection getSelection() {
+ // nothing here
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSelection(ISelection selection) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IPageSite getSite() {
+ return site;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init(IPageSite site) throws PartInitException {
+ this.site = site;
+ }
+
+ }
+
+ private class OutlineContext {
+
+ private List<PageContext> pages = Lists.newArrayListWithCapacity(mapIPapyrusPageToOutlineRec.size());
+
+ OutlineContext() {
+ for (OutlinePageRec next : mapIPapyrusPageToOutlineRec.values()) {
+ pages.add(new PageContext(next));
+ }
+ }
+
+ public void restore() {
+ for (PageContext next : pages) {
+ next.restore();
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ private class PageContext {
+
+ final URI diagramToken;
+
+ final Object context;
+
+ PageContext(OutlinePageRec outlinePage) {
+ Object diagram = outlinePage.papyrusPage.getRawModel();
+ diagramToken = (diagram instanceof EObject) ? EcoreUtil.getURI((EObject) diagram) : null;
+
+ // Can only sensibly manage restoring the state of the page if we can find it again
+ if (diagramToken == null) {
+ context = null;
+ } else {
+ IReloadContextProvider provider = AdapterUtils.adapt(outlinePage.contentOutlinePage, IReloadContextProvider.class, null);
+ context = (provider == null) ? null : provider.createReloadContext();
+ }
+ }
+
+ void restore() {
+ if (diagramToken != null) {
+ try {
+ ModelSet modelSet = multiEditor.getServicesRegistry().getService(ModelSet.class);
+
+ Object diagram = modelSet.getEObject(diagramToken, true);
+ if (diagram != null) {
+ IPage page = sashWindowsContainer.lookupModelPage(diagram);
+ if (page != null) {
+ OutlinePageRec outlinePage = getOutlinePageRec(page, true);
+ if ((outlinePage != null) && (context != null)) {
+ // Restore it. We know it adapts if it provided the reload state in the first place
+ AdapterUtils.adapt(outlinePage.contentOutlinePage, IReloadContextProvider.class, null).restore(context);
+ }
+ }
+ }
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java new file mode 100644 index 00000000000..813d5a71fbe --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java @@ -0,0 +1,86 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.messages.Messages;
+
+/**
+ * Abstract class for String value Container
+ *
+ * @author VL222926
+ *
+ */
+public abstract class AbstractStringValueConverter implements IStringValueConverter {
+
+ protected static final String THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y = Messages.AbstractStringValueConverter_TheStringXIsNotValidToCreateY;
+
+ protected static final String THE_FEATURE_X_CANT_BE_RESOLVED = Messages.AbstractStringValueConverter_TheFeatureXCantBeResolved;
+
+ protected static final String THE_STRING_VALUE_X_CANT_BE_RESOLVED = Messages.AbstractStringValueConverter_TheStringValueXCantBeResolved;
+
+ protected static final String SOME_STRING_ARE_NOT_VALID_TO_CREATE_X = Messages.AbstractStringValueConverter_SomeStringsAreNotValidToCreateY;
+
+ protected static final String SOME_STRING_CANT_BE_RESOLVED_TO_FIND_X = Messages.AbstractStringValueConverter_SomeStringsCantBeResolvedToFindY;
+
+ protected static final String NO_X_REPRESENTED_BY_Y_HAVE_BEEN_FOUND = Messages.AbstractStringValueConverter_NoXReprensentedByYHaveBeenFound;
+
+ private ConvertedValueContainer<?> result;
+
+ /**
+ *
+ * @see org.eclipse.papyrus.infra.ui.converter.IStringValueConverter#deduceValueFromString(java.lang.Object, java.lang.String)
+ *
+ * @param type
+ * @param valueAsString
+ * @return
+ */
+ @Override
+ public final ConvertedValueContainer<?> deduceValueFromString(final Object type, final String valueAsString) {
+ result = doDeduceValueFromString(type, valueAsString);
+ if (result == null) {
+ final IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_VALUE_X_CANT_BE_RESOLVED, valueAsString));
+ result = new ConvertedValueContainer<Object>(null, status);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @return
+ * the converted value, you should call deduceValueFromString before to call this method
+ */
+ public final ConvertedValueContainer<?> getConvertedValue() {
+ if (this.result == null) {
+ throw new IllegalStateException("You should call deduceValueFromString before to call this method"); //$NON-NLS-1$
+ }
+ return this.result;
+ }
+
+ /**
+ *
+ * @param type
+ * the type of the object
+ * @param valueAsString
+ * the string to resolve
+ * @return
+ * a {@link ConvertedValueContainer} with the resolved values and a status
+ */
+ protected abstract ConvertedValueContainer<?> doDeduceValueFromString(final Object type, final String valueAsString);
+
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java new file mode 100644 index 00000000000..e4466c9470d --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java @@ -0,0 +1,75 @@ +/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+
+
+/**
+ *
+ * This class allows to store the value created for a pasted String AND a result status associated to this pasted String
+ *
+ * @param <T>
+ */
+
+public class ConvertedValueContainer<T> {
+
+ /**
+ * this field is used when the pasted value is monovalued
+ */
+ private final T value;
+
+ /**
+ * the resulting status of the parsing
+ */
+ private final IStatus status;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param realValue
+ * a monovalued Value (can be <code>null</code>)
+ * @param realListValue
+ * a collection value (can be <code>null</code>)
+ * @param status
+ * a status (can be <code>null</code>)
+ */
+ public ConvertedValueContainer(final T realValue, final IStatus status) {
+ this.value = realValue;
+ this.status = status;
+ Assert.isNotNull(status);
+ }
+
+
+ /**
+ *
+ * @return
+ * the status of the conversion
+ */
+ public final IStatus getStatus() {
+ return this.status;
+ }
+
+ /**
+ *
+ * @return
+ * the value
+ */
+ public final T getConvertedValue() {
+ return this.value;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java new file mode 100644 index 00000000000..cc42fe5acc9 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java @@ -0,0 +1,373 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.Enumerator;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EEnumLiteral;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.emf.utils.EMFContants;
+import org.eclipse.papyrus.infra.tools.util.BooleanHelper;
+import org.eclipse.papyrus.infra.tools.util.TypesConstants;
+import org.eclipse.papyrus.infra.ui.Activator;
+
+/**
+ * Value solver for EMF
+ *
+ * WARNING : incomplete implementations
+ *
+ * @author vl222926
+ *
+ */
+
+public class EMFStringValueConverter extends AbstractStringValueConverter {
+
+
+
+ /**
+ * Context used for the resolution of the string
+ */
+ private EObject resolutionContext;
+
+ /**
+ * The separator used for multivalue
+ */
+ protected final String multiValueSeparator;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param resolutionContext
+ * the context used for the resolution of the string
+ */
+ public EMFStringValueConverter(final EObject resolutionContext, final String multiValueSeparator) {
+ this.resolutionContext = resolutionContext;
+ this.multiValueSeparator = multiValueSeparator;
+ }
+
+
+ /**
+ *
+ * @return
+ * the context to use for the resolution
+ */
+ public EObject getResolutionContext() {
+ return resolutionContext;
+ }
+
+ /**
+ *
+ * @see org.eclipse.ui.services.IDisposable#dispose()
+ *
+ */
+ @Override
+ public void dispose() {
+ this.resolutionContext = null;
+ }
+
+ /**
+ *
+ * @param resolutionContext
+ * the table context
+ * @param feature
+ * the feature
+ * @param valueAsString
+ * the pasted string for this feature
+ * @return
+ * the value for the pasted string or <code>null</code> if not found
+ */
+ @Override
+ protected ConvertedValueContainer<?> doDeduceValueFromString(final Object feature, final String valueAsString) {
+ final EClassifier featureType = getFeatureType(feature);
+ if (feature instanceof EStructuralFeature) {
+ return deduceValueFromString(feature, featureType, valueAsString);
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @param feature
+ * @param featureType
+ * @param valueAsString
+ * @return
+ */
+ protected ConvertedValueContainer<?> deduceValueFromString(final Object feature, final EClassifier featureType, final String valueAsString) {
+ ConvertedValueContainer<?> realValue = null;
+ // if(feature instanceof EStructuralFeature) {
+ final int upperbound = getFeatureUpperBound(feature);
+ boolean isMany = (upperbound > 1 || upperbound == -1);
+ if (featureType instanceof EDataType) {
+ if (featureType instanceof EEnum) {
+ realValue = deduceEEnumLiteralValue((EEnum) featureType, isMany, valueAsString);
+ }
+ final String typeName = featureType.getName();
+ if (TypesConstants.STRING.equals(typeName) || EMFContants.ESTRING.equals(typeName)) {
+ realValue = deduceStringValue(isMany, valueAsString);
+ } else if (EMFContants.EBOOLEAN.equals(typeName) || TypesConstants.BOOLEAN.equals(typeName)) {
+ realValue = deduceBooleanValue(isMany, valueAsString);
+ } else if (EMFContants.EINT.equals(typeName) || TypesConstants.INTEGER.equals(typeName)) {
+ realValue = deduceIntValue(isMany, valueAsString);
+ } else if (EMFContants.EDOUBLE.equals(typeName)) {
+ realValue = deduceDoubleValue(isMany, valueAsString);
+ }
+ } else if (featureType instanceof EClass) {
+ realValue = deduceEObjectValue(getResolutionContext(), feature, (EClass) featureType, isMany, valueAsString);
+ }
+ return realValue;
+ }
+
+ protected int getFeatureUpperBound(final Object feature) {
+ return ((EStructuralFeature) feature).getUpperBound();
+ }
+
+
+
+ /**
+ *
+ * @param resolutionContext
+ * the context used for the resolution
+ * @param feature
+ * the feature
+ * @param featureType
+ * the type of the feature
+ * @param isMany
+ * <code>true</code> if the feature isMany
+ * @param valueAsString
+ * the string value to resolve
+ * @return
+ * a value container referencing the eobject represented by the string
+ * @throws StringValueSolverException
+ */
+ protected ConvertedValueContainer<?> deduceEObjectValue(EObject resolutionContext, Object feature, EClass featureType, boolean isMany, String valueAsString) {
+ if (valueAsString == null || valueAsString.equals("")) {
+ return new ConvertedValueContainer<EObject>(null, Status.OK_STATUS);
+ }
+ final IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_VALUE_X_CANT_BE_RESOLVED, valueAsString));
+ return new ConvertedValueContainer<EObject>(null, status);
+ }
+
+ /**
+ *
+ * @param feature
+ * an object representing a feature
+ * @return
+ * the type of the feature
+ */
+ protected EClassifier getFeatureType(final Object feature) {
+ final EClassifier featureType;
+ if (feature instanceof EStructuralFeature) {
+ return ((EStructuralFeature) feature).getEType();
+ } else {
+ featureType = null;
+ }
+ return featureType;
+ }
+
+ /**
+ *
+ * @param eenum
+ * the enumeration
+ * @param isMany
+ * <code>true</code> if the feature is many
+ * @param valueAsString
+ * the value to convert
+ * @return
+ * the converted value
+ */
+ protected ConvertedValueContainer<?> deduceEEnumLiteralValue(final EEnum eenum, final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ IStatus iStatus = Status.OK_STATUS;
+ final Collection<String> unresolvedValues = new ArrayList<String>();
+ if (isMany) {
+ final Collection<EEnumLiteral> values = new ArrayList<EEnumLiteral>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ final EEnumLiteral literal = eenum.getEEnumLiteral(str);
+ if (literal != null) {
+ values.add(literal);
+ } else {
+ unresolvedValues.add(str);
+ }
+ }
+ if (!unresolvedValues.isEmpty()) {
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(SOME_STRING_ARE_NOT_VALID_TO_CREATE_X, EMFContants.EENUM_LITERAL), unresolvedValues);
+ }
+ returnedValue = new MultiConvertedValueContainer<EEnumLiteral>(values, iStatus);
+ } else {
+ final EEnumLiteral literal = eenum.getEEnumLiteral(valueAsString);
+ if (literal != null) {
+ // returnedValue = new ConvertedValueContainer<EEnumLiteral>(literal, iStatus);
+ // fix a bug on enumerator
+ returnedValue = new ConvertedValueContainer<Enumerator>(literal.getInstance(), iStatus);
+ } else {
+ unresolvedValues.add(valueAsString);
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y, valueAsString, EMFContants.EENUM_LITERAL), unresolvedValues);
+ returnedValue = new ConvertedValueContainer<Boolean>(null, iStatus);
+ }
+ }
+ return returnedValue;
+ }
+
+ /**
+ *
+ * @param isMany
+ * <code>true</code> if the feature isMany
+ * @param valueAsString
+ * the value to parse
+ * @return
+ * the result of the parsing
+ */
+ protected ConvertedValueContainer<?> deduceBooleanValue(final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ IStatus iStatus = Status.OK_STATUS;
+ final Collection<String> unresolvedValues = new ArrayList<String>();
+ if (isMany) {
+ final Collection<Boolean> values = new ArrayList<Boolean>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ if (BooleanHelper.isBoolean(str)) {
+ values.add(Boolean.valueOf(valueAsString));
+ } else {
+ unresolvedValues.add(str);
+ }
+ }
+ if (!unresolvedValues.isEmpty()) {
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(SOME_STRING_ARE_NOT_VALID_TO_CREATE_X, TypesConstants.BOOLEAN), unresolvedValues);
+ }
+ returnedValue = new MultiConvertedValueContainer<Boolean>(values, iStatus);
+ } else {
+ if (BooleanHelper.isBoolean(valueAsString)) {
+ returnedValue = new ConvertedValueContainer<Boolean>(Boolean.valueOf(valueAsString), iStatus);
+ } else {
+ unresolvedValues.add(valueAsString);
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y, valueAsString, TypesConstants.BOOLEAN), unresolvedValues);
+ returnedValue = new ConvertedValueContainer<Boolean>(null, iStatus);
+ }
+ }
+ return returnedValue;
+ }
+
+ /**
+ *
+ * @param isMany
+ * <code>true</code> if the feature isMany
+ * @param valueAsString
+ * the value to parse
+ * @return
+ * the result of the parsing
+ */
+ protected ConvertedValueContainer<?> deduceDoubleValue(final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ IStatus iStatus = Status.OK_STATUS;
+ final Collection<String> unresolvedValues = new ArrayList<String>();
+ if (isMany) {
+ final Collection<Double> values = new ArrayList<Double>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ final Double value = Double.valueOf(str);
+ if (value != null) {
+ values.add(value);
+ } else {
+ unresolvedValues.add(str);
+ }
+ }
+ if (!unresolvedValues.isEmpty()) {
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(SOME_STRING_ARE_NOT_VALID_TO_CREATE_X, TypesConstants.DOUBLE), unresolvedValues);
+ }
+ returnedValue = new MultiConvertedValueContainer<Double>(values, iStatus);
+ } else {
+ try {
+ returnedValue = new ConvertedValueContainer<Double>(Double.valueOf(valueAsString), iStatus);
+ } catch (final NumberFormatException e) {
+ unresolvedValues.add(valueAsString);
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y, valueAsString, TypesConstants.DOUBLE), unresolvedValues);
+ returnedValue = new ConvertedValueContainer<Boolean>(null, iStatus);
+ }
+ }
+ return returnedValue;
+ }
+
+ /**
+ *
+ * @param isMany
+ * <code>true</code> if the feature isMany
+ * @param valueAsString
+ * the value to parse
+ * @return
+ * the result of the parsing
+ */
+ protected ConvertedValueContainer<?> deduceIntValue(final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ IStatus iStatus = Status.OK_STATUS;
+ final Collection<String> unresolvedValues = new ArrayList<String>();
+ if (isMany) {
+ final Collection<Integer> values = new ArrayList<Integer>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ try {
+ values.add(Integer.valueOf(str));
+ } catch (final NumberFormatException e) {
+ unresolvedValues.add(str);
+ }
+ }
+ if (!unresolvedValues.isEmpty()) {
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(SOME_STRING_ARE_NOT_VALID_TO_CREATE_X, TypesConstants.INTEGER), unresolvedValues);
+ }
+ returnedValue = new MultiConvertedValueContainer<Integer>(values, iStatus);
+ } else {
+ try {
+ returnedValue = new ConvertedValueContainer<Integer>(Integer.valueOf(valueAsString), iStatus);
+ } catch (final NumberFormatException e) {
+ unresolvedValues.add(valueAsString);
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y, valueAsString, TypesConstants.INTEGER), unresolvedValues);
+ returnedValue = new ConvertedValueContainer<Boolean>(null, iStatus);
+ }
+ }
+ return returnedValue;
+ }
+
+
+ /**
+ *
+ * @param isMany
+ * <code>true</code> if the feature is many
+ * @param valueAsString
+ * the value as string
+ * @return
+ * the value container with the real value(s)
+ */
+ protected ConvertedValueContainer<?> deduceStringValue(final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ final IStatus iStatus = Status.OK_STATUS;
+ if (isMany) {
+ final Collection<String> values = new ArrayList<String>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ values.add(str);
+ }
+ returnedValue = new MultiConvertedValueContainer<String>(values, iStatus);
+ } else {
+ returnedValue = new ConvertedValueContainer<String>(valueAsString, iStatus);
+ }
+ return returnedValue;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java new file mode 100644 index 00000000000..242c4acc523 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java @@ -0,0 +1,36 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * Common interface for string converter
+ *
+ * @author VL222926
+ *
+ */
+public interface IStringValueConverter extends IDisposable {
+
+ /**
+ *
+ * @param type
+ * an object representing the type of the in which we want to convert the string
+ * @param valueAsString
+ * the value represented by a string
+ * @return
+ * a {@link ConvertedValueContainer}
+ */
+ public ConvertedValueContainer<?> deduceValueFromString(final Object type, final String valueAsString);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java new file mode 100644 index 00000000000..13aacbf3396 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java @@ -0,0 +1,39 @@ +/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ *
+ * This class allows to store the value created for a pasted String AND a result status associated to this pasted String
+ *
+ * @param <T>
+ */
+public class MultiConvertedValueContainer<T> extends ConvertedValueContainer<Collection<T>> {
+
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param realValue
+ * @param status
+ */
+ public MultiConvertedValueContainer(final Collection<T> realValue, final IStatus status) {
+ super(realValue, status);
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java new file mode 100644 index 00000000000..8a41a9edaa3 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java @@ -0,0 +1,60 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.Status;
+
+/**
+ * This status is used y the String Value solvers
+ *
+ * @author vl222926
+ *
+ */
+public class StringValueConverterStatus extends Status {
+
+ /**
+ * the list of the uresolved strings
+ */
+ private Collection<String> unresolvedString;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param severity
+ * the severity of the status
+ * @param pluginId
+ * the plugin id providing this status
+ * @param message
+ * the message for this status
+ * @param unresolvedString
+ * the list of the unresolved string
+ */
+ public StringValueConverterStatus(int severity, String pluginId, String message, Collection<String> unresolvedString) {
+ super(severity, pluginId, message);
+ this.unresolvedString = unresolvedString;
+ }
+
+
+ /**
+ *
+ * @return
+ * the list of the unresolved string
+ */
+ public final Collection<String> getUnresolvedString() {
+ return unresolvedString;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java new file mode 100644 index 00000000000..a31e0562b90 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation, Christian W. Damus, and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Christian W. Damus - adapted from GEF for bug 469188 + *******************************************************************************/ +package org.eclipse.papyrus.infra.ui.dnd; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.TransferData; + +/** + * A local transfer carrying a single object being dragged. Subclasses should maintain a + * single instance of their Transfer and provide a static method to obtain that + * instance. + */ +public abstract class PapyrusTransfer<T> extends ByteArrayTransfer { + + private final Class<? extends T> objectType; + private final String typeName; + private final int typeID; + + private Reference<T> object; + private long startTime; + + protected PapyrusTransfer(Class<? extends T> objectType) { + super(); + + this.objectType = objectType; + + typeName = String.format("%s:%x:%x", getClass().getSimpleName(), hashCode(), System.currentTimeMillis()); + typeID = registerType(typeName); + } + + @Override + public final int hashCode() { + return System.identityHashCode(this); + } + + /** + * The data object is not converted to bytes. It is held onto in a field. + * Instead, a checksum is written out to prevent unwanted drags across + * mulitple running copies of Eclipse. + * + * @see org.eclipse.swt.dnd.Transfer#javaToNative(Object, TransferData) + */ + @Override + public void javaToNative(Object object, TransferData transferData) { + setObject(objectType.cast(object)); + startTime = System.currentTimeMillis(); + if (transferData != null) + super.javaToNative(String.valueOf(startTime).getBytes(), + transferData); + } + + /** + * The data object is not converted to bytes. It is held onto in a field. + * Instead, a checksum is written out to prevent unwanted drags across + * mulitple running. copies of Eclipse. + * + * @see org.eclipse.swt.dnd.Transfer#nativeToJava(TransferData) + */ + @Override + public Object nativeToJava(TransferData transferData) { + byte bytes[] = (byte[]) super.nativeToJava(transferData); + if (bytes == null) { + return null; + } + long startTime = Long.parseLong(new String(bytes)); + return (this.startTime == startTime) ? getObject() : null; + } + + /** + * Obtains the object being dragged. + */ + public T getObject() { + return (object == null) ? null : objectType.cast(object.get()); + } + + /** + * Sets the object being dragged. + */ + public void setObject(T object) { + this.object = new WeakReference<>(object); + } + + @Override + protected int[] getTypeIds() { + return new int[] { typeID }; + } + + @Override + protected String[] getTypeNames() { + return new String[] { typeName }; + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java new file mode 100644 index 00000000000..e67c81034fb --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java @@ -0,0 +1,68 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelManager;
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+
+/**
+ * A service factory to create the {@link ISashWindowsContentProvider} service.
+ * This service depends on {@link DiSashModelMngrServiceFactory}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class ContentProviderServiceFactory implements IServiceFactory {
+
+ /**
+ * The sashModelMangr.
+ */
+ private DiSashModelManager sashModelMngr;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ // Get required services
+ sashModelMngr = servicesRegistry.getService(DiSashModelManager.class);
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance()
+ *
+ * @return
+ * @throws ServiceException
+ */
+ @Override
+ public Object createServiceInstance() throws ServiceException {
+ return sashModelMngr.getISashWindowsContentProvider();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java new file mode 100644 index 00000000000..983e28735ec --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java @@ -0,0 +1,1244 @@ +/*****************************************************************************
+ * Copyright (c) 2008, 2016 LIFL, CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - manage models by URI, not IFile (CDO)
+ * Christian W. Damus (CEA) - bug 410346
+ * Christian W. Damus (CEA) - bug 431953 (pre-requisite refactoring of ModelSet service start-up)
+ * Christian W. Damus (CEA) - bug 437217
+ * Christian W. Damus - bugs 469464, 469188, 485220
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.editor;
+
+import static org.eclipse.papyrus.infra.core.Activator.log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.ui.URIEditorInput;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+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.IItemLabelProvider;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.core.language.ILanguageChangeListener;
+import org.eclipse.papyrus.infra.core.language.ILanguageService;
+import org.eclipse.papyrus.infra.core.language.LanguageChangeEvent;
+import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IContentChangedListener;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelManager;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.AbstractMultiPageSashEditor;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
+import org.eclipse.papyrus.infra.core.services.ExtensionServicesRegistry;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServiceMultiException;
+import org.eclipse.papyrus.infra.core.services.ServiceStartKind;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.contentoutline.ContentOutlineRegistry;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor.DirtyPolicy;
+import org.eclipse.papyrus.infra.ui.editor.reload.EditorReloadEvent;
+import org.eclipse.papyrus.infra.ui.editor.reload.IEditorReloadListener;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.DoSaveEvent;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.IEditorInputChangedListener;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ISaveAndDirtyService;
+import org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor.ActionBarContributorRegistry;
+import org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor.CoreComposedActionBarContributor;
+import org.eclipse.papyrus.infra.ui.services.EditorLifecycleManager;
+import org.eclipse.papyrus.infra.ui.services.internal.EditorLifecycleManagerImpl;
+import org.eclipse.papyrus.infra.ui.services.internal.InternalEditorLifecycleManager;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IGotoMarker;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.progress.UIJob;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+import org.eclipse.ui.views.properties.IPropertySheetPage;
+import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Multi diagram editor allowing to plug various kind of editors. Editors are
+ * registered with the help of the Eclipse extension mechanism. This
+ * implementation allows to register editors and context separately. An editor
+ * should specify which context it need to run. This multi diagram editor allows
+ * to show editor side by side in one or more sash windows.
+ *
+ * The real implementation for the generic type T of SashMultiPageEditorPart is
+ * actually di2.Diagram
+ *
+ * @author cedric dumoulin
+ * @author <a href="mailto:jerome.benois@obeo.fr">Jerome Benois</a>
+ * @author <a href="mailto:thomas.szadel@atosorigin.com">Thomas Szadel</a>
+ * Refactoring.
+ *
+ * TODO : remove GMF dependency !
+ */
+public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implements IMultiDiagramEditor, ITabbedPropertySheetPageContributor, IGotoMarker, IEditingDomainProvider {
+
+ /** ContentOutline registry */
+ private ContentOutlineRegistry contentOutlineRegistry;
+
+ /** Services registry. Used to get registered services */
+ private ServicesRegistry servicesRegistry;
+
+ /**
+ * ActionBarContributor Registry. Allows to get an ActionBar by its Id. The
+ * registry is initialized from the Eclipse extension mechanism.
+ */
+ private ActionBarContributorRegistry actionBarContributorRegistry;
+
+ /** SashModelMngr to add pages */
+ protected DiSashModelManager sashModelMngr;
+
+ /**
+ * Service used to maintain the dirty state and to perform save and saveAs.
+ */
+ protected ISaveAndDirtyService saveAndDirtyService;
+
+ private final List<IPropertySheetPage> propertiesPages = new LinkedList<IPropertySheetPage>();
+
+ private final List<Runnable> closeActions = new ArrayList<>();
+
+ /**
+ * Listener on {@link ISaveAndDirtyService#addInputChangedListener(IEditorInputChangedListener)}
+ */
+ private static class EditorInputChangedListener implements IEditorInputChangedListener {
+
+ private CoreMultiDiagramEditor editor;
+
+ public EditorInputChangedListener(CoreMultiDiagramEditor editor) {
+ this.editor = editor;
+ }
+
+ /**
+ * This method is called when the editor input is changed from the
+ * ISaveAndDirtyService.
+ *
+ * @see org.eclipse.papyrus.infra.ui.lifecycleevents.IEditorInputChangedListener#editorInputChanged(org.eclipse.ui.part.FileEditorInput)
+ *
+ * @param fileEditorInput
+ */
+ @Override
+ public void editorInputChanged(FileEditorInput fileEditorInput) {
+ // Change the editor input.
+ editor.setInputWithNotify(fileEditorInput);
+ editor.setPartName(fileEditorInput.getName());
+ }
+
+ /**
+ * The isDirty flag has changed, reflect its new value
+ *
+ * @see org.eclipse.papyrus.infra.ui.lifecycleevents.IEditorInputChangedListener#isDirtyChanged()
+ *
+ */
+ @Override
+ public void isDirtyChanged() {
+
+ // Run it in async way.
+ editor.getSite().getShell().getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ // editor can be null if this object has been finalized, but
+ // still queued in the asyncExec queue.
+ // This can happen if the editor is disposed, but some run still in
+ // the exec queue.
+ // When the method is executed asynchronously, the object is already finalized, and so
+ // editor is null.
+ if (editor == null) {
+ return;
+ }
+ editor.firePropertyChange(IEditorPart.PROP_DIRTY);
+ }
+ });
+ }
+
+ public void dispose() {
+ this.editor = null;
+ }
+ }
+
+ protected EditorInputChangedListener editorInputChangedListener;
+
+ private TransactionalEditingDomain transactionalEditingDomain;
+
+ /**
+ * Object managing models lifeCycle.
+ */
+ protected ModelSet resourceSet;
+
+ /**
+ * Cached event that can be reused.
+ */
+ protected DoSaveEvent lifeCycleEvent;
+
+ private class ContentChangedListener implements IContentChangedListener {
+
+ /**
+ * Called when the content is changed. RefreshTabs.
+ */
+ @Override
+ public void contentChanged(ContentEvent event) {
+ scheduleRefresh();
+ }
+ }
+
+ /**
+ * A listener on model change events.
+ */
+ private ContentChangedListener contentChangedListener;
+
+ /**
+ * Undo context used to have the same undo context in all Papyrus related
+ * views and editors. TODO : move away, use a version independent of GMF,
+ * add a listener that will add the context to all commands modifying
+ * attached Resources (==> linked to ModelSet ?)
+ */
+ private IUndoContext undoContext;
+
+ /**
+ * Editor reload listeners.
+ */
+ private CopyOnWriteArrayList<IEditorReloadListener> reloadListeners = new CopyOnWriteArrayList<IEditorReloadListener>();
+
+ /**
+ * A pending reload operation (awaiting next activation of the editor).
+ */
+ private final AtomicReference<DeferredReload> pendingReload = new AtomicReference<DeferredReload>();
+
+ public CoreMultiDiagramEditor() {
+ super();
+
+ addSelfReloadListener();
+ }
+
+ /**
+ * Get the contentOutlineRegistry. Create it if needed.
+ *
+ * @return the contentOutlineRegistry
+ */
+ protected ContentOutlineRegistry getContentOutlineRegistry() {
+ if (contentOutlineRegistry == null) {
+ createContentOutlineRegistry();
+ }
+
+ return contentOutlineRegistry;
+ }
+
+ /**
+ * Create the contentOutlineRegistry.
+ */
+ private void createContentOutlineRegistry() {
+ contentOutlineRegistry = new ContentOutlineRegistry(this, Activator.PLUGIN_ID);
+ }
+
+ /**
+ * Returns the service registry associated to the editor.
+ *
+ * @return the servicesRegistry The registry.
+ */
+ @Override
+ public ServicesRegistry getServicesRegistry() {
+ if (servicesRegistry == null) {
+ servicesRegistry = createServicesRegistry();
+ }
+ return servicesRegistry;
+ }
+
+ /**
+ * Create the ServicesRegistry.
+ *
+ * @return
+ */
+ private ServicesRegistry createServicesRegistry() {
+ // Create Services Registry
+ try {
+ ServicesRegistry servicesRegistry = new ExtensionServicesRegistry(org.eclipse.papyrus.infra.core.Activator.PLUGIN_ID);
+ // servicesRegistry.startRegistry();
+ return servicesRegistry;
+ } catch (ServiceException e) {
+ // Show log and error
+ log.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+ /**
+ * Do nothing as we create the provider before any calls to this method.
+ * Should not be called by subclasses.
+ *
+ * @see org.eclipse.papyrus.infra.core.sasheditor.editor.AbstractMultiPageSashEditor#createPageProvider()
+ */
+ @Override
+ protected ISashWindowsContentProvider createPageProvider() {
+ throw new UnsupportedOperationException("Not implemented. Should not be called as the ContentProvider is already initialized.");
+ }
+
+ /**
+ * Create the pageContentProvider.
+ *
+ * Removed since 0.10.0
+ *
+ * @param pageFactory
+ * @param diResource
+ * Resource used to load/save the SashModel.
+ *
+ *
+ */
+ // protected ISashWindowsContentProvider createPageProvider(IPageModelFactory pageFactory, Resource diResource, TransactionalEditingDomain editingDomain) {
+ //
+ // sashModelMngr = new TransactionalDiSashModelMngr(pageFactory, diResource, editingDomain);
+ //
+ // ISashWindowsContentProvider pageProvider = sashModelMngr.getISashWindowsContentProvider();
+ //
+ // return pageProvider;
+ // }
+
+ /**
+ * Get The {@link IPageMngr} used to add, open, remove or close a diagram in
+ * the SashWindow. This method is available as soon as the {@link CoreMultiDiagramEditor#init(IEditorSite, IEditorInput)} method is
+ * called.
+ *
+ * @return
+ */
+ protected IPageManager getIPageManager() throws IllegalStateException {
+ try {
+ return sashModelMngr.getIPageManager();
+ } catch (Exception e) {
+ throw new IllegalStateException("Method should be called after CoreMultiDiagramEditor#init(IEditorSite, IEditorInput) is called");
+ }
+ }
+
+ /**
+ * Get the ActionBarContributorRegistry. Creates it if necessary.
+ *
+ * @return
+ */
+ protected ActionBarContributorRegistry getActionBarContributorRegistry() {
+ if (actionBarContributorRegistry != null) {
+ return actionBarContributorRegistry;
+ }
+
+ // Try to got it from CoreComposedActionBarContributor
+ // Get it from the contributor.
+ IEditorActionBarContributor contributor = getEditorSite().getActionBarContributor();
+ if (contributor instanceof CoreComposedActionBarContributor) {
+ log.debug(getClass().getSimpleName() + " - ActionBarContributorRegistry loaded from CoreComposedActionBarContributor.");
+ return ((CoreComposedActionBarContributor) contributor).getActionBarContributorRegistry();
+ } else {
+ // Create a registry.
+ log.debug(getClass().getSimpleName() + " - create an ActionBarContributorRegistry.");
+ return createActionBarContributorRegistry();
+ }
+
+ }
+
+ /**
+ * Create the ActionBarContributorRegistry.
+ *
+ * @return
+ */
+ private ActionBarContributorRegistry createActionBarContributorRegistry() {
+ return new ActionBarContributorRegistry(Activator.PLUGIN_ID);
+ }
+
+ /**
+ *
+ *
+ * @param adapter
+ *
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Object getAdapter(Class adapter) {
+
+ if (ServicesRegistry.class == adapter) {
+ return getServicesRegistry();
+ }
+
+ if (IPageManager.class == adapter) {
+ return getIPageManager();
+ }
+
+ if (IPropertySheetPage.class == adapter) {
+ // Do not test if tabbedPropertySheetPage is null before calling new
+ // this is managed by Eclipse which only call current method when
+ // necessary
+ return getPropertySheetPage();
+ }
+
+ // Add a viewer
+ if (IContentOutlinePage.class == adapter) {
+ try {
+ ContentOutlineRegistry outlineRegistry = getContentOutlineRegistry();
+ if (outlineRegistry == null) {
+ return null;
+ }
+ IContentOutlinePage contentOutline = outlineRegistry.getContentOutline();
+ if (contentOutline != null) {
+ return contentOutline;
+ }
+ } catch (BackboneException e) {
+ // Ignore: There is not registered outline.
+ }
+ }
+
+ if (EditingDomain.class == adapter || TransactionalEditingDomain.class == adapter) {
+ return transactionalEditingDomain;
+ }
+
+ /*
+ * Return context used for undo/redo. All papyrus views should use this
+ * context. The prefer way to get this is to use undoContext =
+ * servicesRegistry.getService(IUndoContext.class);
+ */
+ if (IUndoContext.class == adapter) {
+ return undoContext;
+ }
+
+ // EMF requirements
+ if (IEditingDomainProvider.class == adapter) {
+ return this;
+ }
+
+ if (adapter == ISelection.class) {
+ return getSite().getSelectionProvider().getSelection();
+ }
+
+ if (adapter == IReloadableEditor.class) {
+ return createReloadAdapter();
+ }
+
+ return super.getAdapter(adapter);
+ }
+
+ /**
+ * Init the editor.
+ */
+ @Override
+ public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+ // Init super
+ super.init(site, input);
+
+ // Set editor name
+ setPartName(input.getName());
+
+ initContents();
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ super.createPartControl(parent);
+
+ // Fire the PreDisplay event synchronously, so that listeners can continue
+ // setting up the UI before the contents are actually rendered fully
+ getLifecycleManager().firePreDisplay(this);
+
+ // Fire the PostDisplay event asynchronously, to leave time to the Eclipse
+ // framework to actually display the contents of the editor
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ // Because we are asynchronous, the editor may already have been disposed
+ // (Especially in the case of tests running in the UI Thread)
+ if (servicesRegistry == null) {
+ return;
+ }
+ getLifecycleManager().firePostDisplay(CoreMultiDiagramEditor.this);
+ }
+ });
+
+ }
+
+ protected void loadModelAndServices() throws PartInitException {
+ // Create ServicesRegistry and register services
+ servicesRegistry = createServicesRegistry();
+
+ // Add itself as a service
+ servicesRegistry.add(IMultiDiagramEditor.class, 1, this);
+
+ // Create lifeCycle event provider and the event that is used when the editor fire a save event.
+ // lifeCycleEventsProvider = new LifeCycleEventsProvider();
+ // lifeCycleEvent = new DoSaveEvent(servicesRegistry, this);
+ // servicesRegistry.add(ILifeCycleEventsProvider.class, 1, lifeCycleEventsProvider);
+
+ // register services
+ servicesRegistry.add(ActionBarContributorRegistry.class, 1, getActionBarContributorRegistry());
+ // servicesRegistry.add(TransactionalEditingDomain.class, 1, transactionalEditingDomain);
+ // servicesRegistry.add(DiResourceSet.class, 1, resourceSet);
+
+ // Create and initalize editor icons service
+ // PageIconsRegistry pageIconsRegistry = new PageIconsRegistry();
+ // PluggableEditorFactoryReader editorReader = new PluggableEditorFactoryReader(Activator.PLUGIN_ID);
+ // editorReader.populate(pageIconsRegistry);
+ // servicesRegistry.add(IPageIconsRegistry.class, 1, pageIconsRegistry);
+
+
+ // Create PageModelRegistry requested by content provider.
+ // Also populate it from extensions.
+ // PageModelFactoryRegistry pageModelRegistry = new PageModelFactoryRegistry();
+ // editorReader.populate(pageModelRegistry, servicesRegistry);
+
+ // TODO : create appropriate Resource for the contentProvider, and pass it here.
+ // This will allow to remove the old sash stuff.
+ // setContentProvider(createPageProvider(pageModelRegistry, resourceSet.getDiResource(), transactionalEditingDomain));
+ // servicesRegistry.add(ISashWindowsContentProvider.class, 1, getContentProvider());
+ // servicesRegistry.add(IPageMngr.class, 1, getIPageMngr());
+
+ // register a basic label provider
+ // adapter factory used by EMF objects
+ AdapterFactory factory = null;
+ try {
+ EditingDomain domain = ServiceUtils.getInstance().getTransactionalEditingDomain(servicesRegistry);
+ if (domain instanceof AdapterFactoryEditingDomain) {
+ // Use the adapter factory already provided by this editing domain
+ factory = ((AdapterFactoryEditingDomain) domain).getAdapterFactory();
+ }
+ } catch (ServiceException e) {
+ // OK, there's no editing domain. That's fine
+ }
+
+ if (factory == null) {
+ // Must create a new adapter factory
+ factory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
+ }
+
+ /** label provider for EMF objects */
+ ILabelProvider labelProvider = new AdapterFactoryLabelProvider(factory) {
+
+ /**
+ * This implements {@link ILabelProvider}.getText by forwarding it
+ * to an object that implements {@link IItemLabelProvider#getText
+ * IItemLabelProvider.getText}
+ */
+ @Override
+ public String getText(Object object) {
+ // Get the adapter from the factory.
+ //
+ IItemLabelProvider itemLabelProvider = (IItemLabelProvider) adapterFactory.adapt(object, IItemLabelProvider.class);
+ if (object instanceof EObject) {
+ if (((EObject) object).eIsProxy()) {
+ return "Proxy - " + object;
+ }
+ }
+ return itemLabelProvider != null ? itemLabelProvider.getText(object) : object == null ? "" : object.toString();
+ }
+ };
+ servicesRegistry.add(ILabelProvider.class, 1, labelProvider);
+
+ EditorLifecycleManager lifecycleManager = new EditorLifecycleManagerImpl();
+ servicesRegistry.add(EditorLifecycleManager.class, 1, lifecycleManager, ServiceStartKind.LAZY);
+
+ // Start servicesRegistry
+ URI uri;
+ IEditorInput input = getEditorInput();
+ if (input instanceof IFileEditorInput) {
+ uri = URI.createPlatformResourceURI(((IFileEditorInput) input).getFile().getFullPath().toString(), true);
+ } else if (input instanceof URIEditorInput) {
+ uri = ((URIEditorInput) input).getURI();
+ } else {
+ uri = URI.createURI(((IURIEditorInput) input).getURI().toString());
+ }
+
+ try {
+ // Start the ModelSet first, and load if from the specified File.
+ // Also start me so that I may be retrieved from the registry by other services
+ List<Class<?>> servicesToStart = new ArrayList<Class<?>>(1);
+ servicesToStart.add(ModelSet.class);
+ servicesToStart.add(IMultiDiagramEditor.class);
+
+ servicesRegistry.startServicesByClassKeys(servicesToStart);
+
+ resourceSet = servicesRegistry.getService(ModelSet.class);
+ resourceSet.loadModels(uri);
+
+ // start remaining services
+ servicesRegistry.startRegistry();
+ } catch (ModelMultiException e) {
+ try {
+ // with the ModelMultiException it is still possible to open the
+ // editors that's why the service registry is still started
+ servicesRegistry.startRegistry();
+ warnUser(e);
+ } catch (ServiceException e1) {
+ log.error(e);
+ // throw new PartInitException("could not initialize services", e); //$NON-NLS-1$
+ }
+ } catch (ServiceException e) {
+ log.error(e);
+ // throw new PartInitException("could not initialize services", e);
+ }
+
+
+ // Get required services
+
+ try {
+ transactionalEditingDomain = servicesRegistry.getService(TransactionalEditingDomain.class);
+ sashModelMngr = servicesRegistry.getService(DiSashModelManager.class);
+
+ saveAndDirtyService = servicesRegistry.getService(ISaveAndDirtyService.class);
+ undoContext = servicesRegistry.getService(IUndoContext.class);
+
+ servicesRegistry.getService(ILanguageService.class).addLanguageChangeListener(createLanguageChangeListener());
+ } catch (ServiceException e) {
+ log.error("A required service is missing.", e);
+ // if one of the services above fail to start, the editor can't run
+ // => stop
+ throw new PartInitException("could not initialize services", e);
+ }
+
+
+ // Listen on input changed from the ISaveAndDirtyService
+ editorInputChangedListener = new EditorInputChangedListener(this);
+ saveAndDirtyService.addInputChangedListener(editorInputChangedListener);
+ getLifecycleManager().firePostInit(this);
+ }
+
+ private ILanguageChangeListener createLanguageChangeListener() {
+ return new ILanguageChangeListener() {
+
+ @Override
+ public void languagesChanged(LanguageChangeEvent event) {
+ // Re-load the editor if languages changed, because new ModelSet configurations may be required
+ if (event.getType() == LanguageChangeEvent.ADDED) {
+ new UIJob(getSite().getShell().getDisplay(), NLS.bind("Reload editor {0}", getTitle())) {
+
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ IStatus result = Status.OK_STATUS;
+ monitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
+
+ try {
+ ISashWindowsContainer container = getISashWindowsContainer();
+ if ((container != null) && !container.isDisposed()) {
+ IReloadableEditor.ReloadReason reason = IReloadableEditor.ReloadReason.RESOURCES_CHANGED;
+
+ DirtyPolicy dirtyPolicy = DirtyPolicy.getDefault();
+ try {
+ IReloadableEditor.Adapter.getAdapter(CoreMultiDiagramEditor.this).reloadEditor(resourceSet.getResources(), reason, dirtyPolicy);
+ } catch (CoreException e) {
+ result = e.getStatus();
+ }
+ }
+ } finally {
+ monitor.done();
+ }
+
+ return result;
+ }
+ }.schedule();
+ }
+ }
+ };
+ }
+
+ private InternalEditorLifecycleManager getLifecycleManager() {
+ // I've been disposed
+ if (servicesRegistry == null) {
+ return null;
+ }
+ try {
+ return (InternalEditorLifecycleManager) servicesRegistry.getService(EditorLifecycleManager.class);
+ } catch (ServiceException ex) {
+ Activator.log.error(ex);
+ }
+ return null;
+ }
+
+ protected void loadNestedEditors() throws PartInitException {
+ ISashWindowsContentProvider contentProvider = null;
+ try {
+ contentProvider = servicesRegistry.getService(ISashWindowsContentProvider.class);
+ } catch (ServiceException ex) {
+ log.error("A required service is missing.", ex);
+ // if one of the services above fail to start, the editor can't run
+ // => stop
+ throw new PartInitException("could not initialize services", ex);
+ }
+
+ // Set the content provider providing editors.
+ setContentProvider(contentProvider);
+
+ // Listen on contentProvider changes
+ if (contentChangedListener == null) {
+ contentChangedListener = new ContentChangedListener();
+ }
+ sashModelMngr.getSashModelContentChangedProvider().addListener(contentChangedListener);
+
+ IEditorInput input = getEditorInput();
+
+ if (input instanceof IPapyrusPageInput) {
+ IPapyrusPageInput papyrusPageInput = (IPapyrusPageInput) input;
+ final IPageManager pageManager = getIPageManager();
+
+ if (papyrusPageInput.closeOtherPages()) {
+ pageManager.closeAllOpenedPages();
+ }
+
+ for (URI pageIdentifierURI : papyrusPageInput.getPages()) {
+ final EObject pageIdentifier = resourceSet.getEObject(pageIdentifierURI, true);
+ if (!pageManager.allPages().contains(pageIdentifier)) {
+ Activator.log.warn("The object " + pageIdentifier + " does not reference an existing page");
+ continue;
+ }
+
+ if (pageManager.isOpen(pageIdentifier)) {
+ pageManager.selectPage(pageIdentifier);
+ } else {
+ pageManager.openPage(pageIdentifier);
+ }
+ }
+ }
+ }
+
+ protected void warnUser(ModelMultiException e) {
+ Activator.log.error(e);
+ MessageDialog.openError(getSite().getShell(), "Error", String.format("Your model is corrupted, invalid links have been found :\n" + "%s" + "It is recommended to fix it before editing it", e.getMessage()));
+ }
+
+ /**
+ * Activate this editor. Called after the SWT.control is created.
+ */
+ @Override
+ protected void activate() {
+ super.activate();
+
+ initFolderTabMenus();
+
+ try {
+ // Register ISashWindowsContainer as service
+ // Should be done only once the container is ready.
+ getServicesRegistry().add(ISashWindowsContainer.class, 1, getISashWindowsContainer());
+ getServicesRegistry().startServicesByClassKeys(ISashWindowsContainer.class);
+ // Let the IPageMngr use the ISashWindowsContainer to discover current folder
+ // This should be done after SashWindowContainer initialization.
+ // DiSashModelManager sashModelManager = getServicesRegistry().getService(DiSashModelManager.class);
+ sashModelMngr.setCurrentFolderAndPageMngr(getISashWindowsContainer());
+
+ } catch (ServiceException e) {
+ log.error(e);
+ }
+
+ }
+
+ /**
+ * Init the contextual menu shown in the folder tabs. This popup menu is
+ * contributed by the help of Eclipse extensions, using the Commands
+ * framework. I.e, to add a menu item, create a menu, a command and an
+ * handler in the extension.
+ */
+ protected void initFolderTabMenus() {
+ ISashWindowsContainer container = getISashWindowsContainer();
+
+ // TODO : use a constant
+ MenuManager menuManager = new MenuManager("tabmenu");
+ menuManager.add(new Separator("tabcommands"));
+ menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ container.setFolderTabMenuManager(menuManager);
+
+ // TODO : use a constant
+ getSite().registerContextMenu("org.eclipse.papyrus.infra.core.editor.ui.tabmenu", menuManager, getSite().getSelectionProvider());
+
+ }
+
+ /**
+ * Overrides getPropertySheetPage.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor#getPropertySheetPage()
+ */
+ public IPropertySheetPage getPropertySheetPage() {
+ IPropertySheetPage propertiesPage = new MultiDiagramPropertySheetPage(this);
+ propertiesPages.add(propertiesPage);
+ return propertiesPage;
+ }
+
+ @Override
+ public void dispose() {
+ for (IPropertySheetPage propertiesPage : this.propertiesPages) {
+ propertiesPage.dispose();
+ }
+ propertiesPages.clear();
+
+ // Forget the outline page(s)
+ contentOutlineRegistry = null;
+
+ super.dispose();
+ }
+
+ private IReloadableEditor createReloadAdapter() {
+
+ return new IReloadableEditor() {
+
+ @Override
+ public void reloadEditor(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) throws CoreException {
+ // Attempt to re-load, later
+ pendingReload.set(new DeferredReload(triggeringResources, reason, dirtyPolicy));
+
+ // If I am already active, then do it now. Or, if we're not going to ask the user about it, also do it now
+ IWorkbenchPage page = getSite().getPage();
+ if ((page.getActiveEditor() == CoreMultiDiagramEditor.this) || (dirtyPolicy != DirtyPolicy.PROMPT_TO_SAVE)) {
+ pendingReload.get().reload();
+ }
+ }
+
+ @Override
+ public void addEditorReloadListener(IEditorReloadListener listener) {
+ reloadListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void removeEditorReloadListener(IEditorReloadListener listener) {
+ reloadListeners.remove(listener);
+ }
+ };
+ }
+
+ private void addSelfReloadListener() {
+ createReloadAdapter().addEditorReloadListener(new IEditorReloadListener() {
+
+ @Override
+ public void editorAboutToReload(EditorReloadEvent event) {
+ event.putContext(new MultiDiagramEditorSelectionContext(event.getEditor()));
+ }
+
+ @Override
+ public void editorReloaded(EditorReloadEvent event) {
+ ((MultiDiagramEditorSelectionContext) event.getContext()).restore(event.getEditor());
+ }
+ });
+ }
+
+ /**
+ * Register an action to be run when I am closed. Any number of such actions may
+ * be added. note that close actions also run on re-load, which behaves to all
+ * outward appearances like a close and re-open.
+ *
+ * @param closeAction
+ * an action to run when I am closed
+ */
+ public void onClose(Runnable closeAction) {
+ closeActions.add(closeAction);
+ }
+
+ @Override
+ protected void deactivate() {
+ getLifecycleManager().fireBeforeClose(this);
+ if (sashModelMngr != null) {
+ sashModelMngr.getSashModelContentChangedProvider().removeListener(contentChangedListener);
+ }
+
+ super.deactivate();
+
+ // dispose available service
+ if (servicesRegistry != null) {
+ try {
+ servicesRegistry.disposeRegistry();
+ servicesRegistry = null;
+ } catch (ServiceMultiException e) {
+ log.error(e);
+ }
+ }
+
+ if (contentChangedListener != null) {
+ this.contentChangedListener = null;
+ }
+
+ if (editorInputChangedListener != null) {
+ this.editorInputChangedListener.dispose();
+ this.editorInputChangedListener = null;
+ }
+
+ for (Runnable next : closeActions) {
+ try {
+ next.run();
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in close action", e); //$NON-NLS-1$
+ }
+ }
+ closeActions.clear();
+
+ transactionalEditingDomain = null;
+ resourceSet = null;
+ undoContext = null;
+ saveAndDirtyService = null;
+ sashModelMngr = null;
+ }
+
+ void initContents() throws PartInitException {
+ loadModelAndServices();
+ loadNestedEditors();
+ }
+
+ @Override
+ public void setFocus() {
+ super.setFocus();
+
+ DeferredReload reload = pendingReload.get();
+ if (reload != null) {
+ reload.reload();
+ }
+ }
+
+ private void doReload() throws CoreException {
+ final IWorkbenchPage page = getSite().getPage();
+ final IWorkbenchPart activePart = page.getActivePart();
+ final IEditorPart activeEditor = page.getActiveEditor();
+
+ final Iterable<? extends IEditorReloadListener> listeners = ImmutableList.copyOf(reloadListeners);
+ final EditorReloadEvent event = new EditorReloadEvent(CoreMultiDiagramEditor.this);
+
+ try {
+ event.dispatchEditorAboutToReload(listeners);
+
+ deactivate();
+
+ initContents();
+
+ activate();
+
+ // My self-listener will be first, to ensure that the pages are all restored before dependents run
+ event.dispatchEditorReloaded(listeners);
+ } finally {
+ event.dispose();
+
+ // Ensure that the editor previously active is active again (if it still exists)
+ if ((activeEditor != null) && page.isPartVisible(activeEditor)) {
+ page.activate(activeEditor);
+ }
+
+ // Ensure that the part previously active is active again (if it still exists and is not the active editor)
+ if ((activePart != null) && (activePart != activeEditor) && page.isPartVisible(activePart)) {
+ page.activate(activePart);
+ }
+ }
+
+ }
+
+ /**
+ * Overrides doSave.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ public void doSave(IProgressMonitor monitor) {
+
+ saveAndDirtyService.doSave(monitor);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isDirty() {
+ // May happen if the editor has not yet been initialized. In this case, the editor cannot be dirty, so we simply return false.
+ // Bug 410286: The isDirty() method can also be called /after/ the editor has been disposed. Most likely an Eclipse bug?
+ if (saveAndDirtyService == null) {
+ return false;
+ }
+ return saveAndDirtyService.isDirty();
+ }
+
+ /**
+ * Overrides doSaveAs.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.part.EditorPart#doSaveAs()
+ */
+ @Override
+ public void doSaveAs() {
+
+ saveAndDirtyService.doSaveAs();
+ }
+
+ /**
+ * Overrides isSaveAsAllowed.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
+ */
+ @Override
+ public boolean isSaveAsAllowed() {
+ return true;
+ }
+
+ /**
+ * Overrides getContributorId.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor#getContributorId()
+ */
+ @Override
+ public String getContributorId() {
+ // return Activator.PLUGIN_ID;
+ return "TreeOutlinePage";
+
+ }
+
+ // implements IDiagramWorkbenchPart to restore GMF standard behavior
+ // and delegate to the activeEditor
+
+ /**
+ * Overrides getDiagram.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#getDiagram()
+ */
+ // public org.eclipse.gmf.runtime.notation.Diagram getDiagram() {
+ // IEditorPart activeEditor = getActiveEditor();
+ // if(activeEditor instanceof DiagramEditor) {
+ // return ((DiagramEditor)activeEditor).getDiagram();
+ // } else {
+ // return null;
+ // }
+ // }
+
+ /**
+ * This method is called from a GMF diagram. It should only be called from GMF diagram code. Normally, the Diagram under the Mouse is a GMF
+ * Diagram. The active Diagram can be another Diagram, not
+ * under the mouse. This is a GMF issue.
+ */
+ // public DiagramEditPart getDiagramEditPart() {
+ //
+ // // Get the editor under the mouse
+ // // IEditorPart activeEditor = rootContainer.getEditorUnderMouse();
+ // IEditorPart activeEditor = getActiveEditor();
+ // if(activeEditor == null) {
+ // return null;
+ // }
+ // // IEditorPart activeEditor = getActiveEditor();
+ // if(activeEditor instanceof DiagramEditor) {
+ // return ((DiagramEditor)activeEditor).getDiagramEditPart();
+ // } else {
+ // // This case should never happen.
+ // // Return null, as the GMF runtime now support it (since 093009)
+ // return null;
+ // }
+ // }
+
+ /**
+ * Overrides getDiagramGraphicalViewer.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#getDiagramGraphicalViewer()
+ */
+ // public IDiagramGraphicalViewer getDiagramGraphicalViewer() {
+ // IEditorPart activeEditor = getActiveEditor();
+ // if(activeEditor instanceof DiagramEditor) {
+ // return ((DiagramEditor)activeEditor).getDiagramGraphicalViewer();
+ // } else {
+ // return null;
+ // }
+ // }
+
+ /**
+ * Overrides getEditingDomain.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.edit.domain.IEditingDomainProvider#getEditingDomain()
+ */
+ @Override
+ public EditingDomain getEditingDomain() {
+ return transactionalEditingDomain;
+ }
+
+ /**
+ * Throws an UnsupportedOperationException.
+ *
+ * @see org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor#getDiagramEditDomain()
+ */
+ // public DiagramEditDomain getDiagramEditDomain() {
+ // throw new UnsupportedOperationException("Not implemented. Should not be called.");
+ // }
+
+
+ /**
+ * Change the editor input.<BR>
+ * <U>Note</U>: that method should be called within the UI-Thread.
+ *
+ * @see org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor#setEditorInput(org.eclipse.ui.IEditorInput)
+ *
+ * @param newInput
+ * The new input
+ * @deprecated Not used anymore
+ */
+
+ @Override
+ @Deprecated
+ public void setEditorInput(IEditorInput newInput) {
+ setInputWithNotify(newInput);
+ setPartName(newInput.getName());
+ }
+
+ @Override
+ @Deprecated
+ public void gotoMarker(IMarker marker) {
+ IWorkbench wb = PlatformUI.getWorkbench();
+ IWorkbenchPage page = wb.getActiveWorkbenchWindow().getActivePage();
+ boolean first = true;
+ for (IViewReference view : page.getViewReferences()) {
+ // no longer restrict to model explorer (see bug 387578)
+ IWorkbenchPart part = view.getPart(false);
+ if (part instanceof IGotoMarker) {
+ // activate first view implementing the IGotoMarker interface
+ if (first) {
+ page.activate(view.getPart(false));
+ first = false;
+ }
+ ((IGotoMarker) part).gotoMarker(marker);
+ }
+ }
+ }
+
+ private boolean needsRefresh;
+
+ protected void scheduleRefresh() {
+ needsRefresh = true;
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ refreshTabs();
+ }
+ });
+ }
+
+ @Override
+ protected void refreshTabs() {
+ if (!needsRefresh) {
+ return;
+ }
+ needsRefresh = false;
+ super.refreshTabs();
+ }
+
+ @Override
+ public synchronized IEditorPart getActiveEditor() {
+ refreshTabs();
+ return super.getActiveEditor();
+ }
+
+ private final class DeferredReload extends IReloadableEditor.Adapter {
+
+ private final Collection<? extends Resource> triggeringResources;
+
+ private final ReloadReason reason;
+
+ private final DirtyPolicy dirtyPolicy;
+
+ DeferredReload(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) {
+ super(CoreMultiDiagramEditor.this);
+
+ this.triggeringResources = ImmutableSet.copyOf(triggeringResources);
+ this.reason = reason;
+ this.dirtyPolicy = dirtyPolicy;
+ }
+
+ void reload() {
+ try {
+ reloadEditor(triggeringResources, reason, dirtyPolicy);
+ } catch (CoreException e) {
+ // Failed to properly unload/load in place, so just close
+ getSite().getPage().closeEditor(CoreMultiDiagramEditor.this, false);
+
+ StatusManager.getManager().handle(e.getStatus(), StatusManager.LOG | StatusManager.SHOW);
+ }
+ }
+
+ @Override
+ public void reloadEditor(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) throws CoreException {
+ if (!pendingReload.compareAndSet(this, null)) {
+ return;
+ }
+
+ final DirtyPolicy action = dirtyPolicy.resolve(CoreMultiDiagramEditor.this, triggeringResources, reason);
+
+ if ((action == DirtyPolicy.SAVE) && isDirty()) {
+ doSave(new NullProgressMonitor());
+ }
+
+ switch (action) {
+ case SAVE:
+ case DO_NOT_SAVE:
+ if (reason.shouldReload(triggeringResources)) {
+ // Attempt to re-load
+ doReload();
+ } else {
+ // Just close 'er down
+ getSite().getPage().closeEditor(CoreMultiDiagramEditor.this, false);
+ }
+ break;
+ case IGNORE:
+ // Pass
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid resolution of editor re-load dirty policy: " + action); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java new file mode 100644 index 00000000000..1f13fedb84b --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java @@ -0,0 +1,114 @@ +/***************************************************************************** + * Copyright (c) 2013 Cedric Dumoulin. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.editor; + +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel; +import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModelUtils; +import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelManager; +import org.eclipse.papyrus.infra.core.services.IServiceFactory; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.papyrus.infra.ui.editorsfactory.PageModelFactoryRegistry; +import org.eclipse.papyrus.infra.ui.extension.diagrameditor.PluggableEditorFactoryReader; + +/** + * Service Factory to create the {@link DiSashModelManager} service. + * + * @author cedric dumoulin + * + */ +public class DiSashModelManagerServiceFactory implements IServiceFactory { + + private TransactionalEditingDomain transactionalEditingDomain; + + private SashModel sashModel; + + private DiSashModelManager sashModelMngr; + + private ServicesRegistry servicesRegistry; + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry) + * + * @param servicesRegistry + * @throws ServiceException + */ + @Override + public void init(ServicesRegistry servicesRegistry) throws ServiceException { + + this.servicesRegistry = servicesRegistry; + // Get required service + transactionalEditingDomain = servicesRegistry.getService(TransactionalEditingDomain.class); + + // Get the model holding the contentProvider + sashModel = SashModelUtils.getSashModelChecked(servicesRegistry); + + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#startService() + * + * @throws ServiceException + */ + @Override + public void startService() throws ServiceException { + + // Read declared editors + PageModelFactoryRegistry pageModelRegistry = new PageModelFactoryRegistry(); + PluggableEditorFactoryReader editorReader = new PluggableEditorFactoryReader(Activator.PLUGIN_ID); + editorReader.populate(pageModelRegistry, servicesRegistry); + + if (sashModel.getResource() == null) { + throw new ServiceException("Can't start " + this.getClass().getSimpleName() + "'. Required model (SashModel) should be loaded prior starting the service."); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // create the service + sashModelMngr = new DiSashModelManager(pageModelRegistry, sashModel.getResource(), transactionalEditingDomain); + + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#disposeService() + * + * @throws ServiceException + */ + @Override + public void disposeService() throws ServiceException { + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance() + * + * @return + * @throws ServiceException + */ + @Override + public Object createServiceInstance() throws ServiceException { + + // Start locally the service if needed. + // Question: Can createServiceInstance() method be called before + // startService() is called ? + if (sashModelMngr == null) { + startService(); + } + + return sashModelMngr; + } + + + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java new file mode 100644 index 00000000000..ad0806cff77 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java @@ -0,0 +1,101 @@ +/** + * + */ +package org.eclipse.papyrus.infra.ui.editor; + +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel; +import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModelUtils; +import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelMngr; +import org.eclipse.papyrus.infra.core.services.IServiceFactory; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.papyrus.infra.ui.editorsfactory.PageModelFactoryRegistry; +import org.eclipse.papyrus.infra.ui.extension.diagrameditor.PluggableEditorFactoryReader; + +/** + * Service Factory to create the {@link DiSashModelMngr} service. + * + * @author cedric dumoulin + * + */ +public class DiSashModelMngrServiceFactory implements IServiceFactory { + + private TransactionalEditingDomain transactionalEditingDomain; + + private SashModel sashModel; + + private DiSashModelMngr sashModelMngr; + + private ServicesRegistry servicesRegistry; + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry) + * + * @param servicesRegistry + * @throws ServiceException + */ + @Override + public void init(ServicesRegistry servicesRegistry) throws ServiceException { + + this.servicesRegistry = servicesRegistry; + // Get required service + transactionalEditingDomain = servicesRegistry.getService(TransactionalEditingDomain.class); + + // Get the model holding the contentProvider + sashModel = SashModelUtils.getSashModelChecked(servicesRegistry); + + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#startService() + * + * @throws ServiceException + */ + @Override + public void startService() throws ServiceException { + + // Read declared editors + PageModelFactoryRegistry pageModelRegistry = new PageModelFactoryRegistry(); + PluggableEditorFactoryReader editorReader = new PluggableEditorFactoryReader(Activator.PLUGIN_ID); + editorReader.populate(pageModelRegistry, servicesRegistry); + + if (sashModel.getResource() == null) { + throw new ServiceException("Can't start " + this.getClass().getSimpleName() + "'. Required model (SashModel) should be loaded prior starting the service."); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // create the service + sashModelMngr = new DiSashModelMngr(pageModelRegistry, sashModel.getResource()); + + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#disposeService() + * + * @throws ServiceException + */ + @Override + public void disposeService() throws ServiceException { + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance() + * + * @return + * @throws ServiceException + */ + @Override + public Object createServiceInstance() throws ServiceException { + + // Start locally the service if needed. + // Question: Can createServiceInstance() method be called before + // startService() is called ? + if (sashModelMngr == null) { + startService(); + } + + return sashModelMngr; + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java new file mode 100644 index 00000000000..7549517199e --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java @@ -0,0 +1,93 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+
+/**
+ * Interface implemented by the main multipage editor. This interface list the
+ * methods available to diagram editors. Diagram editors can relies on this
+ * interface to retrieve services from the main multi diagram editor. <br>
+ * This interface should stay minimalist, as the editor is not designed to
+ * handle the services itself. A service should be retrieved by using {@link #getServicesRegistry()}.
+ *
+ *
+ * @author cedric dumoulin
+ *
+ * TODO remove extends IEditingDomainProvider. This interface should be
+ * independant of any technology (EMF, GMF, ...). If the EditingDomain
+ * is required, it can be retrieved by the registry.
+ *
+ */
+public interface IMultiDiagramEditor extends IEditorPart {
+
+ /**
+ * Returns the service registry associated to the editor.
+ *
+ * @return the servicesRegistry The registry.
+ */
+ public ServicesRegistry getServicesRegistry();
+
+ /**
+ * Return the editor site.
+ *
+ * @return
+ */
+ @Override
+ public IEditorSite getEditorSite();
+
+ /**
+ * Get the editor input.
+ *
+ * @return
+ */
+ @Override
+ public IEditorInput getEditorInput();
+
+ /**
+ * Change the editor input.
+ *
+ * @param newInput
+ * The new input.
+ * @deprecated No replacement. Input can't be changed on multi editors.
+ */
+ @Deprecated
+ public void setEditorInput(IEditorInput newInput);
+
+ /**
+ * Returns the edit domain shared among editors
+ *
+ * @return the edit domain shared among editors
+ * @deprecated Use {@link #getServicesRegistry()} or {@link #getAdapter(Class)}
+ */
+ // FIXME Remove it (GMF dependency)
+ // public DiagramEditDomain getDiagramEditDomain();
+
+ /**
+ * Get the currently active nested Editor.
+ */
+ public IEditorPart getActiveEditor();
+
+ /**
+ * Get the property sheet page associated to the Editor.
+ *
+ * @return the property sheet page associated to the Editor.
+ * @deprecated Use {@link #getServicesRegistry()} or {@link #getAdapter(Class)}
+ */
+ // @Deprecated
+ // public IPropertySheetPage getPropertySheetPage();
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java new file mode 100644 index 00000000000..a56ab916ec6 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java @@ -0,0 +1,35 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.ui.IEditorInput;
+
+/**
+ * An IEditorInput used to reference the page(s) to open
+ *
+ * @author Camille Letavernier
+ *
+ */
+public interface IPapyrusPageInput extends IEditorInput {
+
+ /**
+ * @return the list of pages to open
+ */
+ public URI[] getPages();
+
+ /**
+ *
+ * @return true if the editor should close all other pages
+ */
+ public boolean closeOtherPages();
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java new file mode 100644 index 00000000000..92bff539cf7 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * Christian W. Damus - bug 485220 + * + */ +package org.eclipse.papyrus.infra.ui.editor; + +import java.util.Collection; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.emf.common.ui.URIEditorInput; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.tools.util.CoreExecutors; +import org.eclipse.papyrus.infra.tools.util.PlatformHelper; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.papyrus.infra.ui.editor.reload.IEditorReloadListener; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IURIEditorInput; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.ide.IDE; + + +/** + * An {@linkplain IAdaptable adapter protocol} for editors that know how to internally + * reload themselves without disturbing the workbench window's perspective layout. + */ +public interface IReloadableEditor { + + /** + * Reloads me in-place in the perspective layout. + * + * @param triggeringResources + * the resources that have changed in some way, triggering re-load + * @param reason + * the reason why the re-load is being requested + * @param dirtyPolicy + * how the client would like to handle the case of a dirty editor + * + * @throws CoreException + * on any failure to unload, reload, or whatever + */ + void reloadEditor(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) throws CoreException; + + void addEditorReloadListener(IEditorReloadListener listener); + + void removeEditorReloadListener(IEditorReloadListener listener); + + /** + * An enumeration of the reason why some resources that an editor has loaded are triggering a re-load (or close). + */ + enum ReloadReason { + /** Resources have changed in persistent storage. */ + RESOURCES_CHANGED, + /** Resources have been deleted from persistent storage. */ + RESOURCES_DELETED; + + /** + * Queries whether, under ordinary circumstances, the editor should attempt to re-load to pick up changes in its dependent resources. + * + * @param triggeringResources + * the resources triggering re-load (or close) + * + * @return whether the editor should re-load + */ + public boolean shouldReload(Collection<? extends Resource> triggeringResources) { + return this != RESOURCES_DELETED; + } + } + + /** + * An enumeration of policies that clients may request to govern what to do with the editor before re-load (or close) if it should happen to be + * dirty. Note that editors are free to honour the requested policy or not, according to their needs. + */ + enum DirtyPolicy { + /** + * Save the editor without prompting. + */ + SAVE, + /** + * Do not save the editor; just discard pending changes and re-load (or close). + */ + DO_NOT_SAVE, + /** + * Do not re-load (or close) the editor; just keep pending changes and deal with conflicts later. + */ + IGNORE, + /** + * Prompt the user to inquire whether to save, discard pending changes, or not re-load (or close) at all. + * Note that the user prompt must always result in one of the other policies being actually applied. + */ + PROMPT_TO_SAVE { + + @Override + public DirtyPolicy resolve(IEditorPart editor, final Collection<? extends Resource> triggeringResources, final ReloadReason reason) throws CoreException { + final boolean dirty = editor.isDirty(); + + if (!dirty) { + if (reason.shouldReload(triggeringResources)) { + // Just re-load it. Simple + return DO_NOT_SAVE; + } else if (isPrincipalResourceAffected(editor, triggeringResources)) { + // Just close it. Also simple + return DO_NOT_SAVE; + } + } + + final String editorName = getEditorName(editor); + + final boolean allReadOnly = allReadOnly(triggeringResources); + final String promptTitle; + final String promptIntro; + final String saveOption; + final String dontSaveOption; + final String ignoreOption = "Ignore"; + + switch (reason) { + case RESOURCES_DELETED: + promptTitle = "Resources Deleted"; + promptIntro = NLS.bind("Some resources used by \"{0}\" have been deleted.", editorName); + saveOption = "Save and Close"; + dontSaveOption = "Close Editor"; + break; + default: + promptTitle = "Resources Changed"; + promptIntro = NLS.bind("Some resources used by \"{0}\" have changed.", editorName); + saveOption = "Save and Re-open"; + dontSaveOption = "Re-open Editor"; + break; + } + + Callable<DirtyPolicy> result; + + if (allReadOnly) { + // Only read-only models have changed. We (most likely) won't save them within this current editor. As they are already loaded, we can just continue. + result = new Callable<DirtyPolicy>() { + + @Override + public DirtyPolicy call() { + Shell parentShell = Display.getCurrent().getActiveShell(); + + final String message; + final String[] options; + if (dirty) { + message = promptIntro + " Note: all these resources are loaded in read-only mode and won't be overridden if you choose to save. Unsaved changes will be lost."; + options = new String[] { saveOption, dontSaveOption, ignoreOption }; + } else { + message = promptIntro; + options = new String[] { dontSaveOption, ignoreOption }; + } + + final MessageDialog dialog = new MessageDialog(parentShell, promptTitle, null, message, MessageDialog.WARNING, options, 0) { + + @Override + protected void setShellStyle(int newShellStyle) { + super.setShellStyle(newShellStyle | SWT.SHEET); + } + }; + final int answer = dialog.open(); + + DirtyPolicy result; + + if (answer == SWT.DEFAULT) { + // User hit Esc or dismissed the dialog with the window manager button. Ignore + result = IGNORE; + } else if (dirty) { + result = values()[answer]; + } else { + result = values()[answer + 1]; // Account for the missing "Save and Xxx" option + } + + return result; + } + }; + } else { + // At least one read-write resource has changed. Potential conflicts. + result = new Callable<DirtyPolicy>() { + + @Override + public DirtyPolicy call() { + DirtyPolicy result = IGNORE; + + final Shell parentShell = Display.getCurrent().getActiveShell(); + final String action = reason.shouldReload(triggeringResources) ? "re-open" : "close"; + final String message; + + if (dirty) { + message = promptIntro + NLS.bind(" Do you wish to {0} the current editor? Unsaved changes will be lost.", action); + } else { + message = promptIntro + NLS.bind(" Do you wish to {0} the current editor?", action); + } + + final String[] options = { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }; + final MessageDialog dialog = new MessageDialog(parentShell, promptTitle, null, message, MessageDialog.WARNING, options, 0) { + + @Override + protected void setShellStyle(int newShellStyle) { + super.setShellStyle(newShellStyle | SWT.SHEET); + } + }; + if (dialog.open() == 0) { + result = DO_NOT_SAVE; + } + + return result; + } + }; + } + + try { + return CoreExecutors.getUIExecutorService().syncCall(result); + } catch (ExecutionException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to determine dirty policy for editor re-load.", e)); + } catch (InterruptedException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Interrupted in determining dirty policy for editor re-load.", e)); + } + } + }; + + /** + * Queries the default dirty policy currently in effect. The default-default is {@link #PROMPT_TO_SAVE}. + * + * @return the default policy + */ + public static DirtyPolicy getDefault() { + return PROMPT_TO_SAVE; + } + + /** + * Resolves me to a specific actionable policy, based on the resources that are triggering re-load (or close) and the reason. + * + * @param editor + * the editor to be re-loaded + * @param triggeringResources + * the resources (possibly an empty collection) that have changed + * @param reloadReason + * the reason why re-load (or close) is triggered + * + * @return the specific policy to implement in re-loading the editor + * + * @throws CoreException + * on failure to resolve the specific policy + */ + public DirtyPolicy resolve(IEditorPart editor, Collection<? extends Resource> triggeringResources, ReloadReason reason) throws CoreException { + return this; + } + + String getEditorName(IEditorPart editor) { + ModelSet modelSet = getModelSet(editor); + return (modelSet == null) ? editor.getTitle() : modelSet.getURIWithoutExtension().lastSegment(); + } + + private ModelSet getModelSet(IEditorPart editor) { + ModelSet result = null; + + if (editor instanceof IMultiDiagramEditor) { + try { + result = ((IMultiDiagramEditor) editor).getServicesRegistry().getService(ModelSet.class); + } catch (ServiceException e) { + // No problem. We have a fall-back + Activator.log.error(e); + } + } + + return result; + } + + boolean isPrincipalResourceAffected(IEditorPart editor, Collection<? extends Resource> triggeringResources) { + boolean result = false; + + ModelSet modelSet = getModelSet(editor); + if (modelSet != null) { + URI principalURI = modelSet.getURIWithoutExtension(); + for (Resource next : triggeringResources) { + if (next.getURI().trimFileExtension().equals(principalURI)) { + result = true; + break; + } + } + } else { + URI principalURI = getURI(editor.getEditorInput()); + if (principalURI != null) { + for (Resource next : triggeringResources) { + if (next.getURI().equals(principalURI)) { + result = true; + break; + } + } + } + } + + return result; + } + + private URI getURI(IEditorInput input) { + URI result = null; + + if (input instanceof URIEditorInput) { + result = ((URIEditorInput) input).getURI(); + } else if (input instanceof IURIEditorInput) { + result = URI.createURI(((IURIEditorInput) input).getURI().toString()); + } + + return result; + } + + protected boolean allReadOnly(Collection<? extends Resource> resources) { + for (Resource resource : resources) { + EditingDomain domain = TransactionUtil.getEditingDomain(resource); + if ((domain == null) || !domain.isReadOnly(resource)) { + return false; + } + } + + return true; + } + } + + /** + * A convenience adapter for editors that don't actually know how to reload themselves in place. + * It simply closes the editor and then opens it again on the original input. + */ + class Adapter implements IReloadableEditor { + + private final IEditorPart editor; + + public Adapter(IEditorPart editor) { + super(); + + this.editor = editor; + } + + public static IReloadableEditor getAdapter(IMultiDiagramEditor editor) { + return PlatformHelper.getAdapter(editor, IReloadableEditor.class, () -> new Adapter(editor)); + } + + @Override + public void reloadEditor(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) throws CoreException { + final IWorkbenchPage page = editor.getSite().getPage(); + final IEditorInput currentInput = editor.getEditorInput(); + + final Display display = editor.getSite().getShell().getDisplay(); + + final String editorId = editor.getSite().getId(); + + final DirtyPolicy action = dirtyPolicy.resolve(editor, triggeringResources, reason); + final boolean save = action == DirtyPolicy.SAVE; + + if (save && editor.isDirty()) { + editor.doSave(new NullProgressMonitor()); + } + + if (action != DirtyPolicy.IGNORE) { + page.closeEditor(editor, save); + + // If resources were deleted, we close and don't re-open + if (reason.shouldReload(triggeringResources)) { + display.asyncExec(new Runnable() { + + @Override + public void run() { + try { + IDE.openEditor(page, currentInput, editorId); + } catch (PartInitException ex) { + Activator.log.error(ex); + } + } + }); + } + } + } + + @Override + public void addEditorReloadListener(IEditorReloadListener listener) { + // Don't need to track these listeners because I never properly reload an editor + } + + @Override + public void removeEditorReloadListener(IEditorReloadListener listener) { + // Don't need to track these listeners because I never properly reload an editor + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java new file mode 100644 index 00000000000..fc0302004dd --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor; + +import java.util.List; +import java.util.Set; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.edit.domain.EditingDomain; +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.StructuredSelection; +import org.eclipse.papyrus.infra.core.sasheditor.editor.IComponentPage; +import org.eclipse.papyrus.infra.core.sasheditor.editor.IEditorPage; +import org.eclipse.papyrus.infra.core.sasheditor.editor.IPage; +import org.eclipse.papyrus.infra.core.sasheditor.editor.IPageVisitor; +import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.papyrus.infra.ui.editor.reload.CompositeReloadContext; +import org.eclipse.papyrus.infra.ui.editor.reload.DelegatingReloadContext; +import org.eclipse.papyrus.infra.ui.editor.reload.EMFSelectionContext; +import org.eclipse.papyrus.infra.ui.editor.reload.EditorReloadEvent; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + + +/** + * A {@linkplain EditorReloadEvent reload event} context that restores the selection of which editor page + * is active in an {@link IMultiDiagramEditor} that is reloaded and delegates to its pages to capture + * re-load context for each to restore whatever they need to restore (internal selections etc.). + */ +class MultiDiagramEditorSelectionContext extends CompositeReloadContext { + + private ISashWindowsContainer sashContainer; + + private final List<URI> resourcesToLoad; + + MultiDiagramEditorSelectionContext(IMultiDiagramEditor editor) { + super(); + + init(editor); + + resourcesToLoad = computeResourcesToLoad(editor); + + IPage active = sashContainer.getActiveSashWindowsPage(); + DiagramPageContext activePage = null; + + Set<IPage> visiblePages = Sets.newIdentityHashSet(); + visiblePages.addAll(sashContainer.getVisiblePages()); + + List<IPage> allPages = getAllPages(sashContainer); + + for (IPage page : allPages) { + final DelegatingReloadContext delegator = (page instanceof IEditorPage) ? add(new DelegatingReloadContext(((IEditorPage) page).getIEditorPart())) : null; + DiagramPageContext context; + + if (page == active) { + // This one will have the selection of the active page + context = new DiagramPageContext(new VisiblePageSelectionProvider(page), page, delegator); + activePage = context; + } else { + if (visiblePages.contains(page)) { + // This one must be selected in its folder in order to make it visible again + context = new DiagramPageContext(new VisiblePageSelectionProvider(page), page, delegator); + } else { + context = new DiagramPageContext(EmptySelectionProvider.INSTANCE, page, delegator); + } + + // We make sure always to restore the active page last + // so that it will not only be visible but also the + // over-all active page + add(context); + } + } + + if (activePage != null) { + // Restore this one last + add(activePage); + } + } + + @Override + public void dispose() { + sashContainer = null; + super.dispose(); + } + + private List<IPage> getAllPages(ISashWindowsContainer container) { + final List<IPage> result = Lists.newArrayList(); + + container.visit(new IPageVisitor() { + + @Override + public void accept(IEditorPage page) { + result.add(page); + } + + @Override + public void accept(IComponentPage page) { + result.add(page); + } + }); + + return result; + } + + private void init(IMultiDiagramEditor editor) { + sashContainer = AdapterUtils.adapt(editor, ISashWindowsContainer.class, null); + } + + void restore(IMultiDiagramEditor editor) { + init(editor); + + // Forcibly re-load all previously loaded resources to that + // (a) we don't lose imports that weren't yet used, and + // (b) we can restore selections in resources that wouldn't be loaded until proxies resolve later + reloadResources(editor); + + ISelectionProvider selectionProvider = new VisiblePageSelectionProvider(); + for (DiagramPageContext next : getReloadContexts(DiagramPageContext.class)) { + next.restore(selectionProvider); + } + } + + protected List<URI> computeResourcesToLoad(IMultiDiagramEditor editor) { + List<URI> result = null; + + ResourceSet rset = getResourceSet(editor); + if (rset != null) { + result = Lists.newArrayListWithCapacity(rset.getResources().size()); + + for (Resource next : rset.getResources()) { + if (next.isLoaded()) { + result.add(next.getURI()); + } + } + } + + return result; + } + + protected void reloadResources(IMultiDiagramEditor editor) { + if (resourcesToLoad != null) { + ResourceSet rset = getResourceSet(editor); + if (rset != null) { + for (URI next : resourcesToLoad) { + try { + rset.getResource(next, true); + } catch (Exception e) { + Activator.log.error("Failed to restore loaded resource: " + next, e); //$NON-NLS-1$ + } + } + } + } + } + + protected final ResourceSet getResourceSet(IMultiDiagramEditor editor) { + ResourceSet result = null; + + EditingDomain editingDomain = editor.getAdapter(EditingDomain.class); + if (editingDomain != null) { + result = editingDomain.getResourceSet(); + } + + return result; + } + + // + // Nested types + // + + private class DiagramPageContext extends EMFSelectionContext { + + private URI pageRef; + + private DelegatingReloadContext pageContext; + + DiagramPageContext(ISelectionProvider structuredSelectionProvider, IPage page, DelegatingReloadContext pageContext) { + super(structuredSelectionProvider); + + this.pageContext = pageContext; + this.pageRef = getToken(page.getRawModel()); + } + + @Override + public void restore(ISelectionProvider structuredSelectionProvider) { + IPage page = sashContainer.lookupModelPage(resolveToken(pageRef)); + + if ((pageContext != null) && (page instanceof IEditorPage)) { + pageContext.restore(((IEditorPage) page).getIEditorPart()); + } + + super.restore(structuredSelectionProvider); + } + + @Override + protected Object deresolveSelectableElement(Object selectableElement) { + return (selectableElement instanceof IPage) ? ((IPage) selectableElement).getRawModel() : super.deresolveSelectableElement(selectableElement); + } + + @Override + protected Object resolveSelectableElement(Object deresolved) { + return sashContainer.lookupModelPage(deresolved); + } + } + + private static class EmptySelectionProvider implements ISelectionProvider { + + static final EmptySelectionProvider INSTANCE = new EmptySelectionProvider(); + + EmptySelectionProvider() { + super(); + } + + @Override + public ISelection getSelection() { + return StructuredSelection.EMPTY; + } + + @Override + public void setSelection(ISelection selection) { + // Pass + } + + @Override + public void addSelectionChangedListener(ISelectionChangedListener listener) { + // Not needed because the selection is always empty + } + + @Override + public void removeSelectionChangedListener(ISelectionChangedListener listener) { + // Not needed because the selection is always empty + } + + } + + private class VisiblePageSelectionProvider implements ISelectionProvider { + + private final IStructuredSelection selection; + + VisiblePageSelectionProvider() { + this(null); + } + + VisiblePageSelectionProvider(IPage visible) { + super(); + + this.selection = (visible == null) ? StructuredSelection.EMPTY : new StructuredSelection(visible); + } + + @Override + public ISelection getSelection() { + return selection; + } + + @Override + public void setSelection(ISelection selection) { + if (!selection.isEmpty()) { + IPage page = (IPage) ((IStructuredSelection) selection).getFirstElement(); + sashContainer.selectPage(page); + } + } + + @Override + public void addSelectionChangedListener(ISelectionChangedListener listener) { + // Not needed + } + + @Override + public void removeSelectionChangedListener(ISelectionChangedListener listener) { + // Not needed + } + + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java new file mode 100644 index 00000000000..9ef43cb4cd3 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java @@ -0,0 +1,178 @@ +/***************************************************************************** + * Copyright (c) 2014, 2015 CEA LIST, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * CEA LIST - Initial API and implementation + * Christian W. Damus - bug 469188 + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.editor; + +import org.eclipse.core.commands.operations.IUndoContext; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.emf.common.ui.URIEditorInput; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.papyrus.infra.core.operation.DelegatingUndoContext; +import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer; +import org.eclipse.papyrus.infra.tools.util.PlatformHelper; +import org.eclipse.papyrus.infra.ui.editor.reload.EditorReloadEvent; +import org.eclipse.papyrus.infra.ui.editor.reload.IEditorReloadListener; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IStorageEditorInput; +import org.eclipse.ui.IURIEditorInput; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.operations.RedoActionHandler; +import org.eclipse.ui.operations.UndoActionHandler; +import org.eclipse.ui.part.IShowInSource; +import org.eclipse.ui.part.ShowInContext; +import org.eclipse.ui.views.properties.PropertyShowInContext; +import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; + + +/** + * A specialized property-sheet page that knows how to restore the Property Sheet view's input from the workbench part + * that most recently gave it its input, after a {@link CoreMultiDiagramEditor} has been re-loaded. + */ +class MultiDiagramPropertySheetPage extends TabbedPropertySheetPage implements IEditorReloadListener { + + private final CoreMultiDiagramEditor multiDiagramEditor; + + private UndoActionHandler undo; + private RedoActionHandler redo; + private DelegatingUndoContext undoContext; + + public MultiDiagramPropertySheetPage(CoreMultiDiagramEditor editor) { + super(editor); + + this.multiDiagramEditor = editor; + IReloadableEditor.Adapter.getAdapter(editor).addEditorReloadListener(this); + } + + @Override + public void dispose() { + IReloadableEditor.Adapter.getAdapter(multiDiagramEditor).removeEditorReloadListener(this); + + if (undo != null) { + undo.dispose(); + } + if (redo != null) { + redo.dispose(); + } + + super.dispose(); + } + + @Override + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + if (selection.isEmpty() && (part instanceof IMultiDiagramEditor)) { + // Perhaps the user selected a page such as the Welcome Page that + // isn't an editor and so doesn't have a selection + IMultiDiagramEditor editor = (IMultiDiagramEditor) part; + ISashWindowsContainer sash = editor.getAdapter(ISashWindowsContainer.class); + if (sash != null) { + if ((sash.getActiveEditor() == null) && (sash.getActiveSashWindowsPage() != null)) { + // Yep, that's the case, here. So show the properties of the input + // resource (usually a DI file) + IEditorInput input = editor.getEditorInput(); + Object newSelection; + if (input instanceof IFileEditorInput) { + newSelection = ((IFileEditorInput) input).getFile(); + } else if (input instanceof IStorageEditorInput) { + IStorageEditorInput storageInput = (IStorageEditorInput) input; + try { + newSelection = storageInput.getStorage(); + } catch (CoreException e) { + newSelection = storageInput; + } + } else if (input instanceof IURIEditorInput) { + newSelection = ((IURIEditorInput) input).getURI(); + } else if (input instanceof URIEditorInput) { + newSelection = ((URIEditorInput) input).getURI(); + } else { + newSelection = null; + } + + if (newSelection != null) { + selection = new StructuredSelection(newSelection); + } + } + } + } + + super.selectionChanged(part, selection); + } + + @Override + public void editorAboutToReload(EditorReloadEvent event) { + Object propertySheet = getSite().getService(IViewPart.class); + if (propertySheet instanceof IShowInSource) { + ShowInContext context = ((IShowInSource) propertySheet).getShowInContext(); + + if (context instanceof PropertyShowInContext) { + IWorkbenchPart inputPart = ((PropertyShowInContext) context).getPart(); + if (inputPart != null) { + event.putContext(inputPart); + } + } + } + } + + @Override + public void editorReloaded(EditorReloadEvent event) { + final IWorkbenchPart inputPart = (IWorkbenchPart) event.getContext(); + if (inputPart != null) { + final Object propertySheet = getSite().getService(IViewPart.class); + if (propertySheet instanceof IPartListener) { + // Kick it with this part + ((IPartListener) propertySheet).partActivated(inputPart); + + // And again later to get its new selection (we don't know when its selection may be restored relative to us) + getSite().getShell().getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + ISelectionProvider selectionProvider = inputPart.getSite().getSelectionProvider(); + if (selectionProvider != null) { + ((ISelectionListener) propertySheet).selectionChanged(inputPart, selectionProvider.getSelection()); + } + } + }); + } + } + + // The editor will have a new undo context (because it will have a new editing domain) + if (undoContext != null) { + undoContext.setDelegate(PlatformHelper.getAdapter(multiDiagramEditor, IUndoContext.class)); + } + } + + @Override + public void setActionBars(IActionBars actionBars) { + super.setActionBars(actionBars); + + undoContext = new DelegatingUndoContext(); + undoContext.setDelegate(PlatformHelper.getAdapter(multiDiagramEditor, IUndoContext.class)); + + undo = new UndoActionHandler(multiDiagramEditor.getSite(), undoContext); + redo = new RedoActionHandler(multiDiagramEditor.getSite(), undoContext); + + actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), undo); + actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), redo); + } + + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java new file mode 100644 index 00000000000..21eb6a2cfdc --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java @@ -0,0 +1,71 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IPageIconsRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.PageIconsRegistry;
+import org.eclipse.papyrus.infra.ui.extension.diagrameditor.PluggableEditorFactoryReader;
+
+/**
+ * Service Factory to register {@link IPageIconsRegistry}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class PageIconRegistryServiceFactory implements IServiceFactory {
+
+ private PageIconsRegistry pageIconsRegistry;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ if (pageIconsRegistry != null) {
+ pageIconsRegistry.dispose();
+ }
+ }
+
+ /**
+ * Create and populate a {@link PageIconsRegistry}. Return it as the service
+ * instance.
+ *
+ * @return
+ */
+ @Override
+ public Object createServiceInstance() {
+ if (pageIconsRegistry == null) {
+ pageIconsRegistry = new PageIconsRegistry();
+ PluggableEditorFactoryReader editorReader = new PluggableEditorFactoryReader(Activator.PLUGIN_ID);
+ editorReader.populate(pageIconsRegistry);
+ }
+ return pageIconsRegistry;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java new file mode 100644 index 00000000000..b7657e6ce1a --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java @@ -0,0 +1,83 @@ +/***************************************************************************** + * Copyright (c) 2011, 2016 LIFL, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * LIFL - Initial API and implementation + * Christian W. Damus - bugs 415638, 485220 + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.editor; + +import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider; +import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelManager; +import org.eclipse.papyrus.infra.core.services.IServiceFactory; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; + +/** + * A service factory to create the {@link IPageMngr} service. This + * serviceFactory depends on {@link ISashWindowsContentProvider} service. + * + * @author cedric dumoulin + * + */ +public class PageMngrServiceFactory implements IServiceFactory { + + /** + * The sashModelMangr. + */ + private DiSashModelManager sashModelMngr; + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry) + * + * @param servicesRegistry + * @throws ServiceException + */ + @Override + public void init(ServicesRegistry servicesRegistry) throws ServiceException { + + // Get required services + sashModelMngr = servicesRegistry.getService(DiSashModelManager.class); + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#startService() + * + * @throws ServiceException + */ + @Override + public void startService() throws ServiceException { + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#disposeService() + * + * @throws ServiceException + */ + @Override + public void disposeService() throws ServiceException { + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance() + * + * @return + * @throws ServiceException + * if the required sash model manager service is unavailable + */ + @Override + public Object createServiceInstance() throws ServiceException { + if (sashModelMngr == null) { + throw new ServiceNotFoundException(DiSashModelManager.class.getName()); + } + return sashModelMngr.getIPageManager(); + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java new file mode 100644 index 00000000000..7b69d7863d9 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java @@ -0,0 +1,62 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.ui.part.FileEditorInput;
+
+/**
+ * Basic implementation of {@link IPapyrusPageInput}
+ *
+ * @author Camille Letavernier
+ */
+public class PapyrusPageInput extends FileEditorInput implements IPapyrusPageInput {
+
+ private final URI[] pages;
+
+ private final boolean closeOtherPages;
+
+ /**
+ * Creates a new PapyrusPageInput
+ *
+ * @param diFile
+ * The file resource
+ * @param pages
+ * The pageIdentifiers of the pages to open
+ * @param closeOtherPages
+ * True if only the selected pages should be opened. All other pages will be closed.
+ */
+ public PapyrusPageInput(IFile diFile, URI[] pages, boolean closeOtherPages) {
+ super(diFile);
+ this.pages = pages;
+ this.closeOtherPages = closeOtherPages;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public URI[] getPages() {
+ return pages;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean closeOtherPages() {
+ return closeOtherPages;
+ }
+
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java new file mode 100644 index 00000000000..3eabad5cbf3 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + + +/** + * An {@linkplain EditorReloadEvent#putContext(Object) editor reload context} that composes other reload contexts. + * This should be used whenever a {@linkplain IReloadContextProvider reload context provider} supplies multiple + * reload contexts, to ensure that they are properly initialized by the reload system. + */ +public class CompositeReloadContext implements IDisposableReloadContext, IAdaptable { + + private final Collection<Object> reloadContexts; + + public CompositeReloadContext() { + this(Collections.EMPTY_LIST); + } + + public CompositeReloadContext(Iterable<?> reloadContexts) { + super(); + + this.reloadContexts = Lists.newArrayList(reloadContexts); + } + + public <T> T add(T reloadContext) { + reloadContexts.add(reloadContext); + return reloadContext; + } + + public Iterable<?> getReloadContexts() { + return Collections.unmodifiableCollection(reloadContexts); + } + + public <T> Iterable<T> getReloadContexts(Class<T> type) { + return Iterables.filter(getReloadContexts(), type); + } + + @Override + public void dispose() { + for (Object next : reloadContexts) { + if (next instanceof IDisposableReloadContext) { + ((IDisposableReloadContext) next).dispose(); + } + } + + reloadContexts.clear(); + } + + @Override + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return (adapter == IInternalEMFSelectionContext.class) ? getEMFContext() : null; + } + + private IInternalEMFSelectionContext getEMFContext() { + IInternalEMFSelectionContext result = null; + + for (Object next : reloadContexts) { + if (AdapterUtils.adapt(next, IInternalEMFSelectionContext.class, null) != null) { + // We need the adapter + result = new IInternalEMFSelectionContext.Composite(this); + break; + } + } + + return result; + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java new file mode 100644 index 00000000000..718b376c2ba --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; + + +/** + * An {@linkplain EditorReloadEvent#putContext(Object) editor reload context} that delegates to another reload context. + * This should be used whenever a {@linkplain IReloadContextProvider reload context provider} is needed to get a reload + * context to delegate to. + */ +public class DelegatingReloadContext implements IDisposableReloadContext, IAdaptable { + + private Object delegate; + + public DelegatingReloadContext(Object reloadContextProvider) { + super(); + + IReloadContextProvider provider = AdapterUtils.adapt(reloadContextProvider, IReloadContextProvider.class, null); + if (provider != null) { + delegate = provider.createReloadContext(); + } + } + + @Override + public void dispose() { + if (delegate instanceof IDisposableReloadContext) { + ((IDisposableReloadContext) delegate).dispose(); + } + + delegate = null; + } + + public Object getDelegate() { + return delegate; + } + + public void restore(Object reloadContextProvider) { + if (delegate != null) { + IReloadContextProvider provider = AdapterUtils.adapt(reloadContextProvider, IReloadContextProvider.class, null); + if (provider != null) { + provider.restore(delegate); + } + } + } + + @Override + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return (adapter == IInternalEMFSelectionContext.class) ? getEMFContext() : null; + } + + private IInternalEMFSelectionContext getEMFContext() { + IInternalEMFSelectionContext result = null; + + if ((delegate != null) && (AdapterUtils.adapt(delegate, IInternalEMFSelectionContext.class, null) != null)) { + // We need the adapter + result = new IInternalEMFSelectionContext.Delegating(this); + } + + return result; + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java new file mode 100644 index 00000000000..e8eea1033cc --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.emf.common.util.URI; +import org.eclipse.jface.viewers.ISelectionProvider; + + +/** + * A convenient selection re-load context for UIs that present EMF-based content. + */ +public class EMFSelectionContext extends SelectionContext<ISelectionProvider, URI> implements IAdaptable { + + private IInternalEMFSelectionContext emfContext; + + public EMFSelectionContext(ISelectionProvider structuredSelectionProvider) { + super(structuredSelectionProvider); + } + + @Override + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return (adapter == IInternalEMFSelectionContext.class) ? getEMFContext() : null; + } + + final IInternalEMFSelectionContext getEMFContext() { + if (emfContext == null) { + emfContext = new IInternalEMFSelectionContext.Default(); + } + return emfContext; + } + + @Override + protected URI getToken(Object object) { + return getEMFContext().getToken(object); + } + + @Override + protected Object resolveToken(URI token) { + return getEMFContext().resolveToken(token); + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java new file mode 100644 index 00000000000..a6f99008f06 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.emf.common.util.URI; +import org.eclipse.jface.viewers.AbstractTreeViewer; + +/** + * A convenient context object for {@link IEditorReloadListener}s to store in an {@link EditorReloadEvent} to capture and restore + * the expansion and selection state of nodes in an EMF-based tree viewer. + */ +public class EMFTreeViewerContext extends TreeViewerContext<URI> implements IAdaptable { + + private IInternalEMFSelectionContext emfContext; + + public EMFTreeViewerContext(AbstractTreeViewer viewer) { + super(viewer); + } + + @Override + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return (adapter == IInternalEMFSelectionContext.class) ? getEMFContext() : null; + } + + final IInternalEMFSelectionContext getEMFContext() { + if (emfContext == null) { + emfContext = new IInternalEMFSelectionContext.Default(); + } + return emfContext; + } + + @Override + protected URI getToken(Object object) { + return getEMFContext().getToken(object); + } + + @Override + protected Object resolveToken(URI token) { + return getEMFContext().resolveToken(token); + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java new file mode 100644 index 00000000000..5015f26011e --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + + + +/** + * Convenience superclass for selective implementation of editor reload call-backs. + */ +public class EditorReloadAdapter implements IEditorReloadListener { + + public EditorReloadAdapter() { + super(); + } + + @Override + public void editorAboutToReload(EditorReloadEvent event) { + // Pass + } + + @Override + public void editorReloaded(EditorReloadEvent event) { + // Pass + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java new file mode 100644 index 00000000000..c4d13f721b4 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import java.util.EventObject; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor; +import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor; + +import com.google.common.base.Supplier; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; + + +/** + * The event object for notifications of each phase in the reloading of a {@linkplain IReloadableEditor reloadable editor}. + */ +public class EditorReloadEvent extends EventObject { + + private static final long serialVersionUID = 1L; + + public static final int ABOUT_TO_RELOAD = 1; + + public static final int RELOADED = 2; + + private int type; + + private transient Map<IEditorReloadListener, Object> context; + + private transient IEditorReloadListener currentListener; + + public EditorReloadEvent(IMultiDiagramEditor editor) { + super(editor); + } + + public final IMultiDiagramEditor getEditor() { + return (IMultiDiagramEditor) getSource(); + } + + public final int getEventType() { + return type; + } + + /** + * Puts some opaque representation of contextual state for the caller to retrieve later when an editor is {@linkplain IEditorReloadListener#editorReloaded(EditorReloadEvent) reloaded}. + * The canonical example of this usage is storing state such as selection, expanded tree nodes, etc. to restore after re-building a UI that + * depends on the reloaded editor. After the editor re-load completes and all listeners are notified of that, then all context objects are + * released. Any that implement the {@link IDisposableReloadContext} interface are disposed according to that protocol. This is done even if it + * happens that the editor re-load procedure cannot complete normally and the editor is forced to close without notifying the post-reload + * listeners. + * + * @param object + * some state to stash for later retrieval following the re-loading of the editor + * + * @return the previous context object, if any (there normally wouldn't be as each listener that is invoked has its own context storage + * + * @throws IllegalStateException + * on any attempt to invoke this method except during an {@link IEditorReloadListener#editorAboutToReload(EditorReloadEvent)} call-back + */ + public Object putContext(Object object) { + checkContext(ABOUT_TO_RELOAD); + + IInternalEMFSelectionContext emfContext = AdapterUtils.adapt(object, IInternalEMFSelectionContext.class, null); + if (emfContext != null) { + initContext(emfContext); + } + + return context.put(currentListener, object); + } + + /** + * Retrieves an opaque representation of contextual state that was previously {@linkplain #putContext(Object) put} by the caller. + * + * @return the previously stashed object, or {@code null} if none + * + * @throws IllegalStateException + * on any attempt to invoke this method except during an {@link IEditorReloadListener#editorReloaded(EditorReloadEvent)} call-back + */ + public Object getContext() { + checkContext(RELOADED); + return context.get(currentListener); + } + + private void initContext(IInternalEMFSelectionContext context) { + Supplier<ResourceSet> resourceSetSupplier = new Supplier<ResourceSet>() { + + @Override + public ResourceSet get() { + try { + return getEditor().getServicesRegistry().getService(ModelSet.class); + } catch (ServiceException e) { + Activator.log.error(e); + throw new IllegalStateException("Invalid service registry in editor"); //$NON-NLS-1$ + } + } + }; + + context.setResourceSetSupplier(resourceSetSupplier); + } + + protected final void checkContext(int phase) { + if (currentListener == null) { + throw new IllegalStateException("Not in an IEditorReloadListener call-back"); //$NON-NLS-1$ + } + + if (phase != this.type) { + throw new IllegalStateException(String.format("Not in '%s' listener call-back", (phase == ABOUT_TO_RELOAD) ? "editorAboutToReload" : "editorReloaded")); + } + } + + public final void dispatchEditorAboutToReload(Iterable<? extends IEditorReloadListener> listeners) { + context = Maps.newHashMap(); + type = ABOUT_TO_RELOAD; + + for (Iterator<? extends IEditorReloadListener> iter = listeners.iterator(); iter.hasNext();) { + currentListener = iter.next(); + + try { + currentListener.editorAboutToReload(this); + } catch (Exception e) { + Activator.log.error("Uncaught exception in editor reload listener.", e); //$NON-NLS-1$ + } finally { + currentListener = null; + } + } + } + + public final void dispatchEditorReloaded(Iterable<? extends IEditorReloadListener> listeners) { + type = RELOADED; + + for (Iterator<? extends IEditorReloadListener> iter = listeners.iterator(); iter.hasNext();) { + currentListener = iter.next(); + + try { + currentListener.editorReloaded(this); + } catch (Exception e) { + Activator.log.error("Uncaught exception in editor reload listener.", e); //$NON-NLS-1$ + } finally { + currentListener = null; + } + } + } + + public void dispose() { + if (context != null) { + Error error = null; + + try { + for (IDisposableReloadContext next : Iterables.filter(context.values(), IDisposableReloadContext.class)) { + try { + next.dispose(); + } catch (Exception e) { + Activator.log.error("Uncaught exception in editor reload context disposal.", e); //$NON-NLS-1$ + } catch (Error e) { + if (error == null) { + error = e; + } + Activator.log.error("Uncaught exception in editor reload context disposal.", e); //$NON-NLS-1$ + } + } + } finally { + context = null; + } + + if (error != null) { + throw error; + } + } + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java new file mode 100644 index 00000000000..8aff9ccf83b --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +/** + * Protocol implemented by {@link EditorReloadEvent} context objects that must be disposed when they are no longer needed. + * + * @see EditorReloadEvent#dispose() + */ +public interface IDisposableReloadContext { + + void dispose(); +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java new file mode 100644 index 00000000000..2114d555152 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import java.util.EventListener; + +import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor; + + +/** + * A protocol for notification of the phases of re-loading of an {@link IReloadableEditor}. + */ +public interface IEditorReloadListener extends EventListener { + + /** + * Notifies that an editor is about to reload. Implementors may put stuff into the {@code event}'s {@link EditorReloadEvent#putContext(Object) + * context} to retrieve in an eventual {@linkplain #editorReloaded(EditorReloadEvent) }re-load} notification. The canonical example of this + * usage is storing state such as selection, expanded tree nodes, etc. to restore after re-building a UI that depends on the reloaded + * editor. + * + * @param event + * notification that an editor is going to re-load itself + */ + void editorAboutToReload(EditorReloadEvent event); + + /** + * Notifies that an editor has reloaded. Implementors may retrieve from the {@code event} any {@link EditorReloadEvent#getContext() + * context} that they put in {@linkplain #editorAboutToReload(EditorReloadEvent) before} the re-load. + * + * @param event + * notification that an editor has reloaded + */ + void editorReloaded(EditorReloadEvent event); +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java new file mode 100644 index 00000000000..f8bda865a97 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; + + +/** + * An internal interface provided (usually as an {@linkplain IAdaptable#getAdapter(Class) adapter}) by EMF-based {@linkplain SelectionContext + * selection contexts}. + */ +interface IInternalEMFSelectionContext { + + void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier); + + URI getToken(Object object); + + Object resolveToken(URI token); + + class Default implements IInternalEMFSelectionContext { + + Supplier<? extends ResourceSet> resourceSetSupplier; + + Default() { + super(); + } + + @Override + public void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier) { + this.resourceSetSupplier = Suppliers.memoize(resourceSetSupplier); + } + + @Override + public URI getToken(Object object) { + return (object instanceof EObject) ? EcoreUtil.getURI((EObject) object) : null; + } + + @Override + public Object resolveToken(URI token) { + ResourceSet rset = (resourceSetSupplier == null) ? null : resourceSetSupplier.get(); + return (rset == null) ? null : rset.getEObject(token, true); + } + + } + + class Composite extends Default { + + private final CompositeReloadContext composite; + + Composite(CompositeReloadContext composite) { + super(); + + this.composite = composite; + } + + @Override + public void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier) { + super.setResourceSetSupplier(resourceSetSupplier); + + for (Object next : composite.getReloadContexts()) { + IInternalEMFSelectionContext emfContext = AdapterUtils.adapt(next, IInternalEMFSelectionContext.class, null); + if (emfContext != null) { + // Pass along the memoizer so that we can all share it + emfContext.setResourceSetSupplier(this.resourceSetSupplier); + } + } + } + } + + class Delegating extends Default { + + private final DelegatingReloadContext delegating; + + Delegating(DelegatingReloadContext delegating) { + super(); + + this.delegating = delegating; + } + + @Override + public void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier) { + super.setResourceSetSupplier(resourceSetSupplier); + + IInternalEMFSelectionContext emfContext = AdapterUtils.adapt(delegating.getDelegate(), IInternalEMFSelectionContext.class, null); + if (emfContext != null) { + // Pass along the memoizer so that we can all share it + emfContext.setResourceSetSupplier(this.resourceSetSupplier); + } + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java new file mode 100644 index 00000000000..f3449f59be9 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + + +/** + * An adapter protocol for objects that can provide {@code context}s to be included in the + * re-load state of dependent parts in an {@link EditorReloadEvent}, for the purpose of + * restoring the state of those objects after re-load has completed. + */ +public interface IReloadContextProvider { + + /** + * Creates an opaque token from which the receiver can be {@linkplain #restore(Object) restored} after the editor has reloaded. + * + * @return an opaque editor re-load context, or {@code null} if none is needed on this occasion (for example because the receiver + * is in its default state) + */ + Object createReloadContext(); + + /** + * Reloads the receiver's state from a token previously {@linkplain #createReloadContext() provided}. + * + * @param reloadContext + * the opaque re-load context token + */ + void restore(Object reloadContext); +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java new file mode 100644 index 00000000000..15d58b5c4a1 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import java.util.List; + +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; + +import com.google.common.collect.Lists; + +/** + * A convenient context object for {@link IEditorReloadListener}s to store in an {@link EditorReloadEvent} to capture and restore + * the selection state a selection provider; + * + * @param <V> + * the type of selection provider + * @param <T> + * the type of token used to restore the selection state + */ +public abstract class SelectionContext<V extends ISelectionProvider, T> { + + private List<T> selection = Lists.newArrayList(); + + public SelectionContext(V structuredSelectionProvider) { + for (Object next : ((IStructuredSelection) structuredSelectionProvider.getSelection()).toList()) { + T token = token(next); + if (token != null) { + selection.add(token); + } + } + } + + public void restore(V structuredSelectionProvider) { + List<Object> select = Lists.newArrayListWithCapacity(selection.size()); + for (T next : selection) { + Object resolved = resolve(next); + if (resolved != null) { + select.add(resolved); + } + } + setSelection(structuredSelectionProvider, select); + } + + T token(Object selectableElement) { + Object deresolved = deresolveSelectableElement(selectableElement); + return (deresolved == null) ? null : getToken(deresolved); + } + + protected Object deresolveSelectableElement(Object selectableElement) { + return selectableElement; + } + + protected abstract T getToken(Object object); + + Object resolve(T token) { + Object deresolved = resolveToken(token); + return (deresolved == null) ? null : resolveSelectableElement(deresolved); + } + + protected Object resolveSelectableElement(Object deresolved) { + return deresolved; + } + + protected abstract Object resolveToken(T token); + + protected void setSelection(V structuredSelectionProvider, List<?> selection) { + structuredSelectionProvider.setSelection(new StructuredSelection(selection)); + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java new file mode 100644 index 00000000000..6d70788326c --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.editor.reload; + +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.viewers.AbstractTreeViewer; +import org.eclipse.jface.viewers.StructuredSelection; + +import com.google.common.collect.Lists; + +/** + * A convenient context object for {@link IEditorReloadListener}s to store in an {@link EditorReloadEvent} to capture and restore + * the expansion and selection state of nodes in a tree viewer. + */ +public abstract class TreeViewerContext<T> extends SelectionContext<AbstractTreeViewer, T> { + + private List<T> expandedNodes = Lists.newArrayList(); + + public TreeViewerContext(AbstractTreeViewer viewer) { + super(viewer); + + for (Object next : viewer.getExpandedElements()) { + T token = token(next); + if (token != null) { + expandedNodes.add(token); + } + } + } + + @Override + public void restore(AbstractTreeViewer viewer) { + List<Object> expand = Lists.newArrayListWithCapacity(expandedNodes.size()); + for (T next : expandedNodes) { + Object resolved = resolve(next); + if (resolved != null) { + expand.add(resolved); + } + } + setExpandedElements(viewer, expand); + + super.restore(viewer); + } + + @Override + protected void setSelection(AbstractTreeViewer viewer, List<?> selection) { + viewer.setSelection(new StructuredSelection(selection), true); + } + + protected void setExpandedElements(AbstractTreeViewer viewer, Collection<?> toExpand) { + viewer.setExpandedElements(toExpand.toArray()); + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java new file mode 100644 index 00000000000..182c962b822 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java @@ -0,0 +1,57 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+
+/**
+ * Factory used to get the Icon associated to the editor used to render the
+ * specified pageIdentifier.
+ *
+ *
+ * @author cedric dumoulin
+ *
+ */
+public interface IEditorFactory {
+
+ /**
+ * Create the {@link IPageModel} for the specified identifier. TODO throw an
+ * exception encapsulating problems encountered while creating the model.
+ *
+ * @param pageIdentifier
+ * Object identifying an Editor.
+ * @return PageModel allowing to create the editor.
+ */
+ public IPageModel createIPageModel(Object pageIdentifier);
+
+ /**
+ * Return true if the factory can create an IPageModel for the specified
+ * pageIdentifier. Return false otherwise TODO throw an exception
+ * encapsulating problems encountered while creating the model.
+ *
+ * @param pageIdentifier
+ * The object representing the page to test
+ * @return
+ */
+ public boolean isPageModelFactoryFor(Object pageIdentifier);
+
+ /**
+ * The ID of this factory
+ *
+ * @return
+ */
+ default String getFactoryID() {
+ return getClass().getName();
+ }
+
+ /**
+ * The display label of this factory
+ *
+ * @return
+ */
+ default String getLabel() {
+ return getClass().getSimpleName();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java new file mode 100644 index 00000000000..9ccf1af0cfe --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java @@ -0,0 +1,64 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelMngr;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Factory used to create an {@link IPageModel} used by the {@link ISashWindowsContainer} to create an instance of the editor represented
+ * by the provided Object. Such factory is required by the {@link DiSashModelMngr}. It is called whenever the ISashWindowsContainer need
+ * to create an editor from an EObject representing this editor in the Di
+ * implementation of the {@link ISashWindowsContentProvider}
+ *
+ *
+ * @author cedric dumoulin
+ *
+ */
+public interface IEditorIconFactory {
+
+ /**
+ * Get the icon associated to the editor used to render the model. Model
+ * represent the top level object of a model editor. Can return a cached
+ * Image.
+ *
+ * @param pageIdentifier
+ * the pageIdentifier representing the Editor. This is usually
+ * the EObject used to reconstruct the editor.
+ * @return the icon representing the editor
+ */
+ public Image getEditorIcon(Object pageIdentifier);
+
+ /**
+ * Create the icon associated to the editor used to render the model. Model
+ * represent the top level object of a model editor. Always return a newly
+ * created Image.
+ *
+ * @param pageIdentifier
+ * the pageIdentifier representing the Editor. This is usually
+ * the EObject used to reconstruct the editor.
+ * @return the icon representing the editor
+ */
+ public Image createEditorIcon(Object pageIdentifier);
+
+ /**
+ * Return true if the factory can create an IPageModel for the specified
+ * pageIdentifier. Return false otherwise TODO throw an exception
+ * encapsulating problems encountered while creating the model.
+ *
+ * @param pageIdentifier
+ * The object representing the page to test
+ * @return
+ */
+ public boolean isPageModelFactoryFor(Object pageIdentifier);
+
+ /**
+ * Dispose this factory
+ */
+ public void dispose();
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java new file mode 100644 index 00000000000..06d9344e865 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java @@ -0,0 +1,30 @@ +/**
+ * Copyright (c) 2011 Atos.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Atos - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+/**
+ *
+ * @author "Arthur Daussy <a href="mailto:arthur.daussy@atos.net">arthur.daussy@atos.net</a>"
+ *
+ */
+public interface IEditorIconFactoryExtended extends IEditorIconFactory {
+
+ /**
+ * Return the icon URL associated to the editor used to render the model. Model represent the top level
+ * object of a model editor.
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ public String getURLMainIcon(Object pageIdentifier);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java new file mode 100644 index 00000000000..6b117ecbeaa --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java @@ -0,0 +1,40 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Registry used to get Icons associated to an editor.
+ *
+ * @author cedric dumoulin
+ */
+public interface IPageIconsRegistry {
+
+ /**
+ * Get the icon associated to the editor used to render the model. Model
+ * represent the top level object of a model editor.
+ *
+ * @param model
+ * the model representing the Editor. This is usually the EObject
+ * used to reconstruct the editor.
+ * @return the icon representing the editor
+ */
+ public Image getEditorIcon(Object model);
+
+ /**
+ * Dispose this registry
+ */
+ public void dispose();
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java new file mode 100644 index 00000000000..c8153b3bef4 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java @@ -0,0 +1,32 @@ +/**
+ * Copyright (c) 2011 Atos Origin.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Atos Origin - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+/**
+ * Extends IPageIconsRegistry in order to offer a second methods which will give back the URL of the requested Icon
+ *
+ * @author "Arthur Daussy <a href="mailto:arthur.daussy@atos.net">arthur.daussy@atos.net</a>"
+ *
+ */
+public interface IPageIconsRegistryExtended extends IPageIconsRegistry {
+
+ /**
+ * Get the URL icon associated to the editor used to render the model. Model represent the top level
+ * object of a model editor.
+ *
+ * @param model
+ * @return {@link String} which represent the URL of the resource
+ */
+ public String getEditorURLIcon(Object model);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java new file mode 100644 index 00000000000..d60e8f71f96 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java @@ -0,0 +1,118 @@ +/** + * + */ +package org.eclipse.papyrus.infra.ui.editorsfactory; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.graphics.Image; + +/** + * Concrete implementation of the {@link IPageIconsRegistry}. This + * implementation allows to add and remove {@link IPageIconsRegistry}. + * + * + * @author cedric dumoulin + */ +public class PageIconsRegistry implements IPageIconsRegistryExtended { + + /** list of registered icon factories */ + protected List<IEditorIconFactory> pageIcons = new ArrayList<IEditorIconFactory>(); + + /** + * Constructor. + * + * @param editorFactoryRegistry + * @param servicesRegistry + */ + public PageIconsRegistry() { + + } + + /** + * Walk each registered {@link IEditorFactory} to find the one handling the + * specified pageIdentifier. Call the corresponding method in the found + * pageIdentifier. + * + * TODO Throw an exception to report errors. + * + * @see org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory#createIPageModel(java.lang.Object) + */ + @Override + public Image getEditorIcon(Object pageIdentifier) { + + for (IEditorIconFactory factory : getPageIcons()) { + if (factory.isPageModelFactoryFor(pageIdentifier)) { + { + // return factory.getEditorIcon(pageIdentifier); + return factory.getEditorIcon(pageIdentifier); + } + } + } + // no editor found ! + // TODO Throw an exception. + // throw new EditorNotFoundException("No editor registered for '" + + // pageIdentifier + "'."); + return null; + } + + /** + * @return the editorFactories + */ + protected List<IEditorIconFactory> getPageIcons() { + return pageIcons; + } + + /** + * Add the specified {@link IEditorFactory} + * + * @param editorIconFactory + */ + public void add(IEditorIconFactory editorIconFactory) { + // This should never happen + if (editorIconFactory == null) { + throw new RuntimeException("Parameter should not be null."); //$NON-NLS-1$ + } + + pageIcons.add(editorIconFactory); + } + + /** + * Remove the specified {@link IEditorFactory} + * + * @param editorIconFactory + */ + public void remove(IEditorIconFactory editorIconFactory) { + pageIcons.remove(editorIconFactory); + } + + /** + * Return the path to the icon ressource. + * + * @see org.eclipse.papyrus.infra.ui.editorsfactory.IPageIconsRegistryExtended#getEditorURLIcon(java.lang.Object) + * + * @param model + * @return + */ + @Override + public String getEditorURLIcon(Object model) { + for (IEditorIconFactory factory : getPageIcons()) { + if (factory.isPageModelFactoryFor(model)) { + { + if (factory instanceof IEditorIconFactoryExtended) { + return ((IEditorIconFactoryExtended) factory).getURLMainIcon(model); + } + } + } + } + return ""; + } + + @Override + public void dispose() { + for (IEditorIconFactory factory : pageIcons) { + factory.dispose(); + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java new file mode 100644 index 00000000000..32774bb7a25 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java @@ -0,0 +1,165 @@ +/***************************************************************************** + * Copyright (c) 2009 - 2015 CEA LIST & LIFL + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation + * Camille Letavernier (CEA LIST) - camille.letavernier@cea.fr - Bug 476625 + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.editorsfactory; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel; +import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider; +import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory; +import org.eclipse.papyrus.infra.ui.Activator; + +/** + * Concrete implementation of the {@link IPageModelFactory} required by the di + * implementation of {@link ISashWindowsContentProvider}. This implementation + * allows to add and remove {@link IEditorFactory}. + * + * + * @author cedric dumoulin + */ +public class PageModelFactoryRegistry implements IPageModelFactory { + + /** ordered list of editor factories */ + protected List<IEditorFactory> editorFactories = new ArrayList<IEditorFactory>(); + + /** + * Constructor. + * + * @param editorFactoryRegistry + * @param servicesRegistry + */ + public PageModelFactoryRegistry() { + + } + + /** + * Walk each registered {@link IEditorFactory} to find the one handling the + * specified pageIdentifier. Call the corresponding method in the found + * pageIdentifier. + * + * TODO Throw an exception to report errors. + * + * @see org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory#createIPageModel(java.lang.Object) + */ + @Override + public IPageModel createIPageModel(Object pageIdentifier) { + return createIPageModel(pageIdentifier, null); + } + + /** + * Walk each registered {@link IEditorFactory} to find the one handling the + * specified pageIdentifier. Call the corresponding method in the found + * pageIdentifier. + * + * If several factories match the selected page, use the favorite editor. + * If the favorite editor is not available, use the priority mechanism + * + * @see org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory#createIPageModel(java.lang.Object) + */ + @Override + public IPageModel createIPageModel(Object pageIdentifier, String favoriteEditorID) { + + IEditorFactory factory = getFactoryFor(pageIdentifier, favoriteEditorID); + if (factory == null) { + return null; + } + return factory.createIPageModel(pageIdentifier); + } + + /** + * Returns the IEditorFactory for the given pageIdentifier. + * + * If several factories match the page identifier, use the favorite one + * + * @param pageIdentifier + * @return + */ + private IEditorFactory getFactoryFor(Object pageIdentifier, String favoriteEditorID) { + List<IEditorFactory> matchingFactories = new LinkedList<>(); + + for (IEditorFactory factory : getEditorFactories()) { + if (factory.isPageModelFactoryFor(pageIdentifier)) { + matchingFactories.add(factory); + } + } + + if (matchingFactories.isEmpty()) { + return null; + } else if (matchingFactories.size() == 1) { + return matchingFactories.get(0); + } else if (favoriteEditorID != null) { + for (IEditorFactory matchingFactory : matchingFactories) { + if (favoriteEditorID.equals(matchingFactory.getFactoryID())) { + return matchingFactory; + } + } + } + + return matchingFactories.get(0); + } + + /** + * @see org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory#getEditorIDsFor(java.lang.Object) + * + * @param pageIdentifier + * @return + */ + @Override + public Map<String, String> getEditorIDsFor(Object pageIdentifier) { + return getEditorFactories().stream() + .filter(f -> f.isPageModelFactoryFor(pageIdentifier)) + .collect(Collectors + .toMap( + f -> f.getFactoryID(), f -> f.getLabel(), // key, value + (v1, v2) -> { // Conflict merger + Activator.log.warn(String.format("Several editors are declared with the same ID: '%s', '%s'", v1, v2)); + return v1; // Any value + } , + LinkedHashMap::new)); // HashMap Supplier + } + + /** + * @return the editorFactories + */ + protected List<IEditorFactory> getEditorFactories() { + return editorFactories; + } + + /** + * Add the specified {@link IEditorFactory} + * + * @param editorFactory + */ + public void add(IEditorFactory editorFactory) { + // This should never happen + if (editorFactory == null) { + throw new IllegalArgumentException("Parameter should not be null."); //$NON-NLS-1$ + } + + editorFactories.add(editorFactory); + } + + /** + * Remove the specified {@link IEditorFactory} + * + * @param editorFactory + */ + public void remove(IEditorFactory editorFactory) { + editorFactories.remove(editorFactory); + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java new file mode 100644 index 00000000000..cbb70c2e4e1 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java @@ -0,0 +1,135 @@ +/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 392301
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editorsfactory.anytype;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.xml.type.AnyType;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IComponentModel;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.infra.ui.extension.diagrameditor.AbstractEditorFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * An EditorFactory for "AnyType", i.e. EObject deserialized from unknown Packages
+ *
+ * Allows recovery and manipulation of models containing optional EMF components
+ *
+ * @author Camille Letavernier
+ */
+public class AnyTypeEditorFactory extends AbstractEditorFactory {
+
+ public AnyTypeEditorFactory() {
+ super(null, "AnyTypeHandler");
+ }
+
+ @Override
+ public IPageModel createIPageModel(Object pageIdentifier) {
+
+ final AnyType anyTypeModel = (AnyType) pageIdentifier;
+
+ return new IComponentModel() {
+
+ private AnyType anyType = anyTypeModel;
+
+ @Override
+ public void dispose() {
+ // Pass. The tab icon is a workbench-shared image
+ }
+
+ @Override
+ public String getTabTitle() {
+ EClass eClass = anyType.eClass();
+ String label;
+ if (eClass == null) {
+ label = "component";
+ } else {
+ label = eClass.getName();
+ }
+ return "Missing " + label;
+ }
+
+ private String getTypeLabel() {
+ EClass eClass = anyType.eClass();
+ String className = eClass == null ? "None" : eClass.getName();
+ return className;
+ }
+
+ private String getNsURI() {
+ EClass eClass = anyType.eClass();
+ EPackage ePackage = eClass == null ? null : eClass.getEPackage();
+ String ePackageName = ePackage == null ? "None" : ePackage.getNsURI();
+
+ return ePackageName;
+ }
+
+ public Image getComponentIcon() {
+ return Display.getDefault().getSystemImage(SWT.ICON_WARNING);
+ }
+
+ @Override
+ public Image getTabIcon() {
+ return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK);
+ }
+
+ @Override
+ public Object getRawModel() {
+ return anyType;
+ }
+
+ public String getErrorText() {
+ String typeLabel = getTypeLabel();
+ String packageURI = getNsURI();
+ String message = "A component is missing. The following Model cannot be loaded: " + typeLabel + " (from " + packageURI + ")\n";
+ message += "Changes to the model won't be reflected in this editor. This editor will be saved in the current state, i.e. without any data loss. ";
+ message += "However, this may result in an inconsistent state of this editor when the missing component will be restored\n";
+ return message;
+ }
+
+ @Override
+ public Composite createPartControl(Composite parent) {
+ Composite tabComposite = new Composite(parent, SWT.NONE);
+ tabComposite.setLayout(new GridLayout(2, false));
+
+ Image componentIcon = getComponentIcon();
+ if (componentIcon != null) {
+ Label errorImageLabel = new Label(tabComposite, SWT.NONE);
+ errorImageLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+ errorImageLabel.setImage(componentIcon);
+ }
+
+ Label label = new Label(tabComposite, SWT.WRAP);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ label.setText(getErrorText());
+
+ return tabComposite;
+ }
+ };
+ }
+
+ @Override
+ public boolean isPageModelFactoryFor(Object pageIdentifier) {
+ return pageIdentifier instanceof AnyType;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java new file mode 100644 index 00000000000..575b769e3ec --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java @@ -0,0 +1,36 @@ +/*****************************************************************************
+ * Copyright (c) 2009 ATOS ORIGIN.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Tristan Faure (ATOS ORIGIN) tristan.faure@atosorigin.com - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.commands;
+
+import org.eclipse.emf.ecore.EObject;
+
+public interface ICreationCondition {
+
+ /**
+ * This method returns true if the diagram creation is allowed
+ *
+ * @param selectedElement
+ * the element where the diagram is provided
+ * @return true if the diagram can be created
+ */
+ boolean create(EObject selectedElement);
+
+ /**
+ * set the command ID in order to take account the environment in order to
+ * create a diagram
+ *
+ * @param commandID
+ */
+ public void setCommand(String commandID);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java new file mode 100644 index 00000000000..beb200f6086 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java @@ -0,0 +1,31 @@ +/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tatiana Fesenko (CEA LIST) - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.commands;
+
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+
+/**
+ * The Interface IModelCreationCommand.
+ */
+public interface IModelCreationCommand {
+
+ /**
+ * Creates the model.
+ *
+ * @param modelSet
+ * the modelSet set
+ */
+ void createModel(final ModelSet modelSet);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java new file mode 100644 index 00000000000..7d6d993c982 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java @@ -0,0 +1,51 @@ +/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.commands;
+
+import org.eclipse.emf.ecore.EObject;
+
+//FIXME Refactoring Juno : I don't know how to migrate this code
+public class PerspectiveContextDependence implements ICreationCondition {
+
+ protected String commandID = null;
+
+ public PerspectiveContextDependence() {
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean create(EObject selectedElement) {
+ // FIXME Refactoring Juno : I don't know how to migrate this code
+ // // Get the perspective
+ // Perspective perspective = ((WorkbenchPage)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()).getActivePerspective();
+ // // look for the perspective
+ // // verify if the command has to be displayed
+ // if(perspective.getHiddenMenuItems().contains(commandID) && perspective.getHiddenToolbarItems().contains(commandID)) {
+ // return false;
+ // }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setCommand(String commandID) {
+ this.commandID = commandID;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java new file mode 100644 index 00000000000..bde8a69767e --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java @@ -0,0 +1,109 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory;
+
+/**
+ * Abstract base class for Factory of editors. See {@link IEditorFactory}.
+ *
+ *
+ * @author Remi Schnekenburger
+ * @author Patrick Tessier
+ * @author cedric dumoulin
+ */
+public abstract class AbstractEditorFactory implements IPluggableEditorFactory {
+
+ /**
+ * Expected Class of the diagram to create.
+ */
+ private Class<?> diagramClass;
+
+ /** Expected diagram type (@see {@link Diagram#getType()}) */
+ private String expectedType;
+
+ /**
+ * EditorDescriptor associated to the factory. TODO : Maybe use individual
+ * setters to set the requested data (ContributorId and Icon).
+ */
+ protected EditorDescriptor editorDescriptor;
+
+ /**
+ * ServiceRegistry that can be provided to created editors.
+ */
+ private ServicesRegistry serviceRegistry;
+
+ /**
+ * Creates a new AbstractEditorFactory.
+ *
+ * @param diagramClass
+ * expected Class of the diagram to create.
+ * @param expectedType
+ * expected diagram type (@see {@link Diagram#getType()})
+ */
+ public AbstractEditorFactory(Class<?> diagramClass, String expectedType) {
+ assert (expectedType != null);
+ this.diagramClass = diagramClass;
+ this.expectedType = expectedType;
+ }
+
+ /**
+ * Initialize the factory with useful Classes.
+ *
+ * @param serviceRegistry
+ * Service registry that will be provided to created editor.
+ * @param editorDescriptor
+ * Descriptor containing data from the Eclipse Extension.
+ */
+ @Override
+ public void init(ServicesRegistry serviceRegistry, EditorDescriptor editorDescriptor) {
+ this.editorDescriptor = editorDescriptor;
+ this.serviceRegistry = serviceRegistry;
+
+ }
+
+ /**
+ * @return the serviceRegistry
+ */
+ public ServicesRegistry getServiceRegistry() {
+ return serviceRegistry;
+ }
+
+ /**
+ * Returns the expected class for the diagram implementation
+ *
+ * @return the expected class for the diagram implementation
+ */
+ public Class<?> getDiagramClass() {
+ return diagramClass;
+ }
+
+ /**
+ * Returns the expected type of the diagram
+ *
+ * @return the expected diagram type (@see {@link Diagram#getType()})
+ */
+ public String getExpectedType() {
+ return expectedType;
+ }
+
+ /**
+ * @return the editorDescriptor
+ */
+ public EditorDescriptor getEditorDescriptor() {
+ return editorDescriptor;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java new file mode 100644 index 00000000000..502360c09d7 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java @@ -0,0 +1,168 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * This descriptor describes a nested diagram. It is used by MultiDiagramEditor
+ * to know about the nested diagram. It is fill by an extension.
+ *
+ * @author Cedric Dumoulin
+ *
+ */
+public class EditorDescriptor {
+
+ /**
+ * Editor factory implementation class.
+ */
+ private Class<IPluggableEditorFactory> editorFactoryClass;
+
+ /**
+ * EditorActionBarContributor Id used to search the
+ * EditorActionBarContributor requested by the editor.
+ */
+ private String actionBarContributorId;
+
+ /**
+ * The icon representing the diagram
+ */
+ private ImageDescriptor icon;
+
+ /**
+ * Resource path to the icon
+ */
+ private String iconPath;
+
+ /**
+ * The order of this factory. Used when several factories match the same element (Diagram...)
+ * The lower the order, the higher the priority of this factory
+ */
+ private int order;
+
+ /**
+ * Constructor.
+ */
+ public EditorDescriptor() {
+
+ }
+
+ /**
+ *
+ * @param attribute
+ */
+ public void setActionBarContributorId(String actionBarContributorId) {
+ this.actionBarContributorId = actionBarContributorId;
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.extension.diagrameditor.IEditorDescriptor#getActionBarContributorId()
+ * @return
+ *
+ */
+ public String getActionBarContributorId() {
+ return actionBarContributorId;
+ }
+
+ /**
+ * get the editor icon path
+ *
+ * @return the editor icon path
+ */
+ public ImageDescriptor getIcon() {
+ return icon;
+ }
+
+ /**
+ * set the editor icon
+ *
+ * @param icon
+ * the icon path
+ */
+ public void setIcon(ImageDescriptor icon) {
+ this.icon = icon;
+ }
+
+ /**
+ * get the class of the editor factory
+ *
+ * @return the class of the editor
+ */
+ public Class<IPluggableEditorFactory> getEditorFactoryClass() {
+ return editorFactoryClass;
+ }
+
+ /**
+ * set the editor facoty to this descriptor
+ *
+ * @param editorFactoryClass
+ * the class that represents the editor factory
+ */
+ public void setEditorFactoryClass(Class<IPluggableEditorFactory> editorFactoryClass) {
+ this.editorFactoryClass = editorFactoryClass;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ if (editorFactoryClass == null || editorFactoryClass.getName() == null) {
+ return "[nestedEditor editorFactory:" + editorFactoryClass + "(null)]";
+ }
+ return "[nestedEditor editorFactory:" + editorFactoryClass.getName() + "]";
+ }
+
+ public int getOrder() {
+ return order;
+ }
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ /**
+ * Set the URL of the Icon
+ *
+ * @param iconPath
+ * path of the Icon
+ */
+ public void setIconURL(String iconPath) {
+ this.iconPath = iconPath;
+ }
+
+ /**
+ * Get the URL of the based images
+ *
+ * @return the path of the mai image. can return null if this property is not set
+ */
+ public String getIconURL() {
+ return iconPath;
+ }
+
+ /**
+ * set the Icon thanks to a {@link IConfigurationElement} and {@link String}which represent the path of the Icon
+ *
+ * @param element
+ * @param iconPath
+ */
+ public void setIcon(IConfigurationElement element, String iconPath, String pluginID) {
+ setIcon(AbstractUIPlugin.imageDescriptorFromPlugin(element.getNamespaceIdentifier(), iconPath));
+ setIconURL(element.getNamespaceIdentifier() + '/' + iconPath);
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java new file mode 100644 index 00000000000..8d57b2fe3ab --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java @@ -0,0 +1,99 @@ +/***************************************************************************** + * Copyright (c) 2008 CEA LIST. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.extension.diagrameditor; + +import static org.eclipse.papyrus.infra.core.Activator.log; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.papyrus.infra.core.extension.BadNameExtensionException; +import org.eclipse.papyrus.infra.core.extension.ExtensionException; +import org.eclipse.papyrus.infra.core.extension.ExtensionUtils; +import org.eclipse.papyrus.infra.ui.Activator; + +/** + * A factory used to create editor descriptor object from Eclipse extensions points elements. + * + * @author Cedric Dumoulin + * @author Patrick Tessier + */ +public class EditorDescriptorExtensionFactory extends ExtensionUtils { + + /** singleton eINSTANCE of this class */ + public final static EditorDescriptorExtensionFactory eINSTANCE = new EditorDescriptorExtensionFactory(); + + /** constant for the editor diagram **/ + public final static String EDITOR_DIAGRAM_EXTENSIONPOINT = "editorDiagram"; + + /** constant for the attribute factoryClass **/ + public final static String FACTORYCLASS_ATTRIBUTE = "factoryClass"; + + /** constant for the attribute contextId **/ + public final static String ACTIONBARCONTRIBUTORID_ATTRIBUTE = "actionBarContributorId"; + + /** constant for the attribute icon **/ + public final static String ICON_ATTRIBUTE = "icon"; + + /** constant for the order attribute */ + public final static String ORDER_ATTRIBUTE = "order"; + + /** + * @return the eINSTANCE + */ + public static EditorDescriptorExtensionFactory getInstance() { + return eINSTANCE; + } + + /** + * Create a descriptor instance corresponding to the ConfigurationElement. + * + * @param element + * an {@link IConfigurationElement} see eclipse extension point + * @return a nestedEditorDescriptor structure that contains information to create diagrams + * @throws BadNameExtensionException + */ + @SuppressWarnings("unchecked") + public EditorDescriptor createNestedEditorDescriptor(IConfigurationElement element) throws ExtensionException { + EditorDescriptor res; + + checkTagName(element, EDITOR_DIAGRAM_EXTENSIONPOINT); + + res = new EditorDescriptor(); + res.setEditorFactoryClass((Class<IPluggableEditorFactory>) parseClass(element, FACTORYCLASS_ATTRIBUTE, EDITOR_DIAGRAM_EXTENSIONPOINT)); + res.setActionBarContributorId(element.getAttribute(ACTIONBARCONTRIBUTORID_ATTRIBUTE)); + + int order = 0; // Default + try { + String orderAttribute = element.getAttribute(ORDER_ATTRIBUTE); + if (orderAttribute != null) { + order = Integer.parseInt(orderAttribute); + } + } catch (NumberFormatException ex) { + Activator.log.warn("Invalid order provided by " + element.getContributor() + ". Order should be an integer value"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + res.setOrder(order); + + String iconPath = element.getAttribute(ICON_ATTRIBUTE); + if (iconPath != null) { + /** Implementation which set the icon and register the complete URL of the icon : Bug eclipse 358732 */ + res.setIcon(element, iconPath, Activator.PLUGIN_ID); + + } + + if (log.isDebugEnabled()) { + log.debug("Read editor descriptor " + res); //$NON-NLS-1$ + } + return res; + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java new file mode 100644 index 00000000000..05fafa58c5d --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java @@ -0,0 +1,137 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory;
+
+/**
+ * A proxy implementation of {@link IEditorFactory} used to do lazy
+ * instantiation of concrete {@link IPluggableEditorFactory}. This class is used
+ * by the {@link PluggableEditorFactoryReader}
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class EditorFactoryProxy implements IEditorFactory {
+
+ /**
+ * The concrete implementation.
+ */
+ private IPluggableEditorFactory editorFactory;
+
+ /**
+ * EditorDescriptor associated to the factory.
+ */
+ protected EditorDescriptor editorDescriptor;
+
+ /**
+ * ServiceRegistry that can be provided to created editors.
+ */
+ private ServicesRegistry serviceRegistry;
+
+ /**
+ * Constructor.
+ *
+ * @param serviceRegistry
+ * @param editorDescriptor
+ */
+ public EditorFactoryProxy(ServicesRegistry serviceRegistry, EditorDescriptor editorDescriptor) {
+ this.serviceRegistry = serviceRegistry;
+ this.editorDescriptor = editorDescriptor;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#createIPageModel(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public IPageModel createIPageModel(Object pageIdentifier) {
+ try {
+ return getEditorFactory().createIPageModel(pageIdentifier);
+ } catch (Exception ex) {
+ // An error occurred in a contribution. Do not use this factory
+ return null;
+ }
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#isPageModelFactoryFor(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public boolean isPageModelFactoryFor(Object pageIdentifier) {
+ try {
+ return getEditorFactory().isPageModelFactoryFor(pageIdentifier);
+ } catch (Exception ex) {
+ // An error occurred in a contribution. Do not use this factory
+ return false;
+ }
+ }
+
+ /**
+ * @return the editorFactory
+ */
+ protected IPluggableEditorFactory getEditorFactory() {
+
+ if (editorFactory == null) {
+ editorFactory = createEditorFactory();
+ }
+
+ return editorFactory;
+
+ }
+
+ /**
+ * Create an instance of IPluggableEditorFactory as described in the
+ * editorDescriptor. TODO let propagate the exceptions.
+ *
+ * @return
+ */
+ private IPluggableEditorFactory createEditorFactory() {
+ // Create the requested class.
+ try {
+ editorFactory = editorDescriptor.getEditorFactoryClass().newInstance();
+ // Set the descriptor. USed by the factory to get the ActionBarId
+ // and Icon
+ editorFactory.init(serviceRegistry, editorDescriptor);
+ return editorFactory;
+ } catch (InstantiationException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#getFactoryID()
+ *
+ * @return
+ */
+ @Override
+ public String getFactoryID() {
+ return getEditorFactory().getFactoryID();
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#getLabel()
+ *
+ * @return
+ */
+ @Override
+ public String getLabel() {
+ return getEditorFactory().getLabel();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java new file mode 100644 index 00000000000..6449012db9b --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java @@ -0,0 +1,152 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IEditorIconFactoryExtended;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * A factory used to create the Icon associated to an editor TODO Lets have a
+ * common ancestor for {@link EditorIconFactory} and {@link EditorFactoryProxy}
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class EditorIconFactory implements IEditorIconFactoryExtended {
+
+ /**
+ * The concrete implementation.
+ */
+ private IPluggableEditorFactory editorFactory;
+
+ /**
+ * EditorDescriptor associated to the factory.
+ */
+ protected EditorDescriptor editorDescriptor;
+
+ /**
+ * Cached image for reuse.
+ */
+ protected Image cachedImage;
+
+ /**
+ * Constructor.
+ *
+ * @param serviceRegistry
+ * @param editorDescriptor
+ */
+ public EditorIconFactory(EditorDescriptor editorDescriptor) {
+ this.editorDescriptor = editorDescriptor;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorIconFactory#getEditorIcon(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public Image getEditorIcon(Object pageIdentifier) {
+
+ if (cachedImage == null) {
+ cachedImage = createEditorIcon(pageIdentifier);
+ }
+
+ return cachedImage;
+ }
+
+ /**
+ * Create an Image associated to the editor used to render the specified
+ * pageIdentifier
+ *
+ * @return
+ */
+ @Override
+ public Image createEditorIcon(Object pageIdentifier) {
+ ImageDescriptor imageDescriptor = editorDescriptor.getIcon();
+ if (imageDescriptor == null) {
+ return null;
+ }
+ Image image = imageDescriptor.createImage();
+ return image;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#isPageModelFactoryFor(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public boolean isPageModelFactoryFor(Object pageIdentifier) {
+ return getEditorFactory().isPageModelFactoryFor(pageIdentifier);
+ }
+
+ /**
+ * @return the editorFactory
+ */
+ protected IPluggableEditorFactory getEditorFactory() {
+
+ if (editorFactory == null) {
+ editorFactory = createEditorFactory();
+ }
+
+ return editorFactory;
+
+ }
+
+ /**
+ * Create an instance of IPluggableEditorFactory as described in the
+ * editorDescriptor. TODO let propagate the exceptions.
+ *
+ * @return
+ */
+ private IPluggableEditorFactory createEditorFactory() {
+ // Create the requested class.
+ try {
+ editorFactory = editorDescriptor.getEditorFactoryClass().newInstance();
+ // Set the descriptor. USed by the factory to get the ActionBarId
+ // and Icon
+ // editorFactory.init(serviceRegistry, editorDescriptor);
+ return editorFactory;
+ } catch (InstantiationException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ /**
+ * Return the URL of the main icon used to create this icon
+ *
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorIconFactory#getURLMainIcon(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public String getURLMainIcon(Object pageIdentifier) {
+ return editorDescriptor.getIconURL();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Dispose the cached image
+ */
+ @Override
+ public void dispose() {
+ if (cachedImage != null) {
+ cachedImage.dispose();
+ cachedImage = null;
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java new file mode 100644 index 00000000000..6600a83af1b --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java @@ -0,0 +1,53 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+/**
+ * Editor was not found.
+ *
+ * @author dumoulin
+ *
+ */
+@SuppressWarnings("serial")
+public class EditorNotFoundException extends MultiDiagramException {
+
+ /**
+ *
+ */
+ public EditorNotFoundException() {
+ }
+
+ /**
+ * @param arg0
+ */
+ public EditorNotFoundException(String arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ */
+ public EditorNotFoundException(Throwable arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public EditorNotFoundException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java new file mode 100644 index 00000000000..ee69f2442a5 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java @@ -0,0 +1,39 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory;
+
+/**
+ * This interface should be implemented by Editor Factories that can be declared
+ * as Eclipse extension. It extends the {@link IEditorFactory} by adding methods
+ * to initialize the factory with multieditor ServiceRegistry and associated
+ * editor data.
+ *
+ * @author C�dric Dumoulin
+ *
+ */
+public interface IPluggableEditorFactory extends IEditorFactory {
+
+ /**
+ * Initialize the factory with useful Classes.
+ *
+ * @param serviceRegistry
+ * Service registry that will be provided to created editor.
+ * @param editorDescriptor
+ * Descriptor containing data from the Eclipse Extension.
+ */
+ public void init(ServicesRegistry serviceRegistry, EditorDescriptor editorDescriptor);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java new file mode 100644 index 00000000000..81f1f7ccac4 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java @@ -0,0 +1,53 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+/**
+ * Root Exception of MultiDiagram exception
+ *
+ * @author dumoulin
+ *
+ */
+@SuppressWarnings("serial")
+public class MultiDiagramException extends Exception {
+
+ /**
+ *
+ */
+ public MultiDiagramException() {
+ }
+
+ /**
+ * @param arg0
+ */
+ public MultiDiagramException(String arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ */
+ public MultiDiagramException(Throwable arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public MultiDiagramException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java new file mode 100644 index 00000000000..75dc1d7cc96 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java @@ -0,0 +1,143 @@ +/***************************************************************************** + * Copyright (c) 2008 CEA LIST. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.extension.diagrameditor; + +import static org.eclipse.papyrus.infra.core.Activator.log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.Platform; +import org.eclipse.papyrus.infra.core.extension.ExtensionException; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.ui.editorsfactory.PageIconsRegistry; +import org.eclipse.papyrus.infra.ui.editorsfactory.PageModelFactoryRegistry; + +/** + * This reader is used to read PluggableEditorFactory from the Eclipse extension + * declarations. It can be used to populate an {@link PageModelFactoryRegistry}. + */ +public class PluggableEditorFactoryReader { + + /** ordered list of editor descriptors */ + protected List<EditorDescriptor> editorDescriptors; + + /** ID of the editor extension (schema filename) */ + public static final String EDITOR_EXTENSION_ID = "papyrusDiagram"; + + /** Namespace where to look for the extension points. */ + protected String extensionPointNamespace; + + /** indicates if extension is loaded or not */ + private boolean isExtensionLoaded = false; + + /** + * Create a new Registry reading extension from the specified namespace. The + * namespace is usually the name of the plugin owning the registry. + * + * @param extensionPointNamespace + */ + public PluggableEditorFactoryReader(String extensionPointNamespace) { + super(); + this.extensionPointNamespace = extensionPointNamespace; + editorDescriptors = new ArrayList<EditorDescriptor>(); + } + + /** + * Populate the provided {@link PageModelFactoryRegistry} with {@link IPluggableEditorFactory} read from Eclipse extension declarations. + * For each declared editor, create a proxy encapsulating the real + * EditorFactory. Then the proxy is added to the PageModelFactoryRegistry. + * + * @param pageModelFactoryRegistry + * The object to populate + * @param serviceRegistry + * ServiceRegistry provided to newly instantiated {@link IPluggableEditorFactory}. + */ + public void populate(PageModelFactoryRegistry pageModelFactoryRegistry, ServicesRegistry serviceRegistry) { + + for (EditorDescriptor desc : getEditorDescriptors()) { + + // Create and add a proxy encapsulating the EditorFactory. + pageModelFactoryRegistry.add(new EditorFactoryProxy(serviceRegistry, desc)); + } + } + + /** + * Populate the provided {@link PageIconsRegistry} with icons read from + * Eclipse extension declarations. For each declared editor, create a {@link EditorIconFactory}. + * + * @param pageModelFactoryRegistry + * The object to populate + * @param serviceRegistry + * ServiceRegistry provided to newly instantiated {@link IPluggableEditorFactory}. + */ + public void populate(PageIconsRegistry registry) { + + for (EditorDescriptor desc : getEditorDescriptors()) { + + // Create and add a proxy encapsulating the EditorFactory. + registry.add(new EditorIconFactory(desc)); + } + } + + /** + * Get the list of editor descriptor. + * + * @return the list of editor descriptor. + */ + public List<EditorDescriptor> getEditorDescriptors() { + if (!isExtensionLoaded) { + isExtensionLoaded = true; + initializeEditorDescriptors(); + } + return editorDescriptors; + } + + /** + * Read editor descriptors from extension points. + */ + private void initializeEditorDescriptors() { + // Reading data from plugins + IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPointNamespace, EDITOR_EXTENSION_ID); + + for (IConfigurationElement ele : configElements) { + EditorDescriptor desc; + try { + if (EditorDescriptorExtensionFactory.EDITOR_DIAGRAM_EXTENSIONPOINT.equals(ele.getName())) { + desc = EditorDescriptorExtensionFactory.eINSTANCE.createNestedEditorDescriptor(ele); + editorDescriptors.add(desc); + } + } catch (ExtensionException e) { + log.error("Initialization editor problem ", e); //$NON-NLS-1$ + } + } + + Collections.sort(editorDescriptors, (ed1, ed2) -> Integer.compare(ed1.getOrder(), ed2.getOrder())); + + if (log.isDebugEnabled()) { + log.debug("Read " + editorDescriptors.size() + " editor descriptors from Eclipse extensions"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "EditorFactoryRegistry: " + editorDescriptors.toString(); + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java new file mode 100644 index 00000000000..6e604a90914 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java @@ -0,0 +1,164 @@ +/***************************************************************************** + * Copyright (c) 2015 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.internal.commands; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.jface.commands.ToggleState; +import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel; +import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModelUtils; +import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IPartService; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * The boolean toggle state of the private page layout storage menu item. + */ +public class PageLayoutStorageState extends ToggleState implements IPartListener, PropertyChangeListener { + + private IPartService partService = null; + + private Reference<IMultiDiagramEditor> activeEditor; + + public PageLayoutStorageState() { + super(); + + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + + if (window != null) { + partService = window.getPartService(); + if (partService != null) { + partService.addPartListener(this); + update(partService.getActivePart()); + } + } + } + + @Override + public void dispose() { + if (partService != null) { + partService.removePartListener(this); + } + + super.dispose(); + } + + @Override + public void partDeactivated(IWorkbenchPart part) { + if ((activeEditor != null) && (activeEditor.get() == part)) { + update(null); + } + } + + @Override + public void partActivated(IWorkbenchPart part) { + update(part); + } + + private void update(IWorkbenchPart part) { + // Default state is private storage + boolean state = true; + + unhookSashModelListener(); + + activeEditor = null; + + if (part instanceof IMultiDiagramEditor) { + IMultiDiagramEditor editor = (IMultiDiagramEditor) part; + activeEditor = new WeakReference<>(editor); + state = isPrivateLayout(editor); + } + + hookSashModelListener(); + + // Fires notification if changed from previous state + setValue(state); + } + + // I am a computed value, actually + @Override + public Object getValue() { + IMultiDiagramEditor editor = (activeEditor == null) ? null : activeEditor.get(); + return (editor != null) ? isPrivateLayout(editor) : super.getValue(); + } + + boolean isPrivateLayout(IMultiDiagramEditor editor) { + ModelSet modelSet = (ModelSet) editor.getAdapter(EditingDomain.class).getResourceSet(); + SashModel sashModel = SashModelUtils.getSashModel(modelSet); + + // The default is private layout + return (sashModel == null) || !sashModel.isLegacyMode(); + } + + @Override + public void partBroughtToTop(IWorkbenchPart part) { + // Pass + } + + @Override + public void partClosed(IWorkbenchPart part) { + // Pass + } + + @Override + public void partOpened(IWorkbenchPart part) { + // Pass + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getSource() instanceof SashModel) { + switch (evt.getPropertyName()) { + case SashModel.PROPERTY_LEGACY_MODE: + setValue(!(Boolean) evt.getNewValue()); + break; + } + } + } + + private SashModel getSashModel() { + SashModel result = null; + + if (activeEditor != null) { + IMultiDiagramEditor editor = activeEditor.get(); + if (editor != null) { + result = SashModelUtils.getSashModel(editor.getServicesRegistry()); + } + } + + return result; + } + + private void unhookSashModelListener() { + SashModel sash = getSashModel(); + if (sash != null) { + sash.removePropertyChangeListener(SashModel.PROPERTY_LEGACY_MODE, this); + } + } + + private void hookSashModelListener() { + SashModel sash = getSashModel(); + if (sash != null) { + sash.addPropertyChangeListener(SashModel.PROPERTY_LEGACY_MODE, this); + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java new file mode 100644 index 00000000000..61c931b1ec4 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java @@ -0,0 +1,226 @@ +/***************************************************************************** + * Copyright (c) 2015 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.internal.commands; + +import java.util.ArrayList; + +import org.eclipse.emf.common.command.AbstractCommand; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.UnexecutableCommand; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModelUtils; +import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer; +import org.eclipse.papyrus.infra.core.sashwindows.di.PageRef; +import org.eclipse.papyrus.infra.core.sashwindows.di.SashModel; +import org.eclipse.papyrus.infra.core.sashwindows.di.SashWindowsMngr; +import org.eclipse.papyrus.infra.core.sashwindows.di.TabFolder; +import org.eclipse.papyrus.infra.core.sashwindows.di.util.DiUtils; +import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor; + +/** + * A factory for commands that manipulate the configuration of the sash editor layout. + */ +public class SashLayoutCommandFactory { + private final IMultiDiagramEditor editor; + + public SashLayoutCommandFactory(IMultiDiagramEditor editor) { + super(); + + this.editor = editor; + } + + /** + * Creates a command that toggles whether the sash model is stored in the private + * workspace metadata area or in the shared {@code *.di} file. + * + * @return a toggle command for the private layout storage + */ + public Command createTogglePrivateLayoutCommand() { + Command result = UnexecutableCommand.INSTANCE; + + ModelSet modelSet = (ModelSet) editor.getAdapter(EditingDomain.class).getResourceSet(); + org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel sashModel = SashModelUtils.getSashModel(modelSet); + if (sashModel != null) { + result = new AbstractToggleCommand("Toggle Private Editor Layout") { + private Command toggleRestoreActivePage; + + { + // If we are toggling off private mode, make sure that we stop + // tracking the active page selection if we were tracking it. + // And remember that for undo + if (!sashModel.isLegacyMode()) { + SashWindowsMngr sash = DiUtils.lookupSashWindowsMngr(sashModel.getResource()); + if ((sash != null) && (sash.getSashModel() != null) && sash.getSashModel().isRestoreActivePage()) { + toggleRestoreActivePage = createToggleRestoreActivePageCommand(); + } + } + } + + @Override + public void execute() { + // First, if we need to toggle restoring the active page, do that + if ((toggleRestoreActivePage != null) && toggleRestoreActivePage.canExecute()) { + toggleRestoreActivePage.execute(); + } + + SashWindowsMngr toMove = DiUtils.lookupSashWindowsMngr(sashModel.getResource()); + + // We don't record changes in the sash model for undo/redo, + // so we cannot assume that any changes to the current page selections + // are undoable in the usual way + if (!sashModel.isLegacyMode()) { + Resource sashResource = toMove.eResource(); + URI sharedURI = sashModel.getSharedResourceURI(); + + // Move the contents into the DI model. If the DI resource isn't loaded, + // give up because something is seriously wrong in that case + Resource diResource = modelSet.getResource(sharedURI, false); + if ((diResource != null) && diResource.isLoaded()) { + moveContents(sashResource, diResource); + + if (sashResource.getContents().isEmpty()) { + // Schedule deletion on save + modelSet.getResourcesToDeleteOnSave().add(sashResource.getURI()); + } + } + } else { + Resource sashResource; + URI privateURI = sashModel.getPrivateResourceURI(); + + // Move the contents into the sash model. If the sash resource isn't loaded + // or doesn't exist, it will have to be handled + if (modelSet.getURIConverter().exists(privateURI, null)) { + sashResource = modelSet.getResource(privateURI, true); + } else { + sashResource = modelSet.createResource(privateURI); + } + + // In case we had marked it for deletion, earlier + modelSet.getResourcesToDeleteOnSave().remove(privateURI); + + Resource diResource = toMove.eResource(); + moveContents(diResource, sashResource); + } + + // Re-load from the new resource. Snippets might find this odd, but + // it would be even more odd for there to be any snippets on this model + sashModel.loadModel(modelSet.getURIWithoutExtension()); + } + }; + } + + return result; + } + + void moveContents(Resource fromResource, Resource toResource) { + // Safe copy to allow concurrent modifications + for (EObject root : new ArrayList<>(fromResource.getContents())) { + EObject toReplace = (EObject) EcoreUtil.getObjectByType(toResource.getContents(), root.eClass()); + if (toReplace != null) { + EcoreUtil.replace(toReplace, root); + } else { + if (root instanceof SashWindowsMngr) { + // This one is expected always to be first + toResource.getContents().add(0, root); + } else { + toResource.getContents().add(root); + } + } + } + + } + + /** + * Creates a command that toggles whether the sash model records the currently + * active page to restore it on next opening. + * + * @return a toggle command for the restore-active-page behaviour + */ + public Command createToggleRestoreActivePageCommand() { + Command result = UnexecutableCommand.INSTANCE; + + ModelSet modelSet = (ModelSet) editor.getAdapter(EditingDomain.class).getResourceSet(); + SashWindowsMngr sashWindows = SashModelUtils.getSashWindowsMngr(modelSet); + ISashWindowsContainer container = editor.getAdapter(ISashWindowsContainer.class); + + SashModel sashModel = sashWindows.getSashModel(); + if (sashModel != null) { + // We don't record the tracking of the active page for undo/redo, + // so we cannot assume that any changes to the current page selections + // are undoable in the usual way + result = new AbstractToggleCommand("Toggle Restore Active Page") { + + @Override + public void execute() { + boolean oldValue = sashModel.isRestoreActivePage(); + + if (oldValue) { + // Clear each tab folder's selection + container.getIFolderList().stream() + .map(f -> f.getRawModel()) + .filter(TabFolder.class::isInstance).map(TabFolder.class::cast) + .filter(f -> f.getCurrentSelection() != null) + .forEach(f -> f.setCurrentSelection(null)); + } else { + // Set each tab folder's selection. + // The 'visible pages' are the current selection in each folder + container.getVisiblePages().stream() + .map(p -> p.getRawModel()) + .filter(PageRef.class::isInstance).map(PageRef.class::cast) + .filter(p -> p.getParent().getCurrentSelection() != p) + .forEach(p -> p.getParent().setCurrentSelection(p)); + } + + // The basic toggle + sashModel.setRestoreActivePage(!oldValue); + } + }; + } + + return result; + } + + // + // Nested types + // + + private static abstract class AbstractToggleCommand extends AbstractCommand { + + AbstractToggleCommand(String label) { + super(label); + } + + @Override + protected boolean prepare() { + // Nothing to prepare + return true; + } + + @Override + public void undo() { + // It's a toggle, so yeah, just execute again + execute(); + } + + @Override + public void redo() { + execute(); + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java new file mode 100644 index 00000000000..12fa47811e9 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java @@ -0,0 +1,78 @@ +/***************************************************************************** + * Copyright (c) 2015 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.internal.commands; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.emf.transaction.RollbackException; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.utils.TransactionHelper; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor; +import org.eclipse.papyrus.infra.ui.services.SaveLayoutBeforeClose; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.ui.statushandlers.StatusManager; + +/** + * Command handler for the private page-layout storage toggle menu. + */ +public class TogglePageLayoutStorageHandler extends AbstractHandler { + + public TogglePageLayoutStorageHandler() { + super(); + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + IEditorPart active = HandlerUtil.getActiveEditor(event); + if (active instanceof IMultiDiagramEditor) { + IMultiDiagramEditor editor = (IMultiDiagramEditor) active; + + // Toggle the storage of the layout + togglePrivatePageLayout(editor); + + // And then save the layout immediately if the editor is not dirty + // (if it is dirty, then the layout will be saved when the editor + // is saved; saving it now would possibly result in inconsistencies) + try { + SaveLayoutBeforeClose save = editor.getServicesRegistry().getService(SaveLayoutBeforeClose.class); + save.saveBeforeClose(editor); + } catch (ServiceException e) { + // Doesn't matter; we'll just have to rely on the normal editor save + } + } + + return null; + } + + public void togglePrivatePageLayout(IMultiDiagramEditor editor) { + Command command = new SashLayoutCommandFactory(editor).createTogglePrivateLayoutCommand(); + EditingDomain domain = editor.getAdapter(EditingDomain.class); + + // Don't execute on the undo history because the changes in the sash model + // are never tracked for undo/redo + try { + TransactionHelper.run(domain, () -> command.execute()); + } catch (RollbackException e) { + StatusManager.getManager().handle(e.getStatus()); + } catch (InterruptedException e) { + Activator.log.error("Failed to execute page layout toggle command", e); //$NON-NLS-1$ + } + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java new file mode 100644 index 00000000000..bff4950d394 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java @@ -0,0 +1,52 @@ +/***************************************************************************** + * Copyright (c) 2015, 2016 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.internal.preferences; + +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.RadioGroupFieldEditor; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.swt.SWT; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +/** + * The preference page for Papyrus Editor general preferences. + */ +public class EditorPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + + public EditorPreferencePage() { + super(Messages.EditorPreferencePage_0, SWT.FLAT); + + setDescription(Messages.EditorPreferencePage_5); + } + + @Override + public void init(IWorkbench workbench) { + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + } + + @Override + protected void createFieldEditors() { + addField(new RadioGroupFieldEditor(EditorPreferences.PREF_CONVERT_SHARED_LAYOUT, + Messages.EditorPreferencePage_1, + 1, + new String[][] { + { Messages.EditorPreferencePage_2, YesNo.PROMPT.name() }, + { Messages.EditorPreferencePage_3, YesNo.NO.name() }, + { Messages.EditorPreferencePage_4, YesNo.YES.name() }, + }, + getFieldEditorParent())); + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java new file mode 100644 index 00000000000..0b8748f6032 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java @@ -0,0 +1,88 @@ +/***************************************************************************** + * Copyright (c) 2015, 2016 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.internal.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.papyrus.infra.ui.Activator; + +/** + * Accessor for the Papyrus Editor preferences. + */ +public class EditorPreferences { + public static final String PREF_CONVERT_SHARED_LAYOUT = "convertSharedLayout"; //$NON-NLS-1$ + + private static final EditorPreferences INSTANCE = new EditorPreferences(); + private final IPreferenceStore store; + + private EditorPreferences() { + super(); + + store = Activator.getDefault().getPreferenceStore(); + } + + public static EditorPreferences getInstance() { + return INSTANCE; + } + + /** + * Queries whether the user prefers to migrate shared editor layout to private storage + * always, never, or interactively pop up a dialog to ask (the default). + * + * @return the shared layout conversion on first open preference, which is never + * {@code null} and defaults to {@link YesNo#PROMPT} + */ + public YesNo getConvertSharedPageLayoutToPrivate() { + return YesNo.valueOf(store.getString(PREF_CONVERT_SHARED_LAYOUT)); + } + + /** + * Sets whether the editor will always, never, or ask the user to migrate shared + * (in the {@code *.di} resource) page layout into the private storage ({@code *.sash} resource} + * on the first opening of a Papyrus model in the workspace that uses the shared + * storage (usually from pre-1.0 release). + * + * @param convert + * the preference setting to assign, or {@code null} for the default, which + * is {@link YesNo#PROMPT} + */ + public void setConvertSharedPageLayoutToPrivate(YesNo convert) { + if (convert == null) { + convert = YesNo.PROMPT; + } + + store.setValue(PREF_CONVERT_SHARED_LAYOUT, convert.name()); + } + + // + // Nested types + // + + /** + * Initializer of defaults for the editor preferences. + */ + public static class Initializer extends AbstractPreferenceInitializer { + + public Initializer() { + super(); + } + + @Override + public void initializeDefaultPreferences() { + IPreferenceStore store = Activator.getDefault().getPreferenceStore(); + + store.setDefault(PREF_CONVERT_SHARED_LAYOUT, YesNo.PROMPT.name()); + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java new file mode 100644 index 00000000000..4fbebcf89bc --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2015 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.internal.preferences; + +import org.eclipse.osgi.util.NLS; + +/** + * Translatable strings. + */ +class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.papyrus.infra.core.internal.preferences.messages"; //$NON-NLS-1$ + public static String EditorPreferencePage_0; + public static String EditorPreferencePage_1; + public static String EditorPreferencePage_2; + public static String EditorPreferencePage_3; + public static String EditorPreferencePage_4; + public static String EditorPreferencePage_5; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java new file mode 100644 index 00000000000..a9ee87d9e4f --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java @@ -0,0 +1,21 @@ +/***************************************************************************** + * Copyright (c) 2015 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.internal.preferences; + +/** + * A tri-state boolean-ish preference data type with a "prompt the user" value. + */ +public enum YesNo { + PROMPT, NO, YES; +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties new file mode 100644 index 00000000000..a34a57ddfbe --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties @@ -0,0 +1,18 @@ +# +# Copyright (c) 2015 Christian W. Damus and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Christian W. Damus - Initial API and implementation +# + +EditorPreferencePage_0=General Editor Settings +EditorPreferencePage_1=Convert shared storage of editor layout to private: +EditorPreferencePage_2=Ask each time +EditorPreferencePage_3=Never +EditorPreferencePage_4=Always +EditorPreferencePage_5=General settings for the Papyrus multi-diagram editor. diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java new file mode 100644 index 00000000000..d11eb1bc59c --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java @@ -0,0 +1,66 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+/**
+ * Event sent whith a Save or SaveAs.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class DoSaveEvent {
+
+ final protected ServicesRegistry serviceRegistry;
+
+ final protected IMultiDiagramEditor multiDiagramEditor;
+
+ final protected boolean isAutoSave;
+
+ /**
+ * Create an Event that is sent with a Save or SaveAs. The same event can be
+ * reused. Constructor.
+ *
+ * @param serviceRegistry
+ * @param multiDiagramEditor
+ */
+ public DoSaveEvent(ServicesRegistry serviceRegistry, IMultiDiagramEditor multiDiagramEditor) {
+ this(serviceRegistry, multiDiagramEditor, false);
+ }
+
+ /**
+ * Create an Event that is sent with a Save or SaveAs. The same event can be
+ * reused. Constructor.
+ *
+ * @param serviceRegistry
+ * @param multiDiagramEditor
+ * @param isAutoSave
+ */
+ public DoSaveEvent(ServicesRegistry serviceRegistry, IMultiDiagramEditor multiDiagramEditor, boolean isAutoSave) {
+ this.serviceRegistry = serviceRegistry;
+ this.multiDiagramEditor = multiDiagramEditor;
+ this.isAutoSave = isAutoSave;
+ }
+
+ /**
+ * @return the serviceRegistry
+ */
+ public ServicesRegistry getServiceRegistry() {
+ return serviceRegistry;
+ }
+
+ /**
+ * @return the multiDiagramEditor
+ */
+ public IMultiDiagramEditor getMultiDiagramEditor() {
+ return multiDiagramEditor;
+ }
+
+ public boolean isAutoSave() {
+ return isAutoSave;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java new file mode 100644 index 00000000000..575e2013934 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java @@ -0,0 +1,40 @@ +/*****************************************************************************
+ * Copyright (c) 2010 LIFL & CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import org.eclipse.ui.part.FileEditorInput;
+
+/**
+ * Interface implemented by classes wishing to be notified of the inputChanged
+ * event after a call to {@link ISaveAndDirtyService#doSaveAs()}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public interface IEditorInputChangedListener {
+
+ /**
+ *
+ * @param fileEditorInput
+ * The new value of EditorInput
+ */
+ public void editorInputChanged(FileEditorInput fileEditorInput);
+
+ /**
+ * Called when the value of the isDirty() flag has changed.
+ */
+ public void isDirtyChanged();
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java new file mode 100644 index 00000000000..cf0bbeee92e --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java @@ -0,0 +1,57 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+/**
+ * Concrete implementation of this interface allows to listen on various
+ * lifecycle events. This interface is the "public" part of the {@link LifeCycleEventsProvider}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public interface ILifeCycleEventsProvider {
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ public void addDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ public void removeDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ public void addAboutToDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ public void removeAboutToDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ public void addPostDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ public void removePostDoSaveListener(ISaveEventListener listener);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java new file mode 100644 index 00000000000..14f6f12d0d3 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java @@ -0,0 +1,56 @@ +/*****************************************************************************
+ * Copyright (c) 2010 LIFL & CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.ui.ISaveablePart;
+
+/**
+ * @author dumoulin
+ *
+ */
+public interface ISaveAndDirtyService extends ISaveablePart {
+
+ /**
+ * Register a nested {@link ISaveablePart} as a listener that will be
+ * notified each time a {@link #doSave(IProgressMonitor)} or {@link #doSaveAs()} is performed. Also, it will be asked for the
+ * dirtyState.
+ *
+ * @param saveablePart
+ */
+ public abstract void registerIsaveablePart(ISaveablePart saveablePart);
+
+ /**
+ * Remove the specified {@link ISaveablePart} from the list of listeners.
+ *
+ * @param saveablePart
+ */
+ public abstract void removeIsaveablePart(ISaveablePart saveablePart);
+
+ /**
+ * Add a listeners on input changed event.
+ *
+ * @param inputChangedListener
+ */
+ public void addInputChangedListener(IEditorInputChangedListener inputChangedListener);
+
+ /**
+ * Remove a listeners on input changed event.
+ *
+ * @param inputChangedListener
+ */
+ public void removeInputChangedListener(IEditorInputChangedListener inputChangedListener);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java new file mode 100644 index 00000000000..d936304bcb5 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java @@ -0,0 +1,27 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+/**
+ * Interface used to listen on open, save and saveAs events.
+ *
+ * @author cedric dumoulin
+ *
+ * @param <T>
+ * Type of event passed to methods.
+ */
+public interface ISaveEventListener {
+
+ /**
+ *
+ * @param editor
+ */
+ public void doSave(DoSaveEvent event);
+
+ /**
+ *
+ * @param editor
+ */
+ public void doSaveAs(DoSaveEvent event);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java new file mode 100644 index 00000000000..7dd9dda4c92 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java @@ -0,0 +1,291 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides events about the life cycle of a MultiEditor. Not all
+ * life cycle events are available. Available events:
+ * <ul>
+ * <li>aboutToDoSave, aboutToDoSaveAs - SaveEventListener</li>
+ * <li>doSave, doSaveAs - SaveEventListener</li>
+ * <li>afterDoSave, afterDoSaveAs - SaveEventListener</li>
+ * <li></li>
+ * <li></li>
+ * </ul>
+ *
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class LifeCycleEventsProvider implements ILifeCycleEventsProvider {
+
+ /**
+ *
+ */
+ protected SaveEventListenerLazyList preSaveListeners = new SaveEventListenerLazyList();
+
+ /**
+ *
+ */
+ protected SaveEventListenerLazyList saveListeners = new SaveEventListenerLazyList();
+
+ /**
+ *
+ */
+ protected SaveEventListenerLazyList postSaveListeners = new SaveEventListenerLazyList();
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void addDoSaveListener(ISaveEventListener listener) {
+
+ saveListeners.addListener(listener);
+ }
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void removeDoSaveListener(ISaveEventListener listener) {
+ saveListeners.removeListener(listener);
+ }
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void addAboutToDoSaveListener(ISaveEventListener listener) {
+
+ preSaveListeners.addListener(listener);
+ }
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void removeAboutToDoSaveListener(ISaveEventListener listener) {
+ preSaveListeners.removeListener(listener);
+ }
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void addPostDoSaveListener(ISaveEventListener listener) {
+
+ postSaveListeners.addListener(listener);
+ }
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void removePostDoSaveListener(ISaveEventListener listener) {
+ postSaveListeners.removeListener(listener);
+ }
+
+ // ****************************************************** //
+ // Fire events methods //
+ // ****************************************************** //
+
+ /**
+ * Fire AboutToSaveEvent to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireAboutToDoSaveEvent(DoSaveEvent event) {
+ preSaveListeners.fireSaveEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveAs to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireAboutToDoSaveAsEvent(DoSaveEvent event) {
+ preSaveListeners.fireSaveAsEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveEvent to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireDoSaveEvent(DoSaveEvent event) {
+ saveListeners.fireSaveEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveAs to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireDoSaveAsEvent(DoSaveEvent event) {
+ saveListeners.fireSaveAsEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveEvent to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void firePostDoSaveEvent(DoSaveEvent event) {
+ postSaveListeners.fireSaveEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveAs to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void firePostDoSaveAsEvent(DoSaveEvent event) {
+ postSaveListeners.fireSaveAsEvent(event);
+ }
+
+ /**
+ * Fire all Save events (about, events, post) to registered Listeners.
+ * Exceptions from listeners are propagated and stop the event chain.
+ *
+ * @param editorPart
+ */
+ public void fireAllDoSaveEvent(DoSaveEvent event) {
+ fireAboutToDoSaveEvent(event);
+ fireDoSaveEvent(event);
+ firePostDoSaveEvent(event);
+ }
+
+ /**
+ * Fire all SaveAs events (about, events, post) to registered Listeners. If
+ * one of the saveAs event fail, post events are not sent.
+ *
+ * @param editorPart
+ */
+ public void fireAllDoSaveAsEvent(DoSaveEvent event) {
+ fireAboutToDoSaveAsEvent(event);
+ fireDoSaveAsEvent(event);
+ firePostDoSaveAsEvent(event);
+ }
+
+ /**
+ * Base class encapsulating a lazy creation list.
+ *
+ * @author cedric dumoulin
+ *
+ * @param <T>
+ */
+ abstract protected class AbstractEventListenersLazyList<T> {
+
+ List<T> listeners;
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ public void addListener(T listener) {
+ // Lazy creation
+ if (listeners == null) {
+ listeners = new ArrayList<T>();
+ }
+
+ // do not add if already present.
+ if (listeners.contains(listener)) {
+ return;
+ }
+
+ listeners.add(listener);
+ }
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ public void removeListener(T listener) {
+ // Lazy creation
+ if (listeners == null) {
+ return;
+ }
+
+ listeners.remove(listener);
+ }
+
+ /**
+ * @return the listeners
+ */
+ protected List<T> getListeners() {
+ return listeners;
+ }
+
+ /**
+ * Remove all listeners.
+ */
+ protected void clear() {
+ if (listeners != null) {
+ listeners.clear();
+ }
+ }
+ }
+
+ /**
+ * List of {@link ISaveEventListener}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+ protected class SaveEventListenerLazyList extends AbstractEventListenersLazyList<ISaveEventListener> {
+
+ /**
+ * Fire OpenEvent to registered Listeners. If a listener throw an
+ * exception, remaining listeners are called, and then the exception is
+ * resent.
+ *
+ * @param editorPart
+ */
+ public void fireSaveEvent(DoSaveEvent event) {
+ // Lazy creation
+ if (listeners == null) {
+ return;
+ }
+
+ for (ISaveEventListener listener : listeners) {
+ listener.doSave(event);
+ }
+ }
+
+ /**
+ * Fire OpenEvent to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireSaveAsEvent(DoSaveEvent event) {
+ // Lazy creation
+ if (listeners == null) {
+ return;
+ }
+
+ for (ISaveEventListener listener : listeners) {
+ listener.doSaveAs(event);
+ }
+
+ }
+
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java new file mode 100644 index 00000000000..8bdfb550d1c --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java @@ -0,0 +1,79 @@ +/*****************************************************************************
+ * Copyright (c) 2010 LIFL & CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+
+/**
+ * A service factory to create the {@link ILifeCycleEventsProvider} service.
+ * This provide a nickname for {@link SaveAndDirtyService} service. This
+ * serviceFactory depends on {@link SaveAndDirtyService} service.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class LifeCycleEventsProviderServiceFactory implements IServiceFactory {
+
+ /**
+ * The sashModelMangr.
+ */
+ private SaveAndDirtyService saveAndDirtyService;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ // Get required services
+ // This rely on the real implementation.
+ saveAndDirtyService = (SaveAndDirtyService) servicesRegistry.getService(ISaveAndDirtyService.class);
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance()
+ *
+ * @return
+ * @throws ServiceException
+ */
+ @Override
+ public Object createServiceInstance() throws ServiceException {
+ return saveAndDirtyService;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java new file mode 100644 index 00000000000..7e858153695 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java @@ -0,0 +1,550 @@ +/***************************************************************************** + * Copyright (c) 2010, 2013 LIFL & CEA LIST. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation + * Christian W. Damus (CEA) - Don't make editor dirty on empty ResourceSetChangeEvent + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.lifecycleevents; + +import static org.eclipse.papyrus.infra.core.Activator.log; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.EventObject; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +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.ecore.util.EcoreUtil; +import org.eclipse.emf.transaction.NotificationFilter; +import org.eclipse.emf.transaction.ResourceSetChangeEvent; +import org.eclipse.emf.transaction.ResourceSetListener; +import org.eclipse.emf.transaction.RollbackException; +import org.eclipse.emf.transaction.Transaction; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.services.IService; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.core.utils.ServiceUtils; +import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.ISaveablePart; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.dialogs.SaveAsDialog; +import org.eclipse.ui.part.FileEditorInput; + +/** + * A Papyrus Service allowing to perform save and saveAs on Papyrus Models. The + * service also allows to listen on the dirty state of the Models. <br> + * The service implements the {@link ISaveablePart} interface, and can be used + * directly in part requiring such interface of adapter. + * + * <br> + * This class allows nested editors to register themselves as nested {@link ISaveablePart}. In this case, the registered part will be notified + * each time a save or saveAs is performed. Also, the nested part will be asked + * for its dirtyState. + * + * TODO : Improve the implementation by registering the isDirty flag value, and + * firing events only if the value really change. Actually, the event is fired + * every time the model is modified, even if the virtual value of the flag + * hasn't changed. + * + * @author cedric dumoulin + * + */ +public class SaveAndDirtyService extends LifeCycleEventsProvider implements ISaveablePart, IService, ISaveAndDirtyService { + + /** + * Class used to propagate life cycle events. This class can be retrieved as + * a service using {@link ILifeCycleEventsProvider}.class. This class + * extends LifeCycleEventsProvider, so the local variable is set with + * ourself (historical reasons). TODO : remove this local variable. + */ + protected LifeCycleEventsProvider lifeCycleEventsProvider = this; + + /** + * Cached event that can be reused. + */ + protected DoSaveEvent lifeCycleEvent; + + /** + * Model set managing models. + */ + private ModelSet resourceSet; + + /** + * + */ + private TransactionalEditingDomain transactionalEditingDomain; + + /** + * The serviceRegistry. + */ + // private ServicesRegistry servicesRegistry; + + /** + * Associated editor. Needed by saveAs to synchronize editor input. + */ + private IMultiDiagramEditor multiDiagramEditor; + + /** + * List of registered {@link ISaveablePart}. This are usually nested + * editors. + */ + private ISaveablePartList registeredIsaveablePart; + + /** + * List of listeners on input changed event after a call to saveAs. + */ + private List<IEditorInputChangedListener> inputChangedListeners; + + /** + * Listener on commandStack changes. + */ + private final CommandStackListener commandStackListener = new CommandStackListener() { + + @Override + public void commandStackChanged(EventObject event) { + + fireIsDirtyChanged(); + }; + }; + + /* + * Listener on ResourceSet + */ + private final ResourceSetListener resourceSetListener = new ResourceSetListener() { + + @Override + public NotificationFilter getFilter() { + return null; + } + + @Override + public boolean isAggregatePrecommitListener() { + return false; + } + + @Override + public boolean isPostcommitOnly() { + return true; + } + + @Override + public boolean isPrecommitOnly() { + return false; + } + + @Override + public void resourceSetChanged(ResourceSetChangeEvent event) { + if (event.getTransaction() != null && event.getTransaction().getStatus().isOK() && madePersistableChanges(event)) { + fireIsDirtyChanged(); + } + } + + private boolean madePersistableChanges(ResourceSetChangeEvent event) { + return !event.getNotifications().isEmpty() && !isUnprotected(event.getTransaction()); + } + + private boolean isUnprotected(Transaction transaction) { + return !Boolean.TRUE.equals(transaction.getOptions().get(Transaction.OPTION_UNPROTECTED)); + } + + @Override + public Command transactionAboutToCommit(ResourceSetChangeEvent event) throws RollbackException { + return null; + } + + }; + + /** + * Constructor. + * + */ + public SaveAndDirtyService() { + registeredIsaveablePart = new ISaveablePartList(); + inputChangedListeners = new ArrayList<IEditorInputChangedListener>(); + } + + /** + * Initialize the service. Retrieve other required services (ModelSet, + * CoreEditor). + * + * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry) + * + * @param servicesRegistry + * @throws ServiceException + */ + @Override + public void init(ServicesRegistry servicesRegistry) throws ServiceException { + + // this.servicesRegistry = servicesRegistry; + + // Retrieve required services. + resourceSet = servicesRegistry.getService(ModelSet.class); + multiDiagramEditor = servicesRegistry.getService(IMultiDiagramEditor.class); + transactionalEditingDomain = ServiceUtils.getInstance().getTransactionalEditingDomain(servicesRegistry); + + // Initialize and register the ILifeCycleEventsProvider service (which + // is ourself). + // This mean that the ILifeCycleEventsProvider is not available until we + // are started. + lifeCycleEvent = new DoSaveEvent(servicesRegistry, multiDiagramEditor); + // servicesRegistry.add(ILifeCycleEventsProvider.class, 1, + // lifeCycleEventsProvider); + + } + + /** + * Do nothing. + * + * @see org.eclipse.papyrus.infra.core.services.IService#startService() + * + * @throws ServiceException + */ + @Override + public void startService() throws ServiceException { + + // Listen to the modifications of the EMF model + transactionalEditingDomain.getCommandStack().addCommandStackListener(commandStackListener); + + // Let's listen to the resource set change + transactionalEditingDomain.addResourceSetListener(resourceSetListener); + } + + /** + * @see org.eclipse.papyrus.infra.core.services.IService#disposeService() + * + * @throws ServiceException + */ + @Override + public void disposeService() throws ServiceException { + if (transactionalEditingDomain != null) { + // Check if commandStack is null (meaning that transactionalEditingDomain + // is disposed + CommandStack commandStack = transactionalEditingDomain.getCommandStack(); + if (commandStack != null) { + transactionalEditingDomain.getCommandStack().removeCommandStackListener(commandStackListener); + } + transactionalEditingDomain.removeResourceSetListener(resourceSetListener); + // resourceSetListener = null; + } + + // clean properties in order to help GC + inputChangedListeners.clear(); + inputChangedListeners = null; + multiDiagramEditor = null; + // servicesRegistry = null; + transactionalEditingDomain = null; + resourceSet = null; + lifeCycleEvent = null; + + postSaveListeners.clear(); + saveListeners.clear(); + preSaveListeners.clear(); + + + } + + /** + * Save the Models + * + * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor) + * + * @param monitor + */ + @Override + public void doSave(IProgressMonitor monitor) { + // Sent pre doSave event + lifeCycleEventsProvider.fireAboutToDoSaveEvent(lifeCycleEvent); + + // sent doSaveEvent + lifeCycleEventsProvider.fireDoSaveEvent(lifeCycleEvent); + // Perform local doSave + // TODO : put it in a listener ? + try { + // Save each associated resource + resourceSet.save(monitor); + // notify registered IsaveablePart + registeredIsaveablePart.doSave(monitor); + markSaveLocation(); + } catch (IOException e) { + log.error("Error during save", e); //$NON-NLS-1$ + } + + // Sent post Events + lifeCycleEventsProvider.firePostDoSaveEvent(lifeCycleEvent); + + } + + /** + * @see org.eclipse.ui.ISaveablePart#doSaveAs() + * + */ + @Override + public void doSaveAs() { + // Sent pre doSave event + lifeCycleEventsProvider.fireAboutToDoSaveAsEvent(lifeCycleEvent); + + // sent doSaveEvent + lifeCycleEventsProvider.fireDoSaveAsEvent(lifeCycleEvent); + // Perform local doSaveAs + + // Show a SaveAs dialog + Shell shell = multiDiagramEditor.getEditorSite().getWorkbenchWindow().getShell(); + SaveAsDialog dialog = new SaveAsDialog(shell); + dialog.setOriginalFile(((IFileEditorInput) multiDiagramEditor.getEditorInput()).getFile()); + dialog.open(); + final IPath path = dialog.getResult(); + if (path != null) { + // try to save the editor's contents under a different file name + final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); + try { + new ProgressMonitorDialog(shell).run(false, // don't fork + false, // can't cancel + new WorkspaceModifyOperation() { // run this operation + + @Override + public void execute(final IProgressMonitor monitor) { + try { + // to event bad redirection after the saveAs + // see bug 319023 + EcoreUtil.resolveAll(resourceSet); + resourceSet.saveAs(path); + // notify registered IsaveablePart + registeredIsaveablePart.doSave(monitor); + } catch (IOException e) { + log.error("Unable to saveAs the resource set", e); //$NON-NLS-1$ + } + } + }); + // set input to the new file + fireEditorInputChanged(new FileEditorInput(file)); + markSaveLocation(); + } catch (InterruptedException e) { + // should not happen, since the monitor dialog is not cancelable + log.error(e); + } catch (InvocationTargetException e) { + log.error(e); + } + } + + // sent doSaveEvent + lifeCycleEventsProvider.firePostDoSaveAsEvent(lifeCycleEvent); + } + + /** + * Change the input of the underlying editor. + * + * @param fileEditorInput + */ + private void fireEditorInputChanged(FileEditorInput fileEditorInput) { + + for (IEditorInputChangedListener listener : inputChangedListeners) { + try { + listener.editorInputChanged(fileEditorInput); + } catch (Exception e) { + log.error("Can't set input for '" + listener + "'", e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + } + + /** + * Fire a PropertyChanged event to registered {@link IEditorInputChangedListener}. + * + * @param propertyId + */ + private void fireIsDirtyChanged() { + + for (IEditorInputChangedListener listener : inputChangedListeners) { + try { + listener.isDirtyChanged(); + } catch (Exception e) { + log.error("Can't call listener '" + listener + "'", e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + } + + /** + * Return true if the multiEditor is dirty, false otherwise. The dirty state + * is compute as follow: + * <ul> + * <li>The {@link TransactionalEditingDomain} commandStack is checked</li> + * <li>and each registered nested Isaveable.isDirty() state is checked</li> + * <li></li> + * <li></li> + * <li></li> + * <li></li> + * </ul> + * If one of these states is false, the returned value is false. <br> + * If all of these states are true, the returned value is true. + * + * @see org.eclipse.ui.ISaveablePart#isDirty() + * + * @return + */ + @Override + public boolean isDirty() { + // First, look if the model part (EMF) is dirty, else look at the + // Graphical part (GEF/GMF) + if (transactionalEditingDomain == null) { + return false; + } + return ((BasicCommandStack) transactionalEditingDomain.getCommandStack()).isSaveNeeded() || registeredIsaveablePart.isDirty(); + } + + /** + * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed() + * + * @return + */ + @Override + public boolean isSaveAsAllowed() { + return true; + } + + /** + * @see org.eclipse.ui.ISaveablePart#isSaveOnCloseNeeded() + * + * @return + */ + @Override + public boolean isSaveOnCloseNeeded() { + return isDirty(); + } + + /** + * Mark the command stack of all sub-editors. Default implementation do + * nothing. + */ + protected void markSaveLocation() { + ((BasicCommandStack) transactionalEditingDomain.getCommandStack()).saveIsDone(); + fireIsDirtyChanged(); + } + + /** + * Register a nested {@link ISaveablePart} as a listener that will be + * notified each time a {@link #doSave(IProgressMonitor)} or {@link #doSaveAs()} is performed. Also, it will be asked for the + * dirtyState. + * + * @param saveablePart + */ + @Override + public void registerIsaveablePart(ISaveablePart saveablePart) { + registeredIsaveablePart.add(saveablePart); + } + + /** + * Remove the specified {@link ISaveablePart} from the list of listeners. + * + * @param saveablePart + */ + @Override + public void removeIsaveablePart(ISaveablePart saveablePart) { + registeredIsaveablePart.remove(saveablePart); + } + + /** + * Add a listeners on input changed event. + * + * @param inputChangedListener + */ + @Override + public void addInputChangedListener(IEditorInputChangedListener inputChangedListener) { + inputChangedListeners.add(inputChangedListener); + } + + /** + * Remove a listeners on input changed event. + * + * @param inputChangedListener + */ + @Override + public void removeInputChangedListener(IEditorInputChangedListener inputChangedListener) { + inputChangedListeners.remove(inputChangedListener); + } + + /** + * A list of {@link ISaveablePart}. + * + * @author dumoulin + * + */ + public class ISaveablePartList extends ArrayList<ISaveablePart> { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Return true if one of the part is dirty, false if all part are not + * dirty. + * + * @return + */ + public boolean isDirty() { + for (ISaveablePart part : this) { + if (part.isDirty()) { + return true; + } + } + + return false; + } + + /** + * Call doSave on each registered {@link ISaveablePart}. + * + * @param monitor + */ + public void doSave(IProgressMonitor monitor) { + for (ISaveablePart part : this) { + + try { + part.doSave(monitor); + } catch (Exception e) { + log.error("Can't save ISaveablePart '" + part + "'", e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + } + + /** + * Call doSaveAs on each registered {@link ISaveablePart}. + * + * @param monitor + */ + public void doSaveAs() { + for (ISaveablePart part : this) { + try { + part.doSaveAs(); + } catch (Exception e) { + log.error("Can't save ISaveablePart '" + part + "'", e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java index ef2255fc632..72f3fbe87b6 100644 --- a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java @@ -19,8 +19,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.papyrus.infra.core.services.ServiceException;
-import org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers;
import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForActionHandlers;
public abstract class AbstractParametricOnSelectedElementsAction {
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java new file mode 100644 index 00000000000..4ece10f8d24 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java @@ -0,0 +1,48 @@ +/***************************************************************************** + * Copyright (c) 2013 CEA LIST. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.messages; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + + private static final String BUNDLE_NAME = "org.eclipse.papyrus.infra.tools.messages.messages"; //$NON-NLS-1$ + + public static String AbstractPreferenceKeyDialog_Level; + + public static String AbstractPreferenceKeyDialog_Localization; + + public static String AbstractPreferenceKeyDialog_Pref_Kind; + + public static String AbstractPreferenceKeyDialog_WouldYouLikeOverloadPreferences; + + public static String AbstractStringValueConverter_NoXReprensentedByYHaveBeenFound; + + public static String AbstractStringValueConverter_SomeStringsAreNotValidToCreateY; + + public static String AbstractStringValueConverter_SomeStringsCantBeResolvedToFindY; + + public static String AbstractStringValueConverter_TheFeatureXCantBeResolved; + + public static String AbstractStringValueConverter_TheStringValueXCantBeResolved; + + public static String AbstractStringValueConverter_TheStringXIsNotValidToCreateY; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties new file mode 100644 index 00000000000..845a45e10ab --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties @@ -0,0 +1,10 @@ +AbstractPreferenceKeyDialog_Level=Level +AbstractPreferenceKeyDialog_Localization=Localization +AbstractPreferenceKeyDialog_Pref_Kind=Pref. kind +AbstractPreferenceKeyDialog_WouldYouLikeOverloadPreferences=Would you like to overload those preferences? +AbstractStringValueConverter_NoXReprensentedByYHaveBeenFound=No {0} represented by {1} have been found +AbstractStringValueConverter_SomeStringsAreNotValidToCreateY=Some Strings are not valid to create {0} +AbstractStringValueConverter_SomeStringsCantBeResolvedToFindY=Some Strings can't be resolved to find {0} +AbstractStringValueConverter_TheFeatureXCantBeResolved=The feature {0} can't be resolved +AbstractStringValueConverter_TheStringValueXCantBeResolved=The string value {0} can't be resolved +AbstractStringValueConverter_TheStringXIsNotValidToCreateY=The String {0} is not valid to create {1} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java new file mode 100644 index 00000000000..731fffe79dc --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java @@ -0,0 +1,72 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * Descriptor of an ActionBarContributor. This descriptor is usually loaded from
+ * the Eclipse extension mechanism.
+ *
+ * @author Cedric Dumoulin
+ * @author Patrick Tessier
+ *
+ */
+public class ActionBarContributorDescriptor {
+
+ protected Class<? extends EditorActionBarContributor> contextClass;
+
+ protected String contextId;
+
+ /**
+ * Instance is created when requested.
+ */
+ protected EditorActionBarContributor instance = null;
+
+ /**
+ * constructor.
+ *
+ * @return the context descriptor
+ * @throws BackboneException
+ */
+ protected EditorActionBarContributor getActionBarContributor() throws BackboneException {
+ if (instance == null) {
+ instance = createActionBarContributor();
+ }
+
+ return instance;
+ }
+
+ private EditorActionBarContributor createActionBarContributor() throws BackboneException {
+ try {
+ EditorActionBarContributor context = contextClass.newInstance();
+ return context;
+
+ } catch (SecurityException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ }
+ }
+
+} // end class
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java new file mode 100644 index 00000000000..fbcda9b915c --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java @@ -0,0 +1,72 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.papyrus.infra.core.extension.BadNameExtensionException;
+import org.eclipse.papyrus.infra.core.extension.ExtensionException;
+import org.eclipse.papyrus.infra.core.extension.ExtensionUtils;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * A factory used to create ActionBarContributor object from Eclipse extensions
+ * points elements.
+ *
+ * @author Cedric Dumoulin
+ * @auhtor Patrick Tessier
+ */
+public class ActionBarContributorExtensionFactory extends ExtensionUtils {
+
+ /** singleton eINSTANCE of this class */
+ public final static ActionBarContributorExtensionFactory eINSTANCE = new ActionBarContributorExtensionFactory();
+
+ /** constant for the editor diagram **/
+ public final static String EDITOR_ACTIONBARCONTRIBUTOR_EXTENSIONPOINT = "" + "actionBarContributor";
+
+ /** constant for the attribute factoryClass **/
+ public final static String CONTEXTCLASS_ATTRIBUTE = "implementingClass";
+
+ /** constant for the attribute contextId **/
+ public final static String ID_ATTRIBUTE = "id";
+
+ /**
+ * @return the eINSTANCE
+ */
+ public static ActionBarContributorExtensionFactory getInstance() {
+ return eINSTANCE;
+ }
+
+ /**
+ * Create a ContextDescriptor instance corresponding to the
+ * ConfigurationElement.
+ *
+ * @param element
+ * an {@link IConfigurationElement} see eclipse extension point
+ * @return a ContextDescriptor structure that contains information to the
+ * diagram context
+ * @throws BadNameExtensionException
+ **/
+ public ActionBarContributorDescriptor createActionBarContributorDescriptor(IConfigurationElement element) throws ExtensionException {
+ ActionBarContributorDescriptor res;
+
+ checkTagName(element, EDITOR_ACTIONBARCONTRIBUTOR_EXTENSIONPOINT);
+
+ res = new ActionBarContributorDescriptor();
+ res.contextClass = (Class<EditorActionBarContributor>) parseClass(element, CONTEXTCLASS_ATTRIBUTE, EDITOR_ACTIONBARCONTRIBUTOR_EXTENSIONPOINT);
+ res.contextId = element.getAttribute(ID_ATTRIBUTE);
+
+ return res;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java new file mode 100644 index 00000000000..5c28baf01e9 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java @@ -0,0 +1,176 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import static org.eclipse.papyrus.infra.core.Activator.log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.core.extension.ExtensionException;
+import org.eclipse.papyrus.infra.core.extension.NotFoundException;
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * A factory managing ActionBarContributor creation. The factory is loaded from
+ * ActionBarContributor declared in Eclipse extension mechanism.
+ *
+ * @author dumoulin
+ *
+ */
+public class ActionBarContributorRegistry implements IActionBarContributorFactory, IService {
+
+ /** ID of the editor extension (schema filename) */
+ public static final String EDITOR_EXTENSION_ID = "papyrusDiagram";
+
+ /** Namespace where to look for the extension points. */
+ protected String extensionPointNamespace;
+
+ /**
+ * Registered context descriptors.
+ */
+ private Map<Object, ActionBarContributorDescriptor> editorContextDescriptors;
+
+ /**
+ * Constructor. defaultContext, input and site are explicitly required in
+ * order be sure that they are initialized. The multiEditor should be
+ * initialized. In particular, getEditorSite(), getEditorInput() and
+ * getDefaultContext() should return initialized values.
+ *
+ * @param multiEditor
+ * the multieditor
+ * @param extensionPointNamespace
+ */
+ public ActionBarContributorRegistry(String extensionPointNamespace) {
+
+ this.extensionPointNamespace = extensionPointNamespace;
+ initializeEditorContextDescriptors();
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public EditorActionBarContributor getActionBarContributor(Object key) throws BackboneException {
+ try {
+ ActionBarContributorDescriptor desc = editorContextDescriptors.get(key);
+ return desc.getActionBarContributor();
+ } catch (NullPointerException e) {
+ // no context found.
+ throw new NotFoundException("No ActionBarContributor registered under id '" + key + "'.");
+ }
+ }
+
+ /**
+ * Get the list of descriptors.
+ *
+ * @return
+ * @throws BackboneException
+ * If a contributor fail to be loaded.
+ */
+ public List<EditorActionBarContributor> getActionBarContributors() throws BackboneException {
+ List<EditorActionBarContributor> res = new ArrayList<EditorActionBarContributor>();
+ for (ActionBarContributorDescriptor desc : editorContextDescriptors.values()) {
+ res.add(desc.getActionBarContributor());
+ }
+ return res;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public void registerActionBarContributor(String contextKey, EditorActionBarContributor contributor) {
+ ActionBarContributorDescriptor desc = new ActionBarContributorDescriptor();
+ desc.contextId = contextKey;
+ desc.instance = contributor;
+ desc.contextClass = contributor.getClass();
+
+ editorContextDescriptors.put(contextKey, desc);
+ }
+
+ /**
+ * Read context descriptors from extension points.
+ */
+ private void initializeEditorContextDescriptors() {
+
+ editorContextDescriptors = new HashMap<Object, ActionBarContributorDescriptor>();
+ // Reading data from plugins
+ IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPointNamespace, EDITOR_EXTENSION_ID);
+
+ ActionBarContributorExtensionFactory extensionReader = new ActionBarContributorExtensionFactory();
+
+ for (IConfigurationElement ele : configElements) {
+ ActionBarContributorDescriptor desc;
+ try {
+ if (ActionBarContributorExtensionFactory.EDITOR_ACTIONBARCONTRIBUTOR_EXTENSIONPOINT.equals(ele.getName())) {
+ desc = extensionReader.createActionBarContributorDescriptor(ele);
+ // Check double
+ if (editorContextDescriptors.get(desc.contextId) != null) {
+ // Already exists. Check if it is the same
+ ActionBarContributorDescriptor existingDesc = editorContextDescriptors.get(desc.contextId);
+ if (desc.equals(existingDesc)) {
+ log.warn("More than one ActionBarContributor is registered under the name '" + desc.contextId + "', with different parameters. Extra declaration are discarded.");
+ }
+ } else {
+ editorContextDescriptors.put(desc.contextId, desc);
+ }
+ }
+ } catch (ExtensionException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug(this.getClass().getSimpleName() + " : contributors desc loaded [" + editorContextDescriptors.size() + "]");
+ }
+ }
+
+ /**
+ * Initialize the service. Do nothing here.
+ *
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) {
+
+ }
+
+ /**
+ * Do nothing in this implementation. {@inheritDoc}
+ *
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ */
+ @Override
+ public void startService() {
+ }
+
+ /**
+ * Do nothing in this implementation.
+ */
+ @Override
+ public void disposeService() {
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java new file mode 100644 index 00000000000..0bf82998e36 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java @@ -0,0 +1,122 @@ +/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import java.util.List;
+
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.actionbarcontributor.ComposedActionBarContributor;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.actionbarcontributor.IMultiPageEditorActionBarContributor;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ *
+ * An ActionBarContributor composed of ActionBarContributor from multi editor.
+ * This ActionBarContributor switch to the contributor dedicated to the active
+ * editor in a MultiPageEditor environement.
+ *
+ * @author dumoulin
+ *
+ */
+public class CoreComposedActionBarContributor extends ComposedActionBarContributor implements IMultiPageEditorActionBarContributor {
+
+ /**
+ * The registry. Used to initialize the registered actionBars.
+ */
+ protected ActionBarContributorRegistry actionBarContributorRegistry;
+
+ protected List<EditorActionBarContributor> contributors;
+
+ /**
+ * Constructor.
+ *
+ * @throws BackboneException
+ */
+ public CoreComposedActionBarContributor() throws BackboneException {
+ // Init the contributors
+ loadContributors();
+ }
+
+ /**
+ *
+ * @throws BackboneException
+ */
+ private void loadContributors() throws BackboneException {
+ actionBarContributorRegistry = new ActionBarContributorRegistry(Activator.PLUGIN_ID);
+
+ contributors = actionBarContributorRegistry.getActionBarContributors();
+ }
+
+ /**
+ * @return the actionBarContributorRegistry
+ */
+ public ActionBarContributorRegistry getActionBarContributorRegistry() {
+ return actionBarContributorRegistry;
+ }
+
+ /**
+ * Dispose all nested ActionBarContributors.
+ */
+ @Override
+ public void dispose() {
+ // Dispose nested contributors.
+ for (EditorActionBarContributor contributor : contributors) {
+ contributor.dispose();
+ }
+ super.dispose();
+ }
+
+ /**
+ * Call the same method on each registered nested ActionBarContributors.
+ */
+ @Override
+ public void init(IActionBars bars, IWorkbenchPage page) {
+ super.init(bars, page);
+ buildActions();
+
+ // init nested contributors.
+ for (EditorActionBarContributor contributor : contributors) {
+ contributor.init(bars, page);
+ // remove GMF GlobalSaveAction from bar, fix bug 407854 - [Editor] The save action is disabled in Papyrus
+ bars.setGlobalActionHandler("save", null); // GMF is not using IWorkbenchCommandConstants.FILE_SAVE as ID //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * Load default actions (undo/redo/delete)
+ *
+ * @see org.eclipse.gef.ui.actions.ActionBarContributor#buildActions()
+ */
+ protected void buildActions() {
+ // getActionBars().getToolBarManager().add(new UndoRetargetAction());
+ // getActionBars().getToolBarManager().add(new RedoRetargetAction());
+ }
+
+ @Override
+ public void setActiveEditor(IEditorPart part) {
+ super.setActiveEditor(part);
+ for (EditorActionBarContributor contributor : contributors) {
+ if (part != null) {
+ contributor.setActiveEditor(part);
+ }
+ }
+
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java new file mode 100644 index 00000000000..d5aa13ef15a --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java @@ -0,0 +1,25 @@ +/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * Interface used to get an ActionBarContributor from its ID.
+ *
+ * @author dumoulin
+ *
+ */
+public interface IActionBarContributorFactory {
+
+ /**
+ * Get an ActionBarContributor by its key. If an ActionBarContributor
+ * already exists for this key, return it.
+ *
+ * @param key
+ * @return
+ */
+ public EditorActionBarContributor getActionBarContributor(Object key) throws BackboneException;
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java new file mode 100644 index 00000000000..3b529b2e091 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java @@ -0,0 +1,300 @@ +/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.preferences.dialog.AbstractApplyValueOnPreferenceKeyDialog;
+
+public abstract class AbstractPapyrusPreferenceStore extends PapyrusScopedPreferenceStore {
+
+ /**
+ * key for element level
+ */
+ private final String elementLevelPrefix;
+
+ /**
+ * key for editor level
+ */
+ private final String instanceEditorLevelPrefix;
+
+ /**
+ * key for all editor of the same kind
+ */
+ private final String editorLevelPrefix;
+
+ /**
+ * constructor
+ *
+ * @param context
+ * the scope to store to
+ * @param qualifier
+ * the qualifier used to look up the preference node
+ * @param key
+ * for all editor of the same kind (all diagrams, all tables, ...)
+ * @param key
+ * for an instance of this editor
+ * @param key
+ * for an element
+ */
+ public AbstractPapyrusPreferenceStore(IScopeContext context, String qualifier, String editorLevelPrefix, String instanceEditorLevelPrefix, String elementLevelPrefix) {
+ super(context, qualifier);
+ this.editorLevelPrefix = editorLevelPrefix;
+ this.instanceEditorLevelPrefix = instanceEditorLevelPrefix;
+ this.elementLevelPrefix = elementLevelPrefix;
+ }
+
+ /**
+ * constructor
+ *
+ * @param context
+ * the scope to store to
+ * @param qualifier
+ * the qualifier used to look up the preference node
+ * @param defaultQualifierPath
+ * the qualifier used when looking up the defaults
+ * @param key
+ * for all editor of the same kind (all diagrams, all tables, ...)
+ * @param key
+ * for an instance of this editor
+ * @param key
+ * for an element
+ */
+ public AbstractPapyrusPreferenceStore(IScopeContext context, String qualifier, String defaultQualifierPath, String editorLevelPrefix, String instanceEditorLevelPrefix, String elementLevelPrefix) {
+ super(context, qualifier, defaultQualifierPath);
+ this.editorLevelPrefix = editorLevelPrefix;
+ this.instanceEditorLevelPrefix = instanceEditorLevelPrefix;
+ this.elementLevelPrefix = elementLevelPrefix;
+ }
+
+
+
+
+ /**
+ * this method is used to overload all value under a level of preferences.
+ * In order to overload a pop-up is opened, and the user can choose value to overload
+ *
+ * @param level
+ * of preference: Editor or diagram
+ */
+
+ public void deleteAllSubPreference(String level) {
+ // remove all sub value diagram+ element
+
+ // key to collect
+ List<String> elementKey = new ArrayList<String>();
+ try {
+ for (int i = 0; i < getStorePreferences().keys().length; i++) {
+ // level diagram collect only element
+ if (level.startsWith(instanceEditorLevelPrefix)) {
+ if (getStorePreferences().keys()[i].startsWith(elementLevelPrefix)) {
+ elementKey.add(getStorePreferences().keys()[i]);
+ }
+ }
+ // editor level, collect all element+diagram
+ else if (level.startsWith(editorLevelPrefix)) {
+ if ((getStorePreferences().keys()[i].startsWith(elementLevelPrefix)) || (getStorePreferences().keys()[i].startsWith(instanceEditorLevelPrefix))) {
+ elementKey.add(getStorePreferences().keys()[i]);
+ }
+ }
+
+ }
+
+ } catch (Exception e) {
+ Activator.log.error(e);
+ }
+ if (elementKey.size() > 0) {
+ List<String> keytoRemove = new ArrayList<String>();
+ String[] keyRoconsult = new String[elementKey.size()];
+ AbstractApplyValueOnPreferenceKeyDialog dialog = createPreferenceKeyDialog(elementKey.toArray(keyRoconsult));
+ dialog.open();
+ keytoRemove = dialog.getKeyToRemove();
+
+ // remove key
+ Iterator<String> iterator = keytoRemove.iterator();
+ while (iterator.hasNext()) {
+ String key = iterator.next();
+ getStorePreferences().remove(key);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param keys
+ * @return
+ * the dialog to apply values
+ */
+ protected abstract AbstractApplyValueOnPreferenceKeyDialog createPreferenceKeyDialog(String[] keys);
+
+
+
+ // each get value will be overloaded
+ // if not value is found for an element, a value is look for in DIAGRAM
+ // if a the value is not find for Diagram a value is find for Papyrus editor
+
+
+ /**
+ * this method is used to find a key that a got a value:
+ * if the key is an element. The method look for if this key exist. If no value exists, it look for the key for diagram
+ * if the key for diagram do not exist it look for key for papyrus Editor
+ * the structure of Key is:
+ * element : ELEMENT_DiagramKind_ElementKind.preferenceKind
+ * Diagram : DIAGRAM_DiagramKind.preferenceKind
+ * Editor: PAPYRUS_EDITOR.preferenceKind
+ *
+ */
+ protected String findKeyWithAValue(String initialKey) {
+ String foundedKey = null;
+ // first look for in value stack
+ foundedKey = findKeyAStoreValue(initialKey);
+ // then look for in default stack
+ if (foundedKey == null) {
+ foundedKey = findKeyWithADefaultValue(initialKey);
+ }
+ if (foundedKey == null) {
+ foundedKey = initialKey;
+ }
+ return foundedKey;
+
+ }
+
+ /**
+ * look for a key with a value in the store stack
+ *
+ * @param initialKey
+ * element : ELEMENT_DiagramKind_ElementKind.preferenceKind
+ * Diagram : DIAGRAM_DiagramKind.preferenceKind
+ * Editor: PAPYRUS_EDITOR.preferenceKind
+ * @return the key that returns a value or null if there is no value
+ */
+ protected String findKeyAStoreValue(String initialKey) {
+ String foundedKey = null;
+ if (getStorePreferences().get(initialKey, null) != null) {
+ foundedKey = initialKey;
+ }
+
+ if (foundedKey == null && hasPrefix(initialKey)) {
+ foundedKey = findKeyAStoreValue(getUpperKey(initialKey));
+ }
+ return foundedKey;
+ }
+
+ /**
+ * this method is used to find a key that a got a value:
+ * if the key is an element. The method look for if this key exist. If no value exists, it look for the key for diagram
+ * if the key for diagram do not exist it look for key for papyrus Editor
+ * the structure of Key is:
+ * element : ELEMENT_DiagramKind_ElementKind.preferenceKind
+ * Diagram : DIAGRAM_DiagramKind.preferenceKind
+ * Editor: PAPYRUS_EDITOR.preferenceKind
+ *
+ */
+ protected String findKeyWithADefaultValue(String initialKey) {
+ String foundedKey = null;
+
+ if (getDefaultPreferences().get(initialKey, null) != null) {
+ foundedKey = initialKey;
+ }
+
+ if (foundedKey == null && hasPrefix(initialKey)) {
+ return findKeyWithADefaultValue(getUpperKey(initialKey));
+ } else {
+ foundedKey = initialKey;
+ }
+ return foundedKey;
+
+ }
+
+ /**
+ * get the upper Key from the initial Key
+ * * the structure of Key is:
+ * element : ELEMENT_DiagramKind_ElementKind.preferenceKind
+ * Diagram : DIAGRAM_DiagramKind.preferenceKind
+ * Editor: PAPYRUS_EDITOR.preferenceKind
+ *
+ * @param initialKey
+ * @return the upperKey
+ *
+ */
+ protected String getUpperKey(String initialKey) {
+
+ String out = initialKey.toString();
+ if (initialKey.startsWith(elementLevelPrefix)) {
+ out = initialKey.toString().replaceAll(elementLevelPrefix, instanceEditorLevelPrefix);
+ out = out.substring(0, out.lastIndexOf("_")) + out.substring(out.indexOf("."), out.length());
+ }
+ if (initialKey.startsWith(instanceEditorLevelPrefix)) {
+ // out=initialKey.toString().replaceAll(instanceEditorLevelPrefix, editorLevelPrefix);
+ out = editorLevelPrefix + out.substring(out.indexOf("."), out.length());
+ }
+ return out;
+ }
+
+ protected boolean hasPrefix(String key) {
+ if (key.startsWith(elementLevelPrefix) || key.startsWith(instanceEditorLevelPrefix)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * get the value from a key
+ *
+ * @param key
+ * @return the value
+ */
+ @Override
+ protected String internalGet(String key) {
+ String newKey = findKeyWithAValue(key);
+ // System.err.println("-->Initial Key "+key+"--> "+ newKey);
+ return Platform.getPreferencesService().get(newKey, null, getPreferenceNodes(true));
+ }
+
+ @Override
+ public boolean getDefaultBoolean(String name) {
+
+ return super.getDefaultBoolean(findKeyWithADefaultValue(name));
+ }
+
+ @Override
+ public double getDefaultDouble(String name) {
+ return super.getDefaultDouble(findKeyWithADefaultValue(name));
+ }
+
+ @Override
+ public float getDefaultFloat(String name) {
+ return super.getDefaultFloat(findKeyWithADefaultValue(name));
+ };
+
+ @Override
+ public int getDefaultInt(String name) {
+ return super.getDefaultInt(findKeyWithADefaultValue(name));
+ }
+
+ @Override
+ public long getDefaultLong(String name) {
+ return super.getDefaultLong(findKeyWithADefaultValue(name));
+ }
+
+ @Override
+ public String getDefaultString(String name) {
+ return super.getDefaultString(findKeyWithADefaultValue(name));
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java new file mode 100644 index 00000000000..f3ec34c88c1 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java @@ -0,0 +1,858 @@ +/***************************************************************************** + * Copyright (c) 2010 CEA LIST. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.preferences; + +/*************************************************************************** + Copyright (c) 2010 CEA LIST. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * + * Contributors: + * the code is copy from ScopedPreferenceStore but I have open some methods in order to be + * available for the overload + * + * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation + * + * + *******************************************************************************/ + +import java.io.IOException; + +import org.eclipse.core.commands.common.EventManager; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.eclipse.jface.preference.IPersistentPreferenceStore; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.util.SafeRunnable; +import org.eclipse.ui.internal.WorkbenchMessages; +import org.osgi.service.prefs.BackingStoreException; + +/** + * The ScopedPreferenceStore is an IPreferenceStore that uses the scopes + * provided in org.eclipse.core.runtime.preferences. + * <p> + * A ScopedPreferenceStore does the lookup of a preference based on it's search scopes and sets the value of the preference based on its store scope. + * </p> + * <p> + * The default scope is always included in the search scopes when searching for preference values. + * </p> + * + * @see org.eclipse.core.runtime.preferences + * @since 3.1 + */ +public class PapyrusScopedPreferenceStore extends EventManager implements IPreferenceStore, IPersistentPreferenceStore { + + /** + * The storeContext is the context where values will stored with the + * setValue methods. If there are no searchContexts this will be the search + * context. (along with the "default" context) + */ + protected IScopeContext storeContext; + + /** + * The searchContext is the array of contexts that will be used by the get + * methods for searching for values. + */ + protected IScopeContext[] searchContexts; + + /** + * A boolean to indicate the property changes should not be propagated. + */ + protected boolean silentRunning = false; + + /** + * The listener on the IEclipsePreferences. This is used to forward updates + * to the property change listeners on the preference store. + */ + protected IEclipsePreferences.IPreferenceChangeListener preferencesListener; + + /** + * The default context is the context where getDefault and setDefault + * methods will search. This context is also used in the search. + */ + protected IScopeContext defaultContext = DefaultScope.INSTANCE; + + /** + * The nodeQualifer is the string used to look up the node in the contexts. + */ + protected String nodeQualifier; + + /** + * The defaultQualifier is the string used to look up the default node. + */ + protected String defaultQualifier; + + /** + * Boolean value indicating whether or not this store has changes to be + * saved. + */ + private boolean dirty; + + /** + * Create a new instance of the receiver. Store the values in context in the + * node looked up by qualifier. <strong>NOTE:</strong> Any instance of + * ScopedPreferenceStore should call + * + * @param context + * the scope to store to + * @param qualifier + * the qualifier used to look up the preference node + * @param defaultQualifierPath + * the qualifier used when looking up the defaults + */ + public PapyrusScopedPreferenceStore(IScopeContext context, String qualifier, String defaultQualifierPath) { + this(context, qualifier); + this.defaultQualifier = defaultQualifierPath; + } + + /** + * Create a new instance of the receiver. Store the values in context in the + * node looked up by qualifier. + * + * @param context + * the scope to store to + * @param qualifier + * the qualifer used to look up the preference node + */ + public PapyrusScopedPreferenceStore(IScopeContext context, String qualifier) { + storeContext = context; + this.nodeQualifier = qualifier; + this.defaultQualifier = qualifier; + + ((IEclipsePreferences) getStorePreferences().parent()).addNodeChangeListener(getNodeChangeListener()); + } + + /** + * Return a node change listener that adds a removes the receiver when nodes + * change. + * + * @return INodeChangeListener + */ + private INodeChangeListener getNodeChangeListener() { + return new IEclipsePreferences.INodeChangeListener() { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#added(org.eclipse.core.runtime.preferences.IEclipsePreferences + * .NodeChangeEvent) + */ + public void added(NodeChangeEvent event) { + if (nodeQualifier.equals(event.getChild().name()) && isListenerAttached()) { + getStorePreferences().addPreferenceChangeListener(preferencesListener); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#removed(org.eclipse.core.runtime.preferences. + * IEclipsePreferences.NodeChangeEvent) + */ + public void removed(NodeChangeEvent event) { + // Do nothing as there are no events from removed node + } + }; + } + + /** + * Initialize the preferences listener. + */ + private void initializePreferencesListener() { + if (preferencesListener == null) { + preferencesListener = new IEclipsePreferences.IPreferenceChangeListener() { + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime. + * preferences.IEclipsePreferences.PreferenceChangeEvent) + */ + public void preferenceChange(PreferenceChangeEvent event) { + + if (silentRunning) { + return; + } + + Object oldValue = event.getOldValue(); + Object newValue = event.getNewValue(); + String key = event.getKey(); + if (newValue == null) { + newValue = getDefault(key, oldValue); + } else if (oldValue == null) { + oldValue = getDefault(key, newValue); + } + firePropertyChangeEvent(event.getKey(), oldValue, newValue); + } + }; + getStorePreferences().addPreferenceChangeListener(preferencesListener); + } + + } + + /** + * Does its best at determining the default value for the given key. Checks + * the given object's type and then looks in the list of defaults to see if + * a value exists. If not or if there is a problem converting the value, the + * default default value for that type is returned. + * + * @param key + * the key to search + * @param obj + * the object who default we are looking for + * @return Object or <code>null</code> + */ + protected Object getDefault(String key, Object obj) { + IEclipsePreferences defaults = getDefaultPreferences(); + if (obj instanceof String) { + return defaults.get(key, STRING_DEFAULT_DEFAULT); + } else if (obj instanceof Integer) { + return Integer.valueOf(defaults.getInt(key, INT_DEFAULT_DEFAULT)); + } else if (obj instanceof Double) { + return new Double(defaults.getDouble(key, DOUBLE_DEFAULT_DEFAULT)); + } else if (obj instanceof Float) { + return new Float(defaults.getFloat(key, FLOAT_DEFAULT_DEFAULT)); + } else if (obj instanceof Long) { + return Long.valueOf(defaults.getLong(key, LONG_DEFAULT_DEFAULT)); + } else if (obj instanceof Boolean) { + return defaults.getBoolean(key, BOOLEAN_DEFAULT_DEFAULT) ? Boolean.TRUE : Boolean.FALSE; + } else { + return null; + } + } + + /** + * Return the IEclipsePreferences node associated with this store. + * + * @return the preference node for this store + */ + protected IEclipsePreferences getStorePreferences() { + return storeContext.getNode(nodeQualifier); + } + + /** + * Return the default IEclipsePreferences for this store. + * + * @return this store's default preference node + */ + protected IEclipsePreferences getDefaultPreferences() { + return defaultContext.getNode(defaultQualifier); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener) + */ + public void addPropertyChangeListener(IPropertyChangeListener listener) { + initializePreferencesListener();// Create the preferences listener if it + // does not exist + addListenerObject(listener); + } + + /** + * Return the preference path to search preferences on. This is the list of + * preference nodes based on the scope contexts for this store. If there are + * no search contexts set, then return this store's context. + * <p> + * Whether or not the default context should be included in the resulting list is specified by the <code>includeDefault</code> parameter. + * </p> + * + * @param includeDefault + * <code>true</code> if the default context should be included + * and <code>false</code> otherwise + * @return IEclipsePreferences[] + * @since 3.4 public, was added in 3.1 as private method + */ + public IEclipsePreferences[] getPreferenceNodes(boolean includeDefault) { + // if the user didn't specify a search order, then return the scope that + // this store was created on. (and optionally the default) + if (searchContexts == null) { + if (includeDefault) { + return new IEclipsePreferences[] { getStorePreferences(), getDefaultPreferences() }; + } + return new IEclipsePreferences[] { getStorePreferences() }; + } + // otherwise the user specified a search order so return the appropriate + // nodes based on it + int length = searchContexts.length; + if (includeDefault) { + length++; + } + IEclipsePreferences[] preferences = new IEclipsePreferences[length]; + for (int i = 0; i < searchContexts.length; i++) { + preferences[i] = searchContexts[i].getNode(nodeQualifier); + } + if (includeDefault) { + preferences[length - 1] = getDefaultPreferences(); + } + return preferences; + } + + /** + * Set the search contexts to scopes. When searching for a value the seach + * will be done in the order of scope contexts and will not search the + * storeContext unless it is in this list. + * <p> + * If the given list is <code>null</code>, then clear this store's search contexts. This means that only this store's scope context and default scope will be used during preference value searching. + * </p> + * <p> + * The defaultContext will be added to the end of this list automatically and <em>MUST NOT</em> be included by the user. + * </p> + * + * @param scopes + * a list of scope contexts to use when searching, or <code>null</code> + */ + public void setSearchContexts(IScopeContext[] scopes) { + this.searchContexts = scopes; + if (scopes == null) { + return; + } + + // Assert that the default was not included (we automatically add it to + // the end) + for (int i = 0; i < scopes.length; i++) { + if (scopes[i].equals(defaultContext)) { + Assert.isTrue(false, WorkbenchMessages.ScopedPreferenceStore_DefaultAddedError); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#contains(java.lang.String) + */ + public boolean contains(String name) { + if (name == null) { + return false; + } + return (Platform.getPreferencesService().get(name, null, getPreferenceNodes(true))) != null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#firePropertyChangeEvent(java.lang.String, + * java.lang.Object, java.lang.Object) + */ + public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) { + // important: create intermediate array to protect against listeners + // being added/removed during the notification + final Object[] list = getListeners(); + if (list.length == 0) { + return; + } + final PropertyChangeEvent event = new PropertyChangeEvent(this, name, oldValue, newValue); + for (int i = 0; i < list.length; i++) { + final IPropertyChangeListener listener = (IPropertyChangeListener) list[i]; + SafeRunner.run(new SafeRunnable(JFaceResources.getString("PreferenceStore.changeError")) { //$NON-NLS-1$ + + public void run() { + listener.propertyChange(event); + } + }); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getBoolean(java.lang.String) + */ + public boolean getBoolean(String name) { + String value = internalGet(name); + return value == null ? BOOLEAN_DEFAULT_DEFAULT : Boolean.valueOf(value).booleanValue(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultBoolean(java.lang.String) + */ + public boolean getDefaultBoolean(String name) { + return getDefaultPreferences().getBoolean(name, BOOLEAN_DEFAULT_DEFAULT); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultDouble(java.lang.String) + */ + public double getDefaultDouble(String name) { + return getDefaultPreferences().getDouble(name, DOUBLE_DEFAULT_DEFAULT); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultFloat(java.lang.String) + */ + public float getDefaultFloat(String name) { + return getDefaultPreferences().getFloat(name, FLOAT_DEFAULT_DEFAULT); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultInt(java.lang.String) + */ + public int getDefaultInt(String name) { + return getDefaultPreferences().getInt(name, INT_DEFAULT_DEFAULT); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultLong(java.lang.String) + */ + public long getDefaultLong(String name) { + return getDefaultPreferences().getLong(name, LONG_DEFAULT_DEFAULT); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultString(java.lang.String) + */ + public String getDefaultString(String name) { + return getDefaultPreferences().get(name, STRING_DEFAULT_DEFAULT); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getDouble(java.lang.String) + */ + public double getDouble(String name) { + String value = internalGet(name); + if (value == null) { + return DOUBLE_DEFAULT_DEFAULT; + } + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + return DOUBLE_DEFAULT_DEFAULT; + } + } + + /** + * Return the string value for the specified key. Look in the nodes which + * are specified by this object's list of search scopes. If the value does + * not exist then return <code>null</code>. + * + * @param key + * the key to search with + * @return String or <code>null</code> if the value does not exist. + */ + protected String internalGet(String key) { + return Platform.getPreferencesService().get(key, null, getPreferenceNodes(true)); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getFloat(java.lang.String) + */ + public float getFloat(String name) { + String value = internalGet(name); + if (value == null) { + return FLOAT_DEFAULT_DEFAULT; + } + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + return FLOAT_DEFAULT_DEFAULT; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getInt(java.lang.String) + */ + public int getInt(String name) { + String value = internalGet(name); + if (value == null) { + return INT_DEFAULT_DEFAULT; + } + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return INT_DEFAULT_DEFAULT; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getLong(java.lang.String) + */ + public long getLong(String name) { + String value = internalGet(name); + if (value == null) { + return LONG_DEFAULT_DEFAULT; + } + try { + return Long.parseLong(value); + } catch (NumberFormatException e) { + return LONG_DEFAULT_DEFAULT; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#getString(java.lang.String) + */ + public String getString(String name) { + String value = internalGet(name); + return value == null ? STRING_DEFAULT_DEFAULT : value; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#isDefault(java.lang.String) + */ + public boolean isDefault(String name) { + if (name == null) { + return false; + } + return (Platform.getPreferencesService().get(name, null, getPreferenceNodes(false))) == null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#needsSaving() + */ + public boolean needsSaving() { + return dirty; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#putValue(java.lang.String, + * java.lang.String) + */ + public void putValue(String name, String value) { + try { + // Do not notify listeners + silentRunning = true; + getStorePreferences().put(name, value); + } finally { + // Be sure that an exception does not stop property updates + silentRunning = false; + dirty = true; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener) + */ + public void removePropertyChangeListener(IPropertyChangeListener listener) { + removeListenerObject(listener); + if (!isListenerAttached()) { + disposePreferenceStoreListener(); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, + * double) + */ + public void setDefault(String name, double value) { + getDefaultPreferences().putDouble(name, value); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, + * float) + */ + public void setDefault(String name, float value) { + getDefaultPreferences().putFloat(name, value); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, + * int) + */ + public void setDefault(String name, int value) { + getDefaultPreferences().putInt(name, value); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, + * long) + */ + public void setDefault(String name, long value) { + getDefaultPreferences().putLong(name, value); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, + * java.lang.String) + */ + public void setDefault(String name, String defaultObject) { + getDefaultPreferences().put(name, defaultObject); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String, + * boolean) + */ + public void setDefault(String name, boolean value) { + getDefaultPreferences().putBoolean(name, value); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setToDefault(java.lang.String) + */ + public void setToDefault(String name) { + + String oldValue = getString(name); + String defaultValue = getDefaultString(name); + try { + silentRunning = true;// Turn off updates from the store + // removing a non-existing preference is a no-op so call the Core + // API directly + getStorePreferences().remove(name); + if (!oldValue.equals(defaultValue)) { + dirty = true; + firePropertyChangeEvent(name, oldValue, defaultValue); + } + + } finally { + silentRunning = false;// Restart listening to preferences + } + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, + * double) + */ + public void setValue(String name, double value) { + double oldValue = getDouble(name); + if (oldValue == value) { + return; + } + try { + silentRunning = true;// Turn off updates from the store + if (getDefaultDouble(name) == value) { + getStorePreferences().remove(name); + } else { + getStorePreferences().putDouble(name, value); + } + dirty = true; + firePropertyChangeEvent(name, new Double(oldValue), new Double(value)); + } finally { + silentRunning = false;// Restart listening to preferences + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, + * float) + */ + public void setValue(String name, float value) { + float oldValue = getFloat(name); + if (oldValue == value) { + return; + } + try { + silentRunning = true;// Turn off updates from the store + if (getDefaultFloat(name) == value) { + getStorePreferences().remove(name); + } else { + getStorePreferences().putFloat(name, value); + } + dirty = true; + firePropertyChangeEvent(name, new Float(oldValue), new Float(value)); + } finally { + silentRunning = false;// Restart listening to preferences + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, + * int) + */ + public void setValue(String name, int value) { + int oldValue = getInt(name); + if (oldValue == value) { + return; + } + try { + silentRunning = true;// Turn off updates from the store + if (getDefaultInt(name) == value) { + getStorePreferences().remove(name); + } else { + getStorePreferences().putInt(name, value); + } + dirty = true; + firePropertyChangeEvent(name, Integer.valueOf(oldValue), Integer.valueOf(value)); + } finally { + silentRunning = false;// Restart listening to preferences + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, + * long) + */ + public void setValue(String name, long value) { + long oldValue = getLong(name); + if (oldValue == value) { + return; + } + try { + silentRunning = true;// Turn off updates from the store + if (getDefaultLong(name) == value) { + getStorePreferences().remove(name); + } else { + getStorePreferences().putLong(name, value); + } + dirty = true; + firePropertyChangeEvent(name, Long.valueOf(oldValue), Long.valueOf(value)); + } finally { + silentRunning = false;// Restart listening to preferences + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, + * java.lang.String) + */ + public void setValue(String name, String value) { + // Do not turn on silent running here as Strings are propagated + if (getDefaultString(name).equals(value)) { + getStorePreferences().remove(name); + } else { + getStorePreferences().put(name, value); + } + dirty = true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String, + * boolean) + */ + public void setValue(String name, boolean value) { + boolean oldValue = getBoolean(name); + if (oldValue == value) { + return; + } + try { + silentRunning = true;// Turn off updates from the store + if (getDefaultBoolean(name) == value) { + getStorePreferences().remove(name); + } else { + getStorePreferences().putBoolean(name, value); + } + dirty = true; + firePropertyChangeEvent(name, oldValue ? Boolean.TRUE : Boolean.FALSE, value ? Boolean.TRUE : Boolean.FALSE); + } finally { + silentRunning = false;// Restart listening to preferences + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPersistentPreferenceStore#save() + */ + public void save() throws IOException { + try { + getStorePreferences().flush(); + dirty = false; + } catch (BackingStoreException e) { + throw new IOException(e.getMessage()); + } + + } + + /** + * Dispose the receiver. + */ + private void disposePreferenceStoreListener() { + + IEclipsePreferences root = (IEclipsePreferences) Platform.getPreferencesService().getRootNode().node(Plugin.PLUGIN_PREFERENCE_SCOPE); + try { + if (!(root.nodeExists(nodeQualifier))) { + return; + } + } catch (BackingStoreException e) { + return;// No need to report here as the node won't have the + // listener + } + + IEclipsePreferences preferences = getStorePreferences(); + if (preferences == null) { + return; + } + if (preferencesListener != null) { + preferences.removePreferenceChangeListener(preferencesListener); + preferencesListener = null; + } + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java new file mode 100644 index 00000000000..f21f02085d6 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java @@ -0,0 +1,71 @@ +/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences.dialog;
+
+import java.util.ArrayList;
+
+/**
+ * The Class ApplyValueOnPreferenceKeyDialog display all the preference key and give all selected keys
+ */
+public abstract class AbstractApplyValueOnPreferenceKeyDialog extends AbstractPreferenceKeyDialog {
+
+ /** The checked key. */
+ protected ArrayList<String> checkedKey;
+
+ /**
+ * Instantiates a new apply value on preference key dialog.
+ *
+ * @param keys
+ * the keys
+ */
+ public AbstractApplyValueOnPreferenceKeyDialog(String[] keys) {
+ super(keys);
+ checkedKey = new ArrayList<String>();
+ }
+
+ /**
+ * Gets the key to remove.
+ *
+ * @return the key to remove
+ */
+ public ArrayList<String> getKeyToRemove() {
+ return checkedKey;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#okPressed()
+ */
+ @Override
+ protected void okPressed() {
+ for (int i = 0; i < keyTable.getItems().length; i++) {
+ if (keyTable.getItems()[i].getChecked()) {
+ checkedKey.add((String) keyTable.getItems()[i].getData());
+ }
+ }
+ super.okPressed();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#cancelPressed()
+ */
+ @Override
+ protected void cancelPressed() {
+ super.cancelPressed();
+ checkedKey = new ArrayList<String>();
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java new file mode 100644 index 00000000000..9265a692051 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java @@ -0,0 +1,105 @@ +/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences.dialog;
+
+import java.util.Arrays;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.messages.Messages;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * The Class AbstractPreferenceKeyDialog display all preference key that are given in parameters
+ */
+public abstract class AbstractPreferenceKeyDialog extends org.eclipse.jface.dialogs.StatusDialog {
+
+ /** The key table. */
+ protected Table keyTable;
+
+ /** The table viewer. */
+ protected TableViewer tableViewer;
+
+ /** The keys. */
+ protected String[] keys;
+
+ /**
+ * Instantiates a new abstract preference key dialog.
+ *
+ * @param keys
+ * the array of preference jy to display
+ */
+ public AbstractPreferenceKeyDialog(String[] keys) {
+ super(new Shell());
+ this.keys = Arrays.copyOf(keys, keys.length);
+ setStatusLineAboveButtons(true);
+ updateStatus(new Status(IStatus.INFO, Activator.PLUGIN_ID, Messages.AbstractPreferenceKeyDialog_WouldYouLikeOverloadPreferences));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+ keyTable = new Table(composite, SWT.CHECK | SWT.BORDER);
+ tableViewer = new TableViewer(keyTable);
+ tableViewer.setLabelProvider(createLabelProvider());
+ tableViewer.setContentProvider(createContentProvider());
+
+ TableColumn column = new TableColumn(keyTable, SWT.NONE);
+ column.setWidth(150);
+ column.setText(Messages.AbstractPreferenceKeyDialog_Pref_Kind);
+
+ column = new TableColumn(keyTable, SWT.NONE);
+ column.setWidth(90);
+ column.setText(Messages.AbstractPreferenceKeyDialog_Level);
+
+ column = new TableColumn(keyTable, SWT.NONE);
+ column.setWidth(200);
+ column.setText(Messages.AbstractPreferenceKeyDialog_Localization);
+ tableViewer.setInput(keys);
+ keyTable.setHeaderVisible(true);
+
+
+ return composite;
+
+ }
+
+ /**
+ *
+ * @return
+ * the label provider for the table viewer
+ */
+ protected abstract IBaseLabelProvider createLabelProvider();
+
+ /**
+ *
+ * @return
+ * the content provider for the table viewer
+ */
+ protected abstract IContentProvider createContentProvider();
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java new file mode 100644 index 00000000000..7264ae39750 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java @@ -0,0 +1,55 @@ +/*****************************************************************************
+ * Copyright (c) 2013, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 469188
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services;
+
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+/**
+ * Listens to the Lifecycle of an {@link IMultiDiagramEditor}
+ *
+ * @author Camille Letavernier
+ *
+ */
+public interface EditorLifecycleEventListener {
+
+ /**
+ * The ServicesRegistry is successfully started
+ *
+ * @param editor
+ */
+ public void postInit(IMultiDiagramEditor editor);
+
+ /**
+ * All the editors are constructed, but not yet displayed
+ *
+ * @param editor
+ */
+ public default void preDisplay(IMultiDiagramEditor editor) {
+ // Pass
+ }
+
+ /**
+ * All the editors are displayed
+ *
+ * @param editor
+ */
+ public void postDisplay(IMultiDiagramEditor editor);
+
+ /**
+ * The editor is about to be closed
+ *
+ * @param editor
+ */
+ public void beforeClose(IMultiDiagramEditor editor);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java new file mode 100644 index 00000000000..2866903aa39 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java @@ -0,0 +1,30 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services;
+
+import org.eclipse.papyrus.infra.core.services.IService;
+
+/**
+ * The LifecycleManager for IMultiDiagramEditor
+ *
+ * It notifies its listeners when the state of the editor changes
+ *
+ * @author Camille Letavernier
+ *
+ */
+public interface EditorLifecycleManager extends IService {
+
+ public void addEditorLifecycleEventsListener(EditorLifecycleEventListener listener);
+
+ public void removeEditorLifecycleEventsListener(EditorLifecycleEventListener listener);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java new file mode 100644 index 00000000000..58482ab0e2c --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java @@ -0,0 +1,34 @@ +/***************************************************************************** + * Copyright (c) 2015 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.services; + +import org.eclipse.osgi.util.NLS; + +/** + * Translatable strings. + */ +class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.papyrus.infra.core.services.messages"; //$NON-NLS-1$ + public static String SaveLayoutBeforeClose_0; + public static String SaveLayoutBeforeClose_1; + public static String SaveLayoutBeforeClose_2; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java new file mode 100644 index 00000000000..423727e534f --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java @@ -0,0 +1,292 @@ +/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437217
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.ConcurrentMap;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor.DirtyPolicy;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.DoSaveEvent;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ILifeCycleEventsProvider;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ISaveEventListener;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.ui.progress.UIJob;
+
+import com.google.common.collect.Maps;
+
+/**
+ * A Service to check workspace modifications on current resources
+ *
+ * @author Camille Letavernier
+ *
+ */
+public class ResourceUpdateService implements IService, IPartListener {
+
+ protected ServicesRegistry registry;
+
+ protected ModelSet modelSet;
+
+ static int[] handledTypes = new int[] { IResourceChangeEvent.POST_CHANGE, IResourceChangeEvent.PRE_DELETE, IResourceChangeEvent.PRE_CLOSE };
+
+ protected boolean isSaving;
+
+ protected ConcurrentMap<IMultiDiagramEditor, Job> pendingEditorCloseJobs = Maps.newConcurrentMap();
+
+ private final ISaveEventListener preSaveListener = new ISaveEventListener() {
+
+ @Override
+ public void doSaveAs(DoSaveEvent event) {
+ isSaving = true;
+ }
+
+ @Override
+ public void doSave(DoSaveEvent event) {
+ isSaving = true;
+ }
+ };
+
+ private final ISaveEventListener postSaveListener = new ISaveEventListener() {
+
+ @Override
+ public void doSaveAs(DoSaveEvent event) {
+ isSaving = false;
+ }
+
+ @Override
+ public void doSave(DoSaveEvent event) {
+ isSaving = false;
+ }
+ };
+
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ this.registry = servicesRegistry;
+ }
+
+ @Override
+ public void startService() throws ServiceException {
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener, IResourceChangeEvent.POST_CHANGE);
+ modelSet = registry.getService(ModelSet.class);
+ registry.getService(ILifeCycleEventsProvider.class).addAboutToDoSaveListener(preSaveListener);
+ registry.getService(ILifeCycleEventsProvider.class).addPostDoSaveListener(postSaveListener);
+ }
+
+ @Override
+ public void disposeService() throws ServiceException {
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener);
+ modelSet = null;
+ }
+
+ protected void closeEditor() {
+ closeEditor(Collections.<Resource> emptyList(), false);
+ }
+
+ protected void closeEditor(final Collection<? extends Resource> triggeringResources, final boolean reopen) {
+ try {
+ if (!reopen) {
+ registry.remove(SaveLayoutBeforeClose.class.getName());
+ }
+
+ final IMultiDiagramEditor editor = registry.getService(IMultiDiagramEditor.class);
+ if (editor != null) {
+ final IWorkbenchPartSite site = editor.getSite();
+ UIJob closeEditorJob = new UIJob(site.getShell().getDisplay(), NLS.bind("Reload editor {0}", editor.getTitle())) {
+
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ // Remove the pending job
+ pendingEditorCloseJobs.remove(editor);
+
+ IStatus result = Status.OK_STATUS;
+ monitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
+
+ try {
+ IReloadableEditor.ReloadReason reason = reopen ? IReloadableEditor.ReloadReason.RESOURCES_CHANGED : IReloadableEditor.ReloadReason.RESOURCES_DELETED;
+
+ DirtyPolicy dirtyPolicy = DirtyPolicy.getDefault();
+ if (!reopen && !editor.isDirty()) {
+ // Check whether we're deleting one of our own resources. If so, just close
+ URI principalURI = modelSet.getURIWithoutExtension();
+ for (Resource next : triggeringResources) {
+ if (next.getURI().trimFileExtension().equals(principalURI)) {
+ dirtyPolicy = DirtyPolicy.DO_NOT_SAVE;
+ break;
+ }
+ }
+ }
+
+ try {
+ IReloadableEditor.Adapter.getAdapter(editor).reloadEditor(triggeringResources, reason, dirtyPolicy);
+ } catch (CoreException e) {
+ result = e.getStatus();
+ }
+ } finally {
+ monitor.done();
+ }
+
+ return result;
+ }
+ };
+
+ // We are notified usually of at least three resources (*.di, *.notation, *.uml) that are unloaded, but
+ // there's no need to close and re-open the same editor three times
+ if (pendingEditorCloseJobs.putIfAbsent(editor, closeEditorJob) == null) {
+ // Async execution to avoid lock conflicts on the Workspace (Probably owned by this thread, and not the UI thread)
+ IWorkbenchSiteProgressService progressService = site.getService(IWorkbenchSiteProgressService.class);
+ progressService.schedule(closeEditorJob);
+ }
+ }
+ } catch (ServiceException ex) {
+ // Nothing
+ }
+ }
+
+ protected void handleResourcesRemoved(Collection<Resource> emfResources) {
+ closeEditor(emfResources, false);
+ }
+
+ protected void handleResourceChanged(Collection<Resource> emfResources) {
+ closeEditor(emfResources, true);
+ }
+
+ // Copied from org.eclipse.emf.ecore.presentation.EcoreEditor
+ protected IResourceChangeListener resourceChangeListener = new IResourceChangeListener() {
+
+ @Override
+ public void resourceChanged(IResourceChangeEvent event) {
+ IResourceDelta delta = event.getDelta();
+ try {
+ class ResourceDeltaVisitor implements IResourceDeltaVisitor {
+
+ protected Collection<Resource> changedResources = new ArrayList<Resource>();
+
+ protected Collection<Resource> removedResources = new ArrayList<Resource>();
+
+ @Override
+ public boolean visit(final IResourceDelta delta) {
+ if (delta.getResource().getType() == IResource.FILE) {
+ if (delta.getKind() == IResourceDelta.REMOVED || delta.getKind() == IResourceDelta.CHANGED) {
+ URI resourceURI = URI.createPlatformResourceURI(delta.getFullPath().toString(), true);
+ Resource resource = modelSet.getResource(resourceURI, false);
+ if (resource == null) {
+ // try again, with a pluginURI, see bug 418428
+ URI pluginURI = URI.createPlatformPluginURI(delta.getFullPath().toString(), true);
+ resource = modelSet.getResource(pluginURI, false);
+ }
+ if (resource != null) {
+
+ if (delta.getKind() == IResourceDelta.REMOVED) {
+ removedResources.add(resource);
+ } else {
+ if ((delta.getFlags() & IResourceDelta.MARKERS) != 0) {
+ // Skip markers
+ // DiagnosticDecorator.DiagnosticAdapter.update(resource, markerHelper.getMarkerDiagnostics(resource, (IFile)delta.getResource()));
+ }
+ if ((delta.getFlags() & IResourceDelta.CONTENT) != 0) {
+ // if(!savedResources.remove(resource)) {
+ // changedResources.add(resource);
+ // }
+ if (!isSaving) {
+ changedResources.add(resource);
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ public Collection<Resource> getChangedResources() {
+ return changedResources;
+ }
+
+ public Collection<Resource> getRemovedResources() {
+ return removedResources;
+ }
+ }
+
+ final ResourceDeltaVisitor visitor = new ResourceDeltaVisitor();
+
+ delta.accept(visitor);
+
+ if (!visitor.getRemovedResources().isEmpty()) {
+ handleResourcesRemoved(visitor.getRemovedResources());
+ }
+
+ if (!visitor.getChangedResources().isEmpty()) {
+ handleResourceChanged(visitor.getChangedResources());
+ }
+ } catch (CoreException exception) {
+ Activator.log.error(exception);
+ }
+ }
+ };
+
+ @Override
+ public void partActivated(IWorkbenchPart part) {
+ // Nothing
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPart part) {
+ // Nothing
+ }
+
+ @Override
+ public void partClosed(IWorkbenchPart part) {
+ // Nothing
+ }
+
+ @Override
+ public void partDeactivated(IWorkbenchPart part) {
+ // Nothing
+ }
+
+ @Override
+ public void partOpened(IWorkbenchPart part) {
+ // Nothing
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java new file mode 100644 index 00000000000..0243ca859b1 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java @@ -0,0 +1,218 @@ +/*****************************************************************************
+ * Copyright (c) 2014, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 434983
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services;
+
+import java.io.IOException;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel;
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.internal.commands.TogglePageLayoutStorageHandler;
+import org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences;
+import org.eclipse.papyrus.infra.ui.internal.preferences.YesNo;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.DoSaveEvent;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ILifeCycleEventsProvider;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.LifeCycleEventsProvider;
+
+/**
+ * This service automatically saves the current SashModel before closing the Papyrus editor
+ *
+ * This is useful, as modifications to the SashModel do not dirty the editor
+ *
+ * The save action is not executed if the editor is dirty when it is closed (To ensure model consistency)
+ *
+ * Bug 430976: [SashEditor] Editor layout is not exactly the same when reopening the model
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=430976
+ *
+ * @author Camille Letavernier
+ */
+public class SaveLayoutBeforeClose implements IService {
+
+ private ServicesRegistry registry;
+
+ private EditorLifecycleManager lifecycleManager;
+
+ private EditorLifecycleEventListener lifecycleListener;
+
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ this.registry = servicesRegistry;
+ }
+
+ @Override
+ public void startService() throws ServiceException {
+ installSaveOnClose();
+ }
+
+ protected void installSaveOnClose() {
+ try {
+ lifecycleManager = registry.getService(EditorLifecycleManager.class);
+ if (lifecycleManager == null) {
+ return;
+ }
+ } catch (ServiceException ex) {
+ return;
+ }
+
+ lifecycleListener = new EditorLifecycleEventListener() {
+
+ @Override
+ public void postInit(IMultiDiagramEditor editor) {
+ // Nothing
+ }
+
+ @Override
+ public void postDisplay(IMultiDiagramEditor editor) {
+ checkSharedLayout(editor);
+ }
+
+ @Override
+ public void beforeClose(IMultiDiagramEditor editor) {
+ saveBeforeClose(editor);
+ }
+ };
+
+ lifecycleManager.addEditorLifecycleEventsListener(lifecycleListener);
+ }
+
+ public void saveBeforeClose(IMultiDiagramEditor editor) {
+ if (editor.isDirty()) {
+ return; // User explicitly quit without saving. Do nothing (And if user wants to save during exit, the sashmodel will be saved anyway)
+ }
+
+ ModelSet modelSet; // Required
+ LifeCycleEventsProvider internalLifecycleEventsProvider = null; // Optional
+
+ try {
+ modelSet = registry.getService(ModelSet.class);
+ } catch (ServiceException ex) {
+ return;
+ }
+
+ try {
+ ILifeCycleEventsProvider eventsProvider = registry.getService(ILifeCycleEventsProvider.class);
+ if (eventsProvider instanceof LifeCycleEventsProvider) {
+ internalLifecycleEventsProvider = (LifeCycleEventsProvider) eventsProvider;
+ }
+ } catch (ServiceException ex) {
+ // Ignore: the service is optional
+ }
+
+ SashModel sashModel = (SashModel) modelSet.getModel(SashModel.MODEL_ID);
+
+ try {
+ // We need to send pre- and post-save events, but we can only do that with the internal LifecycleEventsProvider
+ // The ISaveAndDirtyService can only save the whole model, but we just want to save the sash
+ DoSaveEvent event = new DoSaveEvent(registry, editor, true);
+ if (internalLifecycleEventsProvider != null) {
+ internalLifecycleEventsProvider.fireAboutToDoSaveEvent(event);
+ internalLifecycleEventsProvider.fireDoSaveEvent(event);
+ }
+ sashModel.saveModel();
+ if (internalLifecycleEventsProvider != null) {
+ internalLifecycleEventsProvider.firePostDoSaveEvent(event);
+ }
+ } catch (IOException ex) {
+ Activator.log.error(ex);
+ }
+ }
+
+ private void checkSharedLayout(IMultiDiagramEditor editor) {
+ try {
+ ModelSet modelSet = registry.getService(ModelSet.class);
+ SashModel sashModel = (SashModel) modelSet.getModel(SashModel.MODEL_ID);
+
+ if (sashModel.isLegacyMode()) {
+ // Have we ever created the private sash model file?
+ URI privateURI = sashModel.getPrivateResourceURI();
+ if (!modelSet.getURIConverter().exists(privateURI, null)) {
+ // Prompt the user
+ promptToEnablePrivateStorage(editor);
+ }
+ }
+ } catch (ServiceException ex) {
+ // Shared layout doesn't matter if there's no model-set
+ }
+ }
+
+ private void promptToEnablePrivateStorage(IMultiDiagramEditor editor) {
+ YesNo preference = EditorPreferences.getInstance().getConvertSharedPageLayoutToPrivate();
+
+ if (preference == YesNo.PROMPT) {
+ MessageDialogWithToggle dlg = MessageDialogWithToggle.openYesNoCancelQuestion(editor.getSite().getShell(),
+ Messages.SaveLayoutBeforeClose_0,
+ Messages.SaveLayoutBeforeClose_1,
+ Messages.SaveLayoutBeforeClose_2, false, null, null);
+
+ switch (dlg.getReturnCode()) {
+ case IDialogConstants.YES_ID:
+ preference = YesNo.YES;
+ break;
+ case IDialogConstants.NO_ID:
+ preference = YesNo.NO;
+ break;
+ default:
+ // User cancelled
+ preference = YesNo.PROMPT;
+ break;
+ }
+
+ if (dlg.getToggleState()) {
+ EditorPreferences.getInstance().setConvertSharedPageLayoutToPrivate(preference);
+ }
+ }
+
+ switch (preference) {
+ case YES:
+ // Change the storage to private
+ new TogglePageLayoutStorageHandler().togglePrivatePageLayout(editor);
+
+ // And save the new layout scheme
+ saveBeforeClose(editor);
+ break;
+ case NO:
+ // Just create the empty resource and save it
+ try {
+ ModelSet modelSet = editor.getServicesRegistry().getService(ModelSet.class);
+ SashModel sashModel = (SashModel) modelSet.getModel(SashModel.MODEL_ID);
+ modelSet.createResource(sashModel.getPrivateResourceURI());
+ saveBeforeClose(editor);
+ } catch (ServiceException e) {
+ // Without a model-set, much else is going wrong, so there's no need to deal
+ // with this here
+ }
+ break;
+ default:
+ // User cancelled
+ break;
+ }
+ }
+
+ @Override
+ public void disposeService() throws ServiceException {
+ registry = null;
+ if (lifecycleManager != null) {
+ lifecycleManager.removeEditorLifecycleEventsListener(lifecycleListener);
+ lifecycleListener = null;
+ lifecycleManager = null;
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java new file mode 100644 index 00000000000..b37b131962a --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java @@ -0,0 +1,128 @@ +/*****************************************************************************
+ * Copyright (c) 2013, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 469188
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.services.EditorLifecycleEventListener;
+import org.eclipse.papyrus.infra.ui.services.EditorLifecycleManager;
+
+
+public class EditorLifecycleManagerImpl implements EditorLifecycleManager, InternalEditorLifecycleManager {
+
+ private final Set<EditorLifecycleEventListener> listeners = new HashSet<EditorLifecycleEventListener>();
+
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ // Nothing
+ }
+
+ @Override
+ public void startService() throws ServiceException {
+ // Nothing
+ }
+
+ @Override
+ public void disposeService() throws ServiceException {
+ listeners.clear();
+ }
+
+ @Override
+ public void addEditorLifecycleEventsListener(EditorLifecycleEventListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void removeEditorLifecycleEventsListener(EditorLifecycleEventListener listener) {
+ listeners.remove(listener);
+ }
+
+ @Override
+ public void firePostInit(final IMultiDiagramEditor editor) {
+ for (final EditorLifecycleEventListener listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.postInit(editor);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Already logged by the SafeRunner
+ }
+ });
+ }
+ }
+
+ @Override
+ public void firePreDisplay(final IMultiDiagramEditor editor) {
+ for (final EditorLifecycleEventListener listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.preDisplay(editor);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Already logged by the SafeRunner
+ }
+ });
+ }
+ }
+
+ @Override
+ public void firePostDisplay(final IMultiDiagramEditor editor) {
+ for (final EditorLifecycleEventListener listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.postDisplay(editor);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Already logged by the SafeRunner
+ }
+ });
+ }
+ }
+
+ @Override
+ public void fireBeforeClose(final IMultiDiagramEditor editor) {
+ for (final EditorLifecycleEventListener listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.beforeClose(editor);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Already logged by the SafeRunner
+ }
+ });
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java new file mode 100644 index 00000000000..301557028d9 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java @@ -0,0 +1,48 @@ +/*****************************************************************************
+ * Copyright (c) 2013, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 469188
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services.internal;
+
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+
+public interface InternalEditorLifecycleManager extends IService {
+
+ /**
+ * Sends the postInit notification for this editor
+ *
+ * @param editor
+ */
+ void firePostInit(IMultiDiagramEditor editor);
+
+ /**
+ * Sets the preDisplay notification for this editor
+ *
+ * @param editor
+ */
+ void firePreDisplay(IMultiDiagramEditor editor);
+
+ /**
+ * Sends the postDisplay notification for this editor
+ *
+ * @param editor
+ */
+ void firePostDisplay(IMultiDiagramEditor editor);
+
+ /**
+ * Sends the beforeClose notification for this Editor
+ *
+ * @param editor
+ */
+ void fireBeforeClose(IMultiDiagramEditor editor);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties new file mode 100644 index 00000000000..a6f77150932 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties @@ -0,0 +1,15 @@ +# +# Copyright (c) 2015 Christian W. Damus and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Christian W. Damus - Initial API and implementation +# + +SaveLayoutBeforeClose_0=Editor Layout Storage +SaveLayoutBeforeClose_1=This model stores the editor page layout in the DI resource, which if managed in a source control system will share the layout with others. Convert to local (private) storage of the page layout? +SaveLayoutBeforeClose_2=Remember my decision diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java new file mode 100644 index 00000000000..82ef8983d95 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java @@ -0,0 +1,135 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.menus.ExtensionContributionFactory;
+import org.eclipse.ui.menus.IContributionRoot;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Abstract Class to create menu from an Eclipse Command category
+ *
+ * @author VL222926
+ *
+ */
+public abstract class AbstractCreateMenuFromCommandCategory extends ExtensionContributionFactory {
+
+ /** the category of the command contributing to this menu */
+ protected final String commandCateogyId;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param commandCategoryId
+ * the category of the command contributing to this menu
+ */
+ public AbstractCreateMenuFromCommandCategory(final String commandCategoryId) {
+ this.commandCateogyId = commandCategoryId;
+ }
+
+ /**
+ *
+ * @see org.eclipse.ui.menus.AbstractContributionFactory#createContributionItems(org.eclipse.ui.services.IServiceLocator, org.eclipse.ui.menus.IContributionRoot)
+ *
+ * @param serviceLocator
+ * @param additions
+ */
+ @Override
+ public void createContributionItems(IServiceLocator serviceLocator, IContributionRoot additions) {
+ // test to know if we can create elements if it is possible...
+ Expression visibleWhen = new Expression() {
+
+ @Override
+ public EvaluationResult evaluate(IEvaluationContext context) throws CoreException {
+ return EvaluationResult.TRUE;
+ }
+ };
+ for (final CommandContributionItem item : addCreationItems(serviceLocator, additions, null)) {
+ additions.addContributionItem(item, visibleWhen);
+ }
+ }
+
+ /**
+ *
+ * @param serviceLocator
+ * @param additions
+ * @param parent
+ * @return
+ */
+ protected List<CommandContributionItem> addCreationItems(final IServiceLocator serviceLocator, final IContributionRoot additions, IContributionManager parent) {
+ final ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class);
+ final List<CommandContributionItem> items = new ArrayList<CommandContributionItem>();
+ final Category category = commandService.getCategory(this.commandCateogyId);
+ final Set<Command> commands = new TreeSet<Command>();
+ commands.addAll(Arrays.asList(commandService.getDefinedCommands()));
+ for (Command command : commands) {
+ Category currentCategory = null;
+ try {
+ currentCategory = command.getCategory();
+ } catch (NotDefinedException e) {
+ Activator.log.debug(e.getLocalizedMessage());
+ continue;
+ }
+ if (command.isDefined() && category.equals(currentCategory)) {
+ final IHandler handler = command.getHandler();
+ if (handler instanceof AbstractHandler) {
+
+ // required!?!?! in some case can avoid the message for handler conflicting (ex : Allocate in SysML NatTable Allocation
+ ((AbstractHandler) handler).setEnabled(null);
+ boolean isEnabled = handler.isEnabled();
+ command.setEnabled(null);
+ ((AbstractHandler) handler).setEnabled(null);
+
+ isEnabled = handler.isEnabled();
+ try {
+ if (isEnabled) {
+ CommandContributionItemParameter p = new CommandContributionItemParameter(serviceLocator, "", command.getId(), SWT.PUSH); //$NON-NLS-1$
+ p.label = command.getDescription();
+ p.icon = EclipseCommandUtils.getCommandIcon(command);
+ CommandContributionItem item = new CommandContributionItem(p);
+ items.add(item);
+ }
+ } catch (NotDefinedException e) {
+ Activator.log.debug(e.getLocalizedMessage());
+ }
+ }
+ }
+ }
+ return items;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java new file mode 100644 index 00000000000..0781c1d0ce7 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java @@ -0,0 +1,47 @@ +/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+
+
+/**
+ * Util class for display in Papyrus (label providers, etc...)
+ *
+ * @deprecated Use the LabelProviderService instead
+ */
+@Deprecated
+public class DisplayUtils {
+
+ /**
+ * Gets the shared label provider.
+ *
+ * @return Get the current {@link ILabelProvider} or <code>null</code> if
+ * not found
+ */
+ public static ILabelProvider getLabelProvider() {
+ try {
+ ServicesRegistry registry = EditorUtils.getServiceRegistry();
+ return registry == null ? null : registry.getService(ILabelProvider.class);
+ } catch (IllegalStateException e) {
+ // Registry can't be found, do nothing.
+ Activator.log.error(e);
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java new file mode 100644 index 00000000000..d7d462e82ca --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java @@ -0,0 +1,137 @@ +/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+
+/**
+ * This class provides useful methods to manipulate Eclipse Command
+ *
+ * @author vl222926
+ *
+ */
+public class EclipseCommandUtils {
+
+ private EclipseCommandUtils() {
+ // to prevent instanciation
+ }
+
+ public static final String TOGGLE_STATE = "org.eclipse.ui.commands.toggleState"; //$NON-NLS-1$
+
+ public static final String RADIO_STATE = "org.eclipse.ui.commands.radioState"; //$NON-NLS-1$
+
+ public static final String DELETE_COMMAND = "org.eclipse.ui.edit.delete"; //$NON-NLS-1$
+
+ /**
+ *
+ * @param categoryId
+ * a category id
+ * @return
+ * all commands defined for this category
+ */
+ public static final Collection<Command> getAllExistingCommandsInCategory(final String categoryId) {
+ final Set<Command> commands = new TreeSet<Command>();
+ final ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class);
+ final Category category = commandService.getCategory(categoryId);
+ for (final Command command : commandService.getDefinedCommands()) {
+ Category currentCategory = null;
+ try {
+ currentCategory = command.getCategory();
+ } catch (NotDefinedException e) {
+ Activator.log.debug(e.getLocalizedMessage());
+ continue;
+ }
+ if (/* command.isDefined() && */category.equals(currentCategory)) {
+ commands.add(command);
+ }
+ }
+ return commands;
+ }
+
+ /**
+ *
+ * @param command
+ * an Eclipse command
+ * @return
+ * the image descriptor associated to this command
+ */
+ public static final ImageDescriptor getCommandIcon(final Command command) {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ final ICommandImageService service = workbench.getService(ICommandImageService.class);
+ final ImageDescriptor imageDescriptor = service.getImageDescriptor(command.getId());
+ return imageDescriptor;
+ }
+
+ /**
+ *
+ * @param command
+ * an eclipse command
+ * @param newValue
+ * the new boolean value to set to the state of this command
+ */
+ public static final void updateToggleCommandState(final org.eclipse.core.commands.Command command, final boolean newValue) {
+ if (command != null) {
+ final State state = command.getState(TOGGLE_STATE);
+ if (state != null) {
+ state.setValue(newValue);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param command
+ * an eclipse command
+ * @param newValue
+ * the new value to set to the state of this command
+ */
+ public static final void updateRadioCommandState(final org.eclipse.core.commands.Command command, final Object newValue) {
+ if (command != null) {
+ final State state = command.getState(RADIO_STATE);
+ if (state != null) {
+ state.setValue(newValue);
+ }
+ }
+ }
+
+ /**
+ *
+ * @return
+ * the eclipse command service
+ */
+ public static final ICommandService getCommandService() {
+ IWorkbench wb = PlatformUI.getWorkbench();
+ if (wb != null) {
+ IWorkbenchWindow ww = wb.getActiveWorkbenchWindow();
+ if (ww != null) {
+ return ww.getService(ICommandService.class);
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java new file mode 100644 index 00000000000..be7a0d1dbaa --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java @@ -0,0 +1,71 @@ +/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ *
+ * a helper for the Editor
+ *
+ */
+public class EditorHelper {
+
+ private EditorHelper() {
+ // nothing to do
+ }
+
+ /**
+ *
+ * @return
+ * the current editor or <code>null</code> if not found
+ */
+ public static final IEditorPart getCurrentEditor() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (workbench != null) {
+ final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
+ if (activeWorkbench != null) {
+ final IWorkbenchPage activePage = activeWorkbench.getActivePage();
+ if (activePage != null) {
+ return activePage.getActiveEditor();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @return
+ * the current active part or <code>null</code> if not found
+ */
+ public static final IWorkbenchPart getActivePart() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (workbench != null) {
+ final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
+ if (activeWorkbench != null) {
+ final IWorkbenchPage activePage = activeWorkbench.getActivePage();
+ if (activePage != null) {
+ return activePage.getActivePart();
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java new file mode 100644 index 00000000000..eea097e6062 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java @@ -0,0 +1,721 @@ +/***************************************************************************** + * Copyright (c) 2008, 2013 CEA LIST and others. + * + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation + * <a href="mailto:thomas.szadel@atosorigin.com">Thomas Szadel</a>: Code simplification and NPE + * management. + * Christian W. Damus (CEA LIST) - API for determining URI of a resource in an editor + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.util; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.emf.common.ui.URIEditorInput; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.papyrus.infra.core.editor.BackboneException; +import org.eclipse.papyrus.infra.core.resource.sasheditor.DiModelUtils; +import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider; +import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelMngr; +import org.eclipse.papyrus.infra.core.sasheditor.editor.IPage; +import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer; +import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.core.utils.DiResourceSet; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.papyrus.infra.ui.editor.CoreMultiDiagramEditor; +import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IURIEditorInput; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +/** + * Set of utility methods for the CoreEditor. <br> + * WARNING : Some of these methods rely on + * PlatformUI.getWorkbench().getActiveWorkbenchWindow()getActivePage() to lookup + * for shared objects owned by the main editor. This doesn't work during the + * initialization of the main editor because the main editor is not yet + * registered in the Eclipse workbench. This can lead to a null or an exception, + * and sometime this can lead to getting the shared object of another main + * editor ! + * + * @author cedric dumoulin + * @author <a href="mailto:thomas.szadel@atosorigin.com">Thomas Szadel</a> + */ +// FIXME throws Exception (eg: NotFoundException) instead of null +public class EditorUtils { + + /** + * Gets the opened multi-diagram editors. + * + * @return The opened {@link IMultiDiagramEditor} or null if an error + * occured. + */ + public static IMultiDiagramEditor[] getMultiDiagramEditors() { + // Lookup ServiceRegistry + IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (workbenchWindow == null) { + return null; + } + IWorkbenchPage page = workbenchWindow.getActivePage(); + if (page == null) { + return null; + } + List<IMultiDiagramEditor> list = new ArrayList<IMultiDiagramEditor>(); + for (IEditorReference editorRef : page.getEditorReferences()) { + IEditorPart editorPart = editorRef.getEditor(false); + if (editorPart instanceof IMultiDiagramEditor) { + list.add((IMultiDiagramEditor) editorPart); + } + } + return list.toArray(new IMultiDiagramEditor[list.size()]); + } + + /** + * Returns the editors that are related to to given file.<BR> + * + * @param file + * The file (model, di or notation). + * @return The associated editors. + */ + public static IMultiDiagramEditor[] getRelatedEditors(IFile file) { + // Get the DI file + IFile diFile = DiModelUtils.getRelatedDiFile(file); + if (diFile == null || !diFile.exists()) { + return new IMultiDiagramEditor[0]; + } + + IMultiDiagramEditor[] openedEditors = EditorUtils.getMultiDiagramEditors(); + if (openedEditors == null) { + return new IMultiDiagramEditor[0]; + } + List<IMultiDiagramEditor> list = new ArrayList<IMultiDiagramEditor>(openedEditors.length); + + for (IMultiDiagramEditor editorPart : openedEditors) { + if (editorPart.getEditorInput() instanceof IFileEditorInput && diFile.equals(((IFileEditorInput) editorPart.getEditorInput()).getFile())) { + list.add(editorPart); + } + } + return list.toArray(new IMultiDiagramEditor[list.size()]); + } + + /** + * Create an instance of IPageMngr acting on the provided resource. This + * instance is suitable to add, remove, close or open diagrams. + * + * @param diResource + * @return The non transactional implementation of IPageMngr + */ + public static IPageManager getIPageMngr(Resource diResource) { + return DiSashModelMngr.createIPageMngr(diResource); + } + + + // ////////////////////////////////////////// + // The following methods are deprecated. They have been replaced by specific + // implementations of ServiceUtils (e.g. ServiceUtilsForHandlers, ServiceUtilsForEObject), + // which depend on a specific context (ExecutionEvent, EObject, ...) instead of + // the active editor + // ////////////////////////////////////////// + + /** + * Gets the {@link IMultiDiagramEditor} interface of the a Eclipse active + * editor, if possible, or null if not possible. <br> + * WARNING - This method doesn't work during the initialization of the main + * editor. See note in class doc. <br> + * This method return null if there is no active editor, or if the editor is + * not instance of IMultiDiagramEditor. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * This method should not be used during the editor initialization phase. <br> + * In any case, a check should be done on the returned value that can be + * null. Usage of this method is discouraged. Use {@link #getMultiDiagramEditorChecked()} instead. + * + * + * @return Get the current {@link IMultiDiagramEditor} or null if not found. + */ + public static IMultiDiagramEditor getMultiDiagramEditor() { + // Lookup ServiceRegistry + IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (workbenchWindow == null) { + return null; + } + IWorkbenchPage page = workbenchWindow.getActivePage(); + if (page == null) { + return null; + } + IEditorPart editor = page.getActiveEditor(); + if (editor instanceof IMultiDiagramEditor) { + return (IMultiDiagramEditor) editor; + } else { + return null; + } + } + + /** + * Lookup the currently active Diagram from the Papyrus editor. Return the + * current Diagram or null if none is active. <br> + * WARNING - This method doesn't work during the initialization of the main + * editor. See note in class doc. <br> + * This method return null if the ServicesRegistry can not be found. <br> + * TODO This method introduce dependency on GMF. It can be moved to a GMF + * plugin. + * + * @return The active diagram or null if not found. + * + * @deprecated The core do make suppositions about the type of nested + * Editors, GMF stuff should be moved in GMF projects. In many + * case, {@link #lookupActiveNestedIEditor()} can be used. + */ + // @Deprecated + // public static Diagram lookupEditorActiveDiagram() { + // DiagramEditor diagEditor = lookupActiveDiagramEditor(); + // return diagEditor == null ? null : diagEditor.getDiagram(); + // } + + /** + * Lookup the currently active Diagram from the Papyrus editor. Return the + * current Diagram or null if none is active. <br> + * WARNING - This method doesn't work during the initialization of the main + * editor. See note in class doc. <br> + * This method return null if the ServicesRegistry can not be found. <br> + * TODO This method introduce dependency on GMF. It can be moved to a GMF + * plugin. + * + * @return the active diagram editor or null if not found. + * + * @deprecated The core do make suppositions about the type of nested + * Editors, GMF stuff should be moved in GMF projects. In many + * case, {@link #lookupActiveNestedIEditor()} can be used. + */ + // @Deprecated + // public static DiagramEditor lookupActiveDiagramEditor() { + // // Get the active page within the sashcontainer + // IEditorPart activeEditor = lookupActiveNestedIEditor(); + // // Check if it is a GMF DiagramEditor + // if(activeEditor instanceof DiagramEditor) { + // return ((DiagramEditor)activeEditor); + // } else { + // // Not found + // return null; + // } + // + // } + + /** + * Lookup the currently active {@link IEditorPart} from the Papyrus editor. + * Return the current nested editor part, or null if it can not be found. <br> + * WARNING - This method doesn't work during the initialization of the main + * editor. See note in class doc. <br> + * This method return null if the ServicesRegistry can not be found. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * This method should not be used during the editor initialization phase. <br> + * In any case, a check should be done on the returned value that can be + * null. An alternative is to use + * serviceRegistry.getService(ISashWindowsContainer + * .class).getActiveEditor(); <br> + * It is preferable to retrieve the ServiceRegistry from elsewhere whenever + * it is possible. <br> + * + * + * @return + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + public static IEditorPart lookupActiveNestedIEditor() { + // Get the sashwindow container + ISashWindowsContainer container = getSashWindowContainer(); + // Get the active page within the sashcontainer + return container == null ? null : container.getActiveEditor(); + } + + /** + * Lookup the currently active IEditor in the SashSystem. If the currently + * eclipse active editor doesn't contains a {@link ISashWindowsContainer}, + * return null. If the current SashSystem page is not a IEditor, return + * null. <br> + * WARNING - This method doesn't work during the initialization of the main + * editor. See note in class doc. <br> + * This method return null if the ServicesRegistry can not be found. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * This method should not be used during the editor initialization phase. <br> + * In any case, a check should be done on the returned value that can be + * null. An alternative is to use + * serviceRegistry.getService(ISashWindowsContainer + * .class).getActiveSashWindowsPage(); <br> + * It is preferable to retrieve the ServiceRegistry from elsewhere whenever + * it is possible. + * + * @return + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + public static IPage lookupActiveNestedPage() { + + // Get the sashwindow container + ISashWindowsContainer container = getSashWindowContainer(); + // Get the active page within the sashcontainer + return container == null ? null : container.getActiveSashWindowsPage(); + } + + /** + * + * @return + */ + private static ISashWindowsContainer getSashWindowContainer() { + + try { + return getServiceRegistryChecked().getService(ISashWindowsContainer.class); + } catch (ServiceException e) { + // The contract says that we return null if not found + return null; + } + } + + /** + * Gets the di resource set. + * + * @return Get the current {@link DiResourceSet} or null if not found. + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + public static DiResourceSet getDiResourceSet() { + try { + ServicesRegistry registry = getServiceRegistry(); + return registry == null ? null : registry.getService(DiResourceSet.class); + } catch (ServiceException e) { + Activator.log.error(e); + } + return null; + } + + /** + * Gets the {@link TransactionalEditingDomain} of the current active Eclipse + * Editor. This method should be used only when it is sure that the active + * editor exist, and that you want the EditingDomain of this editor. <br> + * This method return null if the TransactionalEditingDomain can not be + * found. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * This method should not be used during the editor initialization phase. <br> + * In any case, a check should be done on the returned value that can be + * null. An alternative is to use {@link #getTransactionalEditingDomainChecked()} and to catch the + * exception. <br> + * It is preferable to use {@link #getTransactionalEditingDomain(ServicesRegistry)} whenever it is + * possible. <br> + * In GMF EditParts or EditPolicies, the ServiceRegistry can be retrieved + * with methods from + * org.eclipse.papyrus.uml.diagram.common.util.DiagramCoreServiceUtils <br> + * WARNING: This method can return null if there is no Active Editor. This + * happen during the editor initialization, especially when there is no + * other editor opened. + * + * @return Get the current {@link TransactionalEditingDomain} or null if not + * found + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + public static TransactionalEditingDomain getTransactionalEditingDomain() { + try { + ServicesRegistry registry = getServiceRegistry(); + return registry == null ? null : registry.getService(TransactionalEditingDomain.class); + } catch (IllegalStateException e) { + // Registry can't be found, do nothing. + } catch (ServiceException e) { + Activator.log.error(e); + } + return null; + } + + /** + * Gets the {@link TransactionalEditingDomain} of the current active Eclipse + * Editor. This method should be used only when it is sure that the active + * editor exist, and that you want the EditingDomain of this editor. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * This method should not be used during the editor initialization phase. <br> + * It is preferable to use {@link #getTransactionalEditingDomain(ServicesRegistry)} whenever it is + * possible. <br> + * This method throw a {@link ServiceException} if the + * TransactionalEditingDomain can not be found. <br> + * In GMF EditParts or EditPolicies, the ServiceRegistry can be retrieved + * with methods from + * org.eclipse.papyrus.uml.diagram.common.util.DiagramCoreServiceUtils + * + * + * WARNING: This method throws an exception when no Active Editor is found. + * This happen during the editor initialization, especially when there is no + * other editor opened. + * + * @return Get the current {@link TransactionalEditingDomain} + * @throws ServiceException + * @throws ServiceNotFoundException + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + public static TransactionalEditingDomain getTransactionalEditingDomainChecked() throws ServiceException { + try { + ServicesRegistry registry = getServiceRegistryChecked(); + return registry.getService(TransactionalEditingDomain.class); + } catch (IllegalStateException e) { + throw new ServiceException(e); + } catch (Exception e) { + throw new ServiceException(e); + } + } + + /** + * Gets the {@link TransactionalEditingDomain} registered in the {@link ServicesRegistry}. + * + * @param servicesRegistry + * @return + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * </ul> + */ + @Deprecated + public static TransactionalEditingDomain getTransactionalEditingDomain(ServicesRegistry registry) { + try { + return registry.getService(TransactionalEditingDomain.class); + } catch (IllegalStateException e) { + // Registry can't be found, do nothing. + } catch (ServiceException e) { + Activator.log.error(e); + } + return null; + } + + /** + * Gets the {@link TransactionalEditingDomain} registered in the {@link ServicesRegistry}. + * + * @param servicesRegistry + * @return + * @throws ServiceException + * If the TransactionalEditingDomain can not be found. + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * </ul> + */ + @Deprecated + public static TransactionalEditingDomain getTransactionalEditingDomainChecked(ServicesRegistry registry) throws ServiceException { + return registry.getService(TransactionalEditingDomain.class); + } + + /** + * Get the {@link ServicesRegistry}of the currently active eclipse editor. <br> + * WARNING - This method doesn't work during the initialization of the main + * editor. See note in class doc. <br> + * This method return null if the ServicesRegistry can not be found. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * This method should not be used during the editor initialization phase. <br> + * In any case, a check should be done on the returned value that can be + * null. An alternative is to use {@link #getServiceRegistryChecked()} and + * to catch the exception. <br> + * It is preferable to retrieve the ServiceRegistry from elsewhere whenever + * it is possible. <br> + * In GMF EditParts or EditPolicies, the ServiceRegistry can be retrieved + * with methods from + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF + * + * <br> + * WARNING: This method can return null if there is no Active Editor. This + * happen during the editor initialization, especially when there is no + * other editor opened. + * + * @return The {@link ServicesRegistry} or null if not found. + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + static public ServicesRegistry getServiceRegistry() { + // Lookup ServiceRegistry + IMultiDiagramEditor editor = getMultiDiagramEditor(); + return editor == null ? null : (ServicesRegistry) editor.getAdapter(ServicesRegistry.class); + } + + /** + * Get the service registry of the currently active main editor. <br> + * WARNING - This method doesn't work during the initialization of the main + * editor. See note in class doc. + * + * @return The {@link ServicesRegistry} or null if not found. + * @throws ServiceException + * If an error occurs. + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + static public ServicesRegistry getServiceRegistryChecked() throws ServiceException { + // Lookup ServiceRegistry + IMultiDiagramEditor editor = getMultiDiagramEditor(); + if (editor == null) { + throw new ServiceException("Can't get ServiceRegistry"); //$NON-NLS-1$ + } + + return editor.getAdapter(ServicesRegistry.class); + } + + /** + * Get the ISashWindowsContentProvider of the active Eclipse Editor, if + * possible. <br> + * This method return null if the ServiceRegistry can not be found or if an + * error occur. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * This method should not be used during the editor initialization phase. <br> + * In any case, a check should be done on the returned value that can be + * null. <br> + * + * @return the ISashWindowsContentProvider from the main editor or null if + * not found. + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + static public ISashWindowsContentProvider getISashWindowsContentProvider() { + + try { + return getServiceRegistryChecked().getService(ISashWindowsContentProvider.class); + } catch (ServiceException e) { + // The contract says that we return null if not found + return null; + } + } + + /** + * Get the ISashWindowsContentProvider of the active Eclipse Editor, if + * possible. <br> + * This method return null if the ServiceRegistry can not be found or if an + * error occur. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * This method should not be used during the editor initialization phase. <br> + * In any case, a check should be done on the returned value that can be + * null. + * + * @return the ISashWindowsContentProvider from the main editor or null if + * not found. + * @deprecated Check + * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments + * /cookbook/PapyrusCookBook.odt and use one of the replacement: + * <ul> + * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li> + * <li> + * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li> + * <li> + * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li> + * </ul> + */ + @Deprecated + public static IPageManager getIPageMngr() { + + try { + return getServiceRegistryChecked().getService(IPageManager.class); + } catch (ServiceException e) { + // The contract says that we return null if not found + return null; + } + } + + /** + * Get the Eclipse ActiveEditor. + * + * @return The active {@link CoreMultiDiagramEditor} or null if not found. + * @deprecated Use {@link EditorUtils#getMultiDiagramEditor()} + */ + @Deprecated + protected static IEditorPart getWorkbenchActiveEditor() { + IMultiDiagramEditor editorPart = getMultiDiagramEditor(); + if (editorPart instanceof CoreMultiDiagramEditor) { + return editorPart; + } else { + return null; + } + } + + /** + * Gets the {@link IMultiDiagramEditor} interface of the a Eclipse active + * editor, if possible, or throw an exception if not possible. <br> + * WARNING - This method throw an exception during the initialization of the + * main editor. This method throws an exception if there is no active + * editor, or if the editor is not instance of IMultiDiagramEditor. <br> + * This method is designed to be used by ui actions that interact with the + * active editor. <br> + * + * + * @return Get the current {@link IMultiDiagramEditor} or null if not found. + * @throws BackboneException + * If it is not possible to get an instanceof {@link IMultiDiagramEditor} + */ + public static IMultiDiagramEditor getMultiDiagramEditorChecked() throws BackboneException { + IEditorPart editor; + try { + editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); + } catch (NullPointerException e) { + // Can't get the active editor + throw new BackboneException("Can't get the current Eclipse Active Editor: There is no active editor at this time."); //$NON-NLS-1$ + } + + if (editor instanceof IMultiDiagramEditor) { + return (IMultiDiagramEditor) editor; + } else { + throw new BackboneException("Can't get an Active Editor instance of IMultiDiagramEditor. (actual type:" + editor.getClass().getName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + /** + * Obtains the URI of the EMF resource identified by the given editor reference. + * + * @param editorRef + * an editor reference + * + * @return the best-effort URI of the resource that it edits, or {@code null} if it could not be determined, + * including the case when the editor input could not be obtained from the reference + */ + public static URI getResourceURI(IEditorReference editorRef) { + try { + return getResourceURI(editorRef.getEditorInput()); + } catch (PartInitException e) { + Activator.log.error("Could not obtain editor input from editor reference.", e); //$NON-NLS-1$ + return null; + } + } + + /** + * Obtains the URI of the EMF resource edited by the given {@code editor}. + * + * @param editor + * an open editor + * + * @return the best-effort URI of the resource that it edits, or {@code null} if it could not be determined, + * such as if the editor input could not be obtained from the editor + */ + public static URI getResourceURI(IEditorPart editor) { + return getResourceURI(editor.getEditorInput()); + } + + /** + * Obtains the URI of the EMF resource identified by the given editor input. + * + * @param editorInput + * an editor input + * + * @return the best-effort URI of the resource that it edits, or {@code null} if it could not be determined + */ + public static URI getResourceURI(IEditorInput editorInput) { + URI result = null; + + if (editorInput instanceof IFileEditorInput) { + result = URI.createPlatformResourceURI(((IFileEditorInput) editorInput).getFile().getFullPath().toString(), true); + } else if (editorInput instanceof URIEditorInput) { + result = ((URIEditorInput) editorInput).getURI(); + } else if (editorInput instanceof IURIEditorInput) { + result = URI.createURI(((IURIEditorInput) editorInput).getURI().toASCIIString(), true); + } else if (editorInput != null) { + // desperation + Object adapter = editorInput.getAdapter(URI.class); + if (adapter instanceof URI) { + result = (URI) adapter; + } + } + + return result; + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java new file mode 100644 index 00000000000..bfcafbe8284 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java @@ -0,0 +1,45 @@ +/***************************************************************************** + * Copyright (c) 2014 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.util; + +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.Callable; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; + +/** + * The {@link Callable} analogue of an {@link IRunnableWithProgress}. + */ +public interface ICallableWithProgress<V> { + /** + * Invokes me in a runnable context with a progress monitor. + * + * @param monitor + * the progress monitor to use to display progress and receive + * requests for cancellation + * @exception InvocationTargetException + * if the run method must propagate a checked exception, + * it should wrap it inside an <code>InvocationTargetException</code>; runtime exceptions are automatically + * wrapped in an <code>InvocationTargetException</code> by the calling context + * @exception InterruptedException + * if the operation detects a request to cancel, + * using <code>IProgressMonitor.isCanceled()</code>, it should exit by throwing <code>InterruptedException</code> + * + * @see UIUtil#call(IRunnableContext, ICallableWithProgress) + * @see IRunnableContext#run + */ + V call(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException; +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java new file mode 100644 index 00000000000..309542ee425 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.ui.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.ui.IMemento; + + +/** + * Invocation handler for the dynamic local memento implementation. + */ +class LocalMemento implements InvocationHandler { + + private static final Class<?>[] INTERFACES = { IMemento.class }; + + private static final Map<Method, Method> delegates = createDelegates(); + + private final String type; + + private final String id; + + private final List<IMemento> children = new ArrayList<IMemento>(); + + private final Map<String, Object> attributes = new HashMap<String, Object>(); + + private String textData; + + LocalMemento(String type, String id) { + super(); + + this.type = type; + this.id = id; + } + + static IMemento createMemento(String type, String id) { + LocalMemento handler = new LocalMemento(type, id); + return (IMemento) Proxy.newProxyInstance(LocalMemento.class.getClassLoader(), INTERFACES, handler); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Object result = null; + + Method implementation = delegates.get(method); + if (implementation == null) { + throw new UnsupportedOperationException("dynamic proxy handler does not understand " + method.getName()); //$NON-NLS-1$ + } else { + result = implementation.invoke(this, args); + } + + return result; + } + + @API + String getType() { + return type; + } + + @API + String getID() { + return id; + } + + @API + IMemento createChild(String type) { + return createChild(type, null); + } + + @API + IMemento createChild(String type, String id) { + IMemento result = createMemento(type, id); + children.add(result); + return result; + } + + @API + IMemento getChild(String type) { + IMemento result = null; + for (IMemento next : children) { + if (type.equals(next.getType())) { + result = next; + break; + } + } + return result; + } + + @API + IMemento[] getChildren() { + return children.toArray(new IMemento[children.size()]); + } + + @API + IMemento[] getChildren(String type) { + List<IMemento> result = new ArrayList<IMemento>(children.size()); + for (IMemento next : children) { + if (type.equals(next.getType())) { + result.add(next); + } + } + return result.toArray(new IMemento[result.size()]); + } + + @API + Float getFloat(String key) { + return coerce(attributes.get(key), Float.class); + } + + private <T> T coerce(Object value, Class<T> type) { + Object result; + + if (value == null) { + result = value; + } else if (type.isInstance(value)) { + result = value; + } else if (Number.class.isAssignableFrom(type) && (value instanceof Number)) { + Number number = (Number) value; + if (type == Integer.class) { + result = number.intValue(); + } else if (type == Float.class) { + result = number.floatValue(); + } else { + throw new IllegalArgumentException("unsupported numeric type: " + type.getSimpleName()); //$NON-NLS-1$ + } + } else if (Number.class.isAssignableFrom(type) && (value instanceof String)) { + String string = (String) value; + if (type == Integer.class) { + result = Integer.valueOf(string); + } else if (type == Float.class) { + result = Float.valueOf(string); + } else { + throw new IllegalArgumentException("unsupported numeric type: " + type.getSimpleName()); //$NON-NLS-1$ + } + } else if (type == Boolean.class) { + // We know the value isn't a Boolean, otherwise we would have handled it already + if (value instanceof String) { + result = Boolean.valueOf((String) value); + } else { + throw new IllegalArgumentException("unsupported boolean conversion from type: " + ((value == null) ? "null" : value.getClass().getSimpleName())); //$NON-NLS-1$ + } + } else if (type == String.class) { + result = String.valueOf(value); + } else { + throw new IllegalArgumentException("unsupported attribute type: " + type.getSimpleName()); //$NON-NLS-1$ + } + + return type.cast(result); + } + + @API + Integer getInteger(String key) { + return coerce(attributes.get(key), Integer.class); + } + + @API + String getString(String key) { + return coerce(attributes.get(key), String.class); + } + + @API + Boolean getBoolean(String key) { + return coerce(attributes.get(key), Boolean.class); + } + + @API + String getTextData() { + return textData; + } + + @API + String[] getAttributeKeys() { + return attributes.keySet().toArray(new String[attributes.size()]); + } + + @API + void putFloat(String key, float value) { + attributes.put(key, value); + } + + @API + void putInteger(String key, int value) { + attributes.put(key, value); + } + + @API + void putString(String key, String value) { + attributes.put(key, value); + } + + @API + void putBoolean(String key, boolean value) { + attributes.put(key, value); + } + + @API + void putTextData(String data) { + textData = data; + } + + private boolean isLocalMemento(IMemento memento) { + return (memento != null) && Proxy.isProxyClass(memento.getClass()) && ((Proxy.getInvocationHandler(memento) instanceof LocalMemento)); + } + + @API + void putMemento(IMemento memento) { + if (!isLocalMemento(memento)) { + throw new IllegalArgumentException("memento is not a local memento"); //$NON-NLS-1$ + } + children.add(memento); + } + + @Override + @API(owner = Object.class) + public String toString() { + StringBuilder result = new StringBuilder(); + + append(result, 0); + + return result.toString(); + } + + private void append(StringBuilder buf, int depth) { + // Indent + for (int i = 0; i < depth; i++) { + buf.append(" "); //$NON-NLS-1$ + } + + buf.append("LocalMemento(");//$NON-NLS-1$ + buf.append(type); + if (id != null) { + buf.append('[').append(id).append(']'); + } + buf.append(") ").append(attributes); //$NON-NLS-1$ + buf.append('\n'); + + final int nextDepth = depth + 1; + for (IMemento next : children) { + ((LocalMemento) Proxy.getInvocationHandler(next)).append(buf, nextDepth); + } + } + + private static Map<Method, Method> createDelegates() { + Map<Method, Method> result = new HashMap<Method, Method>(); + + for (Method implementation : LocalMemento.class.getDeclaredMethods()) { + if (implementation.isAnnotationPresent(API.class)) { + try { + Method api = implementation.getAnnotation(API.class).owner().getMethod(implementation.getName(), implementation.getParameterTypes()); + result.put(api, implementation); + } catch (NoSuchMethodException e) { + throw new LinkageError("Incompatible IMemento API change: " + implementation.getName()); + } + } + } + + return result; + } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + private @interface API { + + Class<?> owner() default IMemento.class; + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java new file mode 100644 index 00000000000..ee0d9fb314f --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java @@ -0,0 +1,67 @@ +/***************************************************************************** + * Copyright (c) 2010 CEA LIST. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tristan Faure (ATOS ORIGIN INTEGRATION) tristan.faure@atosorigin.com - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.util; + +import java.io.IOException; +import java.net.URL; + +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.papyrus.infra.ui.Activator; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +/** + * Services to access to Papyrus images + * + * @author tristan faure + * + */ +public class PapyrusImageUtils { + + private static final String default_icon_32 = "/icons/papyrus/32x32/Papyrus_32x32_t.gif"; //$NON-NLS-1$ + + private static final String default_icon = "/icons/papyrus/Papyrus.gif"; //$NON-NLS-1$ + + /** + * get the default icon for Papyrus the image does not have to be disposed + * as it is registered in an ImageRegistry + * + * @return the Image + */ + public static Image getDefaultIcon() { + return getIcon(default_icon); + } + + /** + * get the default icon 32x32 for Papyrus the image does not have to be + * disposed as it is registered in an ImageRegistry + * + * @return the Image + */ + public static Image getDefaultIcon32() { + return getIcon(default_icon_32); + } + + private static Image getIcon(String path) { + String key = Activator.PLUGIN_ID + path; + Image result = JFaceResources.getImageRegistry().get(key); + if (result == null) { + URL url = Activator.getDefault().getBundle().getEntry(path); + try { + result = new Image(Display.getDefault(), url.openStream()); + JFaceResources.getImageRegistry().put(key, result); + } catch (IOException e) { + } + } + return result; + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java new file mode 100644 index 00000000000..c642bc534fe --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java @@ -0,0 +1,119 @@ +/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author VL222926
+ *
+ */
+public class SelectionHelper {
+
+ /**
+ * Constructor.
+ *
+ */
+ private SelectionHelper() {
+ // to avoid instanciation
+ }
+
+ /**
+ *
+ * @return
+ * the selection service or <code>null</code> if not found
+ *
+ */
+ public static final ISelectionService getSelectionService() {
+ IWorkbench wb = PlatformUI.getWorkbench();
+ if (wb != null) {
+ // don't work
+ // ISelectionService s1 = (ISelectionService) wb.getService(ISelectionService.class);
+ IWorkbenchWindow ww = wb.getActiveWorkbenchWindow();
+ if (ww != null) {
+ return (ISelectionService) ww.getService(ISelectionService.class);
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @return
+ * the current selection or an empty selection. can't be <code>null</code>
+ */
+ public static final ISelection getCurrentSelection() {
+ ISelectionService selectionService = getSelectionService();
+ if (selectionService != null) {
+ ISelection currentSelection = selectionService.getSelection();
+ if (currentSelection != null) {
+ return currentSelection;
+ }
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ /**
+ *
+ * @param viewId
+ * the id of the view for which we want the selection
+ * @return
+ * the current selection for the view, the returned value can't be <code>null</code>
+ */
+ public static final ISelection getCurrentSelection(String viewId) {
+ ISelectionService selectionService = getSelectionService();
+ if (selectionService != null) {
+ ISelection currentSelection = selectionService.getSelection(viewId);
+ if (currentSelection != null) {
+ return currentSelection;
+ }
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ /**
+ *
+ * @return
+ * a structured selection.
+ * the returned value can't be <code>null</code>
+ */
+ public static final IStructuredSelection getCurrentStructuredSelection() {
+ ISelection selection = getCurrentSelection();
+ if (selection instanceof IStructuredSelection) {
+ return (IStructuredSelection) selection;
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ /**
+ *
+ * @param viewId
+ * the id of the view for which we want the selection
+ * @return
+ * the current selection for the view, the returned value can't be <code>null</code>
+ */
+ public static final IStructuredSelection getCurrentStructuredSelection(String viewId) {
+ ISelection selection = getCurrentSelection(viewId);
+ if (selection instanceof IStructuredSelection) {
+ return (IStructuredSelection) selection;
+ }
+ return StructuredSelection.EMPTY;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java new file mode 100644 index 00000000000..917a41e8688 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java @@ -0,0 +1,149 @@ +/***************************************************************************** + * Copyright (c) 2010, 2016 LIFL, CEA LIST, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation + * Christian W. Damus - bug 485220 + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.util; + +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer; +import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.core.utils.AbstractServiceUtils; +import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor; +import org.eclipse.papyrus.infra.ui.lifecycleevents.ILifeCycleEventsProvider; +import org.eclipse.ui.IEditorPart; + +/** + * Set of utility methods for accessing core Services. This class provide + * methods to access the Papyrus well known services. This class is designed to + * be used from ui Action Handlers or from any code relying on the Eclipse + * Active Editor. <br> + * All methods from this class rely on the Eclipse Active Editor, which should + * be an instance of {@link IMultiDiagramEditor}. If this is not the case, + * methods throw an exception {@link ServiceException}. + * + * @author cedric dumoulin + * + * @deprecated 0.10: Use org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForHandlers instead + */ +@Deprecated +public class ServiceUtilsForActionHandlers extends AbstractServiceUtils<Void> { + + private ServiceUtilsForActionHandlers() { + // Singleton + } + + private final static ServiceUtilsForActionHandlers instance = new ServiceUtilsForActionHandlers(); + + /** + * Get the singleton instance of the class. + * + * @return + */ + public static final ServiceUtilsForActionHandlers getInstance() { + return instance; + } + + @Override + public ServicesRegistry getServiceRegistry(Void from) throws ServiceException { + return getServiceRegistry(); + } + + /** + * Get the service registry from the specified parameter. + * + * @param from + * @return + */ + public ServicesRegistry getServiceRegistry() throws ServiceException { + ServicesRegistry serviceRegistry = getContextualServiceRegistry(); + if (serviceRegistry != null) { + return serviceRegistry; + } + + // Not found + throw new ServiceNotFoundException("Can't get the ServiceRegistry from current Eclipse Active Editor"); //$NON-NLS-1$ + } + + /** + * Gets the {@link TransactionalEditingDomain} registered in the {@link ServicesRegistry}. + * + * @return + * @throws ServiceException + * If an error occurs while getting the requested service. + */ + public TransactionalEditingDomain getTransactionalEditingDomain() throws ServiceException { + return getServiceRegistry().getService(TransactionalEditingDomain.class); + } + + /** + * Gets the {@link IPageManager} registered in the {@link ServicesRegistry}. + * + * @return + * @throws ServiceException + * If an error occurs while getting the requested service. + */ + public IPageManager getIPageManager() throws ServiceException { + return getServiceRegistry().getService(IPageManager.class); + } + + /** + * Gets the {@link IPageMngr} registered in the {@link ServicesRegistry}. + * + * @return + * @throws ServiceException + * If an error occurs while getting the requested service. + */ + public ModelSet getModelSet() throws ServiceException { + return getServiceRegistry().getService(ModelSet.class); + } + + /** + * Gets the {@link ILifeCycleEventsProvider} registered in the {@link ServicesRegistry}. + * + * @param from + * @return + * @throws ServiceException + * If an error occurs while getting the requested service. + */ + public ILifeCycleEventsProvider getILifeCycleEventsProvider() throws ServiceException { + return getServiceRegistry().getService(ILifeCycleEventsProvider.class); + } + + /** + * Gets the {@link ISashWindowsContainer} registered in the {@link ServicesRegistry}. + * + * @param from + * @return + * @throws ServiceException + * If an error occurs while getting the requested service. + */ + public ISashWindowsContainer getISashWindowsContainer() throws ServiceException { + return getServiceRegistry().getService(ISashWindowsContainer.class); + } + + /** + * Gets the {@link IEditorPart} of the currently nested active editor. + * + * @param from + * @return + * @throws ServiceException + * If an error occurs while getting the requested service. + */ + public IEditorPart getNestedActiveIEditorPart() throws ServiceException { + return getISashWindowsContainer().getActiveEditor(); + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java new file mode 100644 index 00000000000..624257964cc --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java @@ -0,0 +1,63 @@ +/***************************************************************************** + * Copyright (c) 2012 CEA LIST. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.util; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.papyrus.infra.core.services.ServiceException; +import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.core.utils.AbstractServiceUtils; +import org.eclipse.ui.IWorkbenchPage; + +/** + * A ServiceUtils implementation for manipulating the Papyrus services from an IWorkbenchPage + * + * @author Camille Letavernier + * + */ +public class ServiceUtilsForWorkbenchPage extends AbstractServiceUtils<IWorkbenchPage> { + + @Override + public ServicesRegistry getServiceRegistry(IWorkbenchPage from) throws ServiceException { + IAdaptable adaptable = null; + if (from instanceof IAdaptable) { + adaptable = (IAdaptable) from; + } else if (from != null) { + // 421392: [Model Explorer] Link with Editor does not work properly + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=421392 + + // Since Eclipse 4.4, the concrete WorkbenchPage is not IAdaptable anymore. + // Try the ActivePart + adaptable = from.getActivePart(); + } + + if (adaptable != null) { + ServicesRegistry registry = (ServicesRegistry) adaptable.getAdapter(ServicesRegistry.class); + if (registry != null) { + return registry; + } + } + + + throw new ServiceException("Cannot resolve the ServiceRegistry from the IWorkbenchPage. Page: " + from); //$NON-NLS-1$ + } + + public static ServiceUtilsForWorkbenchPage getInstance() { + return instance; + } + + private static ServiceUtilsForWorkbenchPage instance = new ServiceUtilsForWorkbenchPage(); + + private ServiceUtilsForWorkbenchPage() { + // Singleton + } + +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java new file mode 100644 index 00000000000..825a99386a3 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java @@ -0,0 +1,81 @@ +/***************************************************************************** + * Copyright (c) 2014, 2016 CEA LIST, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + * Christian W. Damus - bug 465416 + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.util; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.emf.common.util.WrappedException; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.operation.IRunnableWithProgress; + + +/** + * Helper utilities for working with transactions on the UI thread. + */ +public class TransactionUIHelper { + + /** + * Create a privileged runnable with progress, which is like a regular {@linkplain TransactionalEditingDomain#createPrivilegedRunnable(Runnable) + * privileged runnable} except that it is given a progress monitor for progress reporting. + * This enables execution of monitored runnables on the modal-context thread using the transaction borrowed from the UI thread. + * + * @param domain + * an editing domain + * @param runnable + * a runnable with progress that is to borrow the {@code domain}'s active transaction on the modal context thread + * @return the privileged runnable, ready to pass into the progress service or other such API + */ + public static IRunnableWithProgress createPrivilegedRunnableWithProgress(TransactionalEditingDomain domain, final IRunnableWithProgress runnable) { + final IProgressMonitor monitorHolder[] = { null }; + + final Runnable privileged = domain.createPrivilegedRunnable(new Runnable() { + + @Override + public void run() { + try { + runnable.run(monitorHolder[0]); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new WrappedException(e); + } + } + }); + + return new IRunnableWithProgress() { + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + monitorHolder[0] = monitor; + + try { + privileged.run(); + } catch (OperationCanceledException e) { + throw new InterruptedException(e.getLocalizedMessage()); + } catch (WrappedException e) { + Exception unwrapped = e.exception(); + if (unwrapped instanceof InvocationTargetException) { + throw (InvocationTargetException) unwrapped; + } else if (unwrapped instanceof InterruptedException) { + throw (InterruptedException) unwrapped; + } else { + throw e; + } + } + } + }; + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java new file mode 100644 index 00000000000..1dd62db4ff5 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * Christian W. Damus - bug 399859 + * Christian W. Damus - bug 451557 + * Christian W. Damus - bug 485220 + * + */ +package org.eclipse.papyrus.infra.ui.util; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.eclipse.core.databinding.observable.Realm; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.emf.common.util.AbstractTreeIterator; +import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.papyrus.infra.tools.util.IExecutorService; +import org.eclipse.papyrus.infra.tools.util.Iterators2; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IMemento; + +import com.google.common.collect.Iterators; + + +/** + * Miscellaneous general-purpose UI utilities. + */ +public class UIUtil { + + /** + * Not instantiable by clients. + */ + private UIUtil() { + super(); + } + + /** + * Create an executor that runs tasks asynchronously on the UI thread. If you need synchronous execution, schedule {@link Future}s and {@linkplain Future#get() wait} for them. + * + * @param display + * the display on which thread to execute tasks + * + * @return the executor + */ + public static IExecutorService createUIExecutor(Display display) { + return new DisplayExecutorService(display); + } + + /** + * Create an executor that runs tasks asynchronously on an observable {@link Realm}. If you need synchronous execution, schedule {@link Future}s and {@linkplain Future#get() wait} for them. + * + * @param realm + * the observable realm on which thread to execute tasks + * + * @return the executor + */ + public static ExecutorService createObservableExecutor(Realm realm) { + return new RealmExecutorService(realm); + } + + /** + * Creates a local memento that is not persistable and is not based on an XML document. This is useful for capturing the + * state of UI elements locally in cases where persistence of the memento is not required. + * + * @return the memento + */ + public static IMemento createLocalMemento() { + return LocalMemento.createMemento("__anonymous__", null); //$NON-NLS-1$ + } + + /** + * Synchronously invokes a {@code callable} on the given {@code display}'s thread. + * + * @param display + * a display + * @param callable + * a callable to invoke + * @return the callable's result (which, because this method is synchronous, will be ready) + * + * @see #asyncCall(Display, Callable) + * @see #createUIExecutor(Display) + */ + public static <V> Future<V> syncCall(Display display, Callable<V> callable) { + final FutureTask<V> result = new FutureTask<V>(callable); + display.syncExec(result); + return result; + } + + /** + * Synchronously invokes a {@code callable} on the default display thread. + * + * @param callable + * a callable to invoke + * @return the callable's result (which, because this method is synchronous, will be ready) + * + * @see #syncCall(Display, Callable) + * @see #asyncCall(Callable) + * @see #createUIExecutor(Display) + */ + public static <V> Future<V> syncCall(Callable<V> callable) { + return syncCall(Display.getDefault(), callable); + } + + /** + * Asynchronously invokes a {@code callable} on the given {@code display}'s thread. + * + * @param display + * a display + * @param callable + * a callable to invoke + * @return the callable's result + * + * @see #syncCall(Display, Callable) + * @see #createUIExecutor(Display) + */ + public static <V> Future<V> asyncCall(Display display, Callable<V> callable) { + final FutureTask<V> result = new FutureTask<V>(callable); + display.asyncExec(result); + return result; + } + + /** + * Asynchronously invokes a {@code callable} on the default display thread. + * + * @param callable + * a callable to invoke + * @return the callable's result + * + * @see #asyncCall(Display, Callable) + * @see #syncCall(Callable) + * @see #createUIExecutor(Display) + */ + public static <V> Future<V> asyncCall(Callable<V> callable) { + return asyncCall(Display.getDefault(), callable); + } + + /** + * Calls a {@code callable} in the given {@code context}. + * + * @param fork + * {@code true} if the runnable should be run in a separate thread, + * and {@code false} to run in the same thread + * @param cancelable + * {@code true} to enable the cancellation, and {@code false} to make the operation uncancellable + * @param runnable + * the runnable to run + * + * @exception InvocationTargetException + * wraps any exception or error which occurs + * while running the runnable + * @exception InterruptedException + * propagated by the context if the runnable + * acknowledges cancellation by throwing this exception. This should not be thrown + * if {@code cancelable} is {@code false}. + */ + public static <V> V call(IRunnableContext context, boolean fork, boolean cancelable, ICallableWithProgress<V> callable) throws InvocationTargetException, InterruptedException { + class RunnableWrapper implements IRunnableWithProgress { + final ICallableWithProgress<V> delegate; + + V result; + + RunnableWrapper(ICallableWithProgress<V> delegate) { + this.delegate = delegate; + } + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + result = delegate.call(monitor); + } + } + + RunnableWrapper wrapper = new RunnableWrapper(callable); + context.run(fork, cancelable, wrapper); + return wrapper.result; + } + + /** + * Obtains a simple executor that asynchronously executes at most one task on the default + * display thread. While any task is still pending execution on this executor, + * all others are silently discarded. This is useful for cases where, for example, UI + * refreshes are posted repeatedly from independent events that aren't aware of each other + * but where each refresh task would repeat the same work. + * + * @param display + * a display on which thread to execute tasks + * + * @return the executor + * + * @see #createAsyncOnceExecutor(Display) + */ + public static Executor createAsyncOnceExecutor() { + return createAsyncOnceExecutor(Display.getDefault()); + } + + /** + * Obtains a simple executor that asynchronously executes at most one task on the given {@code display}'s thread. While any task is still pending execution on this executor, + * all others are silently discarded. This is useful for cases where, for example, UI + * refreshes are posted repeatedly from independent events that aren't aware of each other + * but where each refresh task would repeat the same work. + * + * @param display + * a display on which thread to execute tasks + * + * @return the executor + */ + public static Executor createAsyncOnceExecutor(final Display display) { + return new Executor() { + private final AtomicBoolean pending = new AtomicBoolean(); + + @Override + public void execute(final Runnable task) { + if (pending.compareAndSet(false, true)) { + display.asyncExec(new Runnable() { + + @Override + public void run() { + pending.set(false); + task.run(); + } + }); + } + } + }; + } + + /** + * Obtains a tree iterator over all of the controls contained within a given {@code root} control, not including that {@code root}. + * + * @param root + * a control to iterate + * @return an unmodifiable iterator over all of its nested controls, which naturally will be empty if the {@code root} is not a {@link Composite} + */ + public static TreeIterator<Control> allChildren(Control root) { + return new AbstractTreeIterator<Control>(root, false) { + private static final long serialVersionUID = 1L; + + @Override + protected Iterator<? extends Control> getChildren(Object object) { + return (object instanceof Composite) ? Iterators.forArray(((Composite) object).getChildren()) : Iterators.<Control> emptyIterator(); + } + }; + } + + /** + * Obtains a tree iterator over all of the controls of a particular type contained within a given {@code root} control, not including that {@code root}. + * + * @param root + * a control to iterate + * @param type + * the type of children to include in the iteration + * + * @return an unmodifiable iterator over all of its nested controls, which naturally will be empty if the {@code root} is not a {@link Composite} + */ + public static <C extends Control> TreeIterator<C> allChildren(Control root, final Class<C> type) { + return Iterators2.filter(allChildren(root), type); + } + + // + // Nested types + // + + private static abstract class UIExecutorService extends AbstractExecutorService implements IExecutorService { + + private final Lock lock = new ReentrantLock(); + + private final Condition emptyCond = lock.newCondition(); + + private final Queue<RunnableWrapper> pending = new LinkedList<RunnableWrapper>(); + + private volatile boolean shutdown; + + UIExecutorService() { + super(); + } + + @Override + public void execute(Runnable command) { + if (isShutdown()) { + throw new RejectedExecutionException("Executor service is shut down"); //$NON-NLS-1$ + } + + asyncExec(enqueue(command)); + } + + @Override + public <V> V syncCall(Callable<V> callable) throws InterruptedException, ExecutionException { + class SyncResult implements Runnable { + V result; + ExecutionException fail; + + @Override + public void run() { + try { + result = callable.call(); + } catch (Exception e) { + fail = new ExecutionException(e); + fail.fillInStackTrace(); + } + } + } + + SyncResult result = new SyncResult(); + + syncExec(result); + + if (result.fail != null) { + throw result.fail; + } + + return result.result; + } + + abstract void asyncExec(Runnable runnable); + + @Override + public List<Runnable> shutdownNow() { + List<Runnable> result = new ArrayList<Runnable>(); + + shutdown(); + + for (Runnable dequeued = dequeue(); dequeued != null; dequeued = dequeue()) { + result.add(dequeued); + } + + return result; + } + + private RunnableWrapper enqueue(Runnable task) { + RunnableWrapper result = new RunnableWrapper(task); + + lock.lock(); + try { + boolean wasEmpty = pending.isEmpty(); + pending.offer(result); + if (wasEmpty) { + // Now not empty + emptyCond.signalAll(); + } + } finally { + lock.unlock(); + } + + return result; + } + + private RunnableWrapper dequeue() { + RunnableWrapper result = null; + + lock.lock(); + try { + result = pending.poll(); + if (result == null) { + // Now empty + emptyCond.signalAll(); + } + } finally { + lock.unlock(); + } + + return result; + } + + boolean dequeue(RunnableWrapper task) { + boolean result = false; + + lock.lock(); + try { + result = pending.remove(task); + if (result && pending.isEmpty()) { + // Now empty + emptyCond.signalAll(); + } + } finally { + lock.unlock(); + } + + return result; + } + + @Override + public void shutdown() { + shutdown = true; + } + + @Override + public boolean isTerminated() { + lock.lock(); + try { + return isShutdown() && pending.isEmpty(); + } finally { + lock.unlock(); + } + } + + @Override + public boolean isShutdown() { + return shutdown; + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + if (timeout < 0L) { + throw new IllegalArgumentException("negative timeout"); //$NON-NLS-1$ + } + + final Date deadline = (timeout == 0L) ? null : new Date(System.currentTimeMillis() + unit.toMillis(timeout)); + boolean result = false; + + lock.lock(); + try { + boolean stillWaiting = true; + for (result = isTerminated(); !result && stillWaiting; result = isTerminated()) { + if (deadline == null) { + emptyCond.await(); + } else { + stillWaiting = emptyCond.awaitUntil(deadline); + } + } + } finally { + lock.unlock(); + } + + return result; + } + + // + // Nested types + // + + private class RunnableWrapper implements Runnable { + + private final Runnable delegate; + + RunnableWrapper(Runnable delegate) { + this.delegate = delegate; + } + + @Override + public void run() { + // Don't run if I was cancelled by shutdown + if (dequeue(this)) { + delegate.run(); + } + } + } + }; + + private static class DisplayExecutorService extends UIExecutorService { + private final Display display; + + DisplayExecutorService(Display display) { + super(); + + this.display = display; + } + + @Override + void asyncExec(Runnable runnable) { + display.asyncExec(runnable); + } + + @Override + public void syncExec(Runnable task) { + display.syncExec(task); + } + } + + private static class RealmExecutorService extends UIExecutorService { + private final Realm realm; + + RealmExecutorService(Realm realm) { + super(); + + this.realm = realm; + } + + @Override + void asyncExec(Runnable runnable) { + realm.asyncExec(runnable); + } + + @Override + public void syncExec(Runnable task) { + realm.exec(task); + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java new file mode 100644 index 00000000000..c94256dd8f5 --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java @@ -0,0 +1,71 @@ +/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ *
+ * a helper for the Eclipse workbench part
+ *
+ */
+public class WorkbenchPartHelper {
+
+ private WorkbenchPartHelper() {
+ // nothing to do
+ }
+
+ /**
+ *
+ * @return
+ * the current IWorkbenchPart or <code>null</code> if not found
+ */
+ public static final IWorkbenchPart getCurrentActiveWorkbenchPart() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (workbench != null) {
+ final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
+ if (activeWorkbench != null) {
+ final IWorkbenchPage activePage = activeWorkbench.getActivePage();
+ if (activePage != null) {
+ return activePage.getActivePart();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @return
+ * the current IEditorPart or <code>null</code> if not found
+ */
+ public static final IEditorPart getCurrentActiveEditorPart() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (workbench != null) {
+ final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
+ if (activeWorkbench != null) {
+ final IWorkbenchPage activePage = activeWorkbench.getActivePage();
+ if (activePage != null) {
+ return activePage.getActiveEditor();
+ }
+ }
+ }
+ return null;
+ }
+}
|