diff options
author | Christian W. Damus | 2014-07-25 19:19:58 +0000 |
---|---|---|
committer | Gerrit Code Review @ Eclipse.org | 2014-07-25 19:19:58 +0000 |
commit | 43af1aa06fba01ee95ad7b72f07cabf80321bce2 (patch) | |
tree | 244572e62a28ef2180c216b7a9bb445816614cda | |
parent | d558c050796a7e06772835b0b5bb6a936166b0bb (diff) | |
parent | dfde88b139d345b628415dda0769aa87dd7733c6 (diff) | |
download | org.eclipse.papyrus-43af1aa06fba01ee95ad7b72f07cabf80321bce2.tar.gz org.eclipse.papyrus-43af1aa06fba01ee95ad7b72f07cabf80321bce2.tar.xz org.eclipse.papyrus-43af1aa06fba01ee95ad7b72f07cabf80321bce2.zip |
Merge "437217: [Editors] In-place reloading of model resources in the editors https://bugs.eclipse.org/bugs/show_bug.cgi?id=437217"
58 files changed, 4940 insertions, 348 deletions
diff --git a/plugins/editor/org.eclipse.papyrus.editor/META-INF/MANIFEST.MF b/plugins/editor/org.eclipse.papyrus.editor/META-INF/MANIFEST.MF index 4995983e4c5..7e0bbf7ac34 100644 --- a/plugins/editor/org.eclipse.papyrus.editor/META-INF/MANIFEST.MF +++ b/plugins/editor/org.eclipse.papyrus.editor/META-INF/MANIFEST.MF @@ -6,7 +6,8 @@ Require-Bundle: org.eclipse.papyrus.infra.core;bundle-version="1.0.0", org.eclipse.gmf.runtime.diagram.ui;bundle-version="1.5.0",
org.eclipse.papyrus.infra.core.sasheditor;bundle-version="1.0.0",
org.eclipse.ui.ide;bundle-version="3.8.0",
- org.eclipse.papyrus.infra.core.log;bundle-version="1.0.0"
+ org.eclipse.papyrus.infra.core.log;bundle-version="1.0.0",
+ com.google.guava;bundle-version="11.0.0"
Bundle-Vendor: %providerName
Bundle-ActivationPolicy: lazy
Bundle-Version: 1.0.0.qualifier
diff --git a/plugins/editor/org.eclipse.papyrus.editor/src/org/eclipse/papyrus/editor/PapyrusPaletteSynchronizer.java b/plugins/editor/org.eclipse.papyrus.editor/src/org/eclipse/papyrus/editor/PapyrusPaletteSynchronizer.java index ad19bc2d895..f655bfc175a 100644 --- a/plugins/editor/org.eclipse.papyrus.editor/src/org/eclipse/papyrus/editor/PapyrusPaletteSynchronizer.java +++ b/plugins/editor/org.eclipse.papyrus.editor/src/org/eclipse/papyrus/editor/PapyrusPaletteSynchronizer.java @@ -1,3 +1,16 @@ +/***************************************************************************** + * Copyright (c) 2014 Montages AG, 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: + * Montages AG - Initial API and implementation + * Christian W. Damus (CEA) - bug 437217 + * + *****************************************************************************/ package org.eclipse.papyrus.editor; import org.eclipse.gef.ui.views.palette.PaletteView; @@ -20,27 +33,15 @@ import org.eclipse.ui.IWorkbenchPage; public PapyrusPaletteSynchronizer(PapyrusMultiDiagramEditor multiEditor) { myMultiDiagramEditor = multiEditor; + + // Handle the initial page selection + synchronizePaletteView(multiEditor.getISashWindowsContainer().getActiveSashWindowsPage()); } - /* - * (non-Javadoc) - * - * @see - * org.eclipse.papyrus.infra.core.sasheditor.internal.ActivePageTracker.IActiveEditorChangedListener - * #activeEditorChanged(org.eclipse.papyrus.infra.core.sasheditor.internal.PagePart, - * org.eclipse.papyrus.infra.core.sasheditor.internal.PagePart) - */ public void activeEditorChanged(PagePart oldEditor, PagePart newEditor) { synchronizePaletteView(newEditor); } - /* - * (non-Javadoc) - * - * @see - * org.eclipse.papyrus.infra.core.sasheditor.editor.IPageChangedListener#pageChanged(org.eclipse - * .papyrus.infra.core.sasheditor.editor.IPage) - */ public void pageChanged(IPage newPage) { synchronizePaletteView(newPage); } @@ -50,21 +51,21 @@ import org.eclipse.ui.IWorkbenchPage; * inner page * * @param activePage - * inner page to synchronize palette view with + * inner page to synchronize palette view with */ private void synchronizePaletteView(IPage activePage) { PaletteView paletteView = findPaletteView(); - if (paletteView == null) { + if(paletteView == null) { return; } // IEditorPage is not granted, it may be, e.g ErrorComponentPart - IEditorPart activePart = activePage instanceof IEditorPage ? ((IEditorPage) activePage).getIEditorPart() : null; - if (activePart == myLastActivePart) { + IEditorPart activePart = activePage instanceof IEditorPage ? ((IEditorPage)activePage).getIEditorPart() : null; + if(activePart == myLastActivePart) { return; } - - if (activePart == null) { + + if(activePart == null) { paletteView.partClosed(myLastActivePart); } else { // multi-editor may be activated outside of this code @@ -80,15 +81,15 @@ import org.eclipse.ui.IWorkbenchPage; * Called when host editor is disposed, cleans up */ public void dispose() { - if (myLastActivePart == null) { - // nothing to do - return; - } PaletteView paletteView = findPaletteView(); - if (paletteView == null) { + if(paletteView == null) { return; } - paletteView.partClosed(myLastActivePart); + if(myLastActivePart != null) { + paletteView.partClosed(myLastActivePart); + } else { + paletteView.partClosed(myMultiDiagramEditor); + } } /** @@ -98,7 +99,7 @@ import org.eclipse.ui.IWorkbenchPage; */ private PaletteView findPaletteView() { IWorkbenchPage samePage = myMultiDiagramEditor.getSite().getPage(); - return (PaletteView) samePage.findView(PaletteView.ID); + return (PaletteView)samePage.findView(PaletteView.ID); } } diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/editor/AbstractMultiPageSashEditor.java b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/editor/AbstractMultiPageSashEditor.java index 69e50222664..c33a59e41df 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/editor/AbstractMultiPageSashEditor.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/editor/AbstractMultiPageSashEditor.java @@ -9,6 +9,7 @@ * Contributors:
* Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
* Christian W. Damus (CEA) - bug 431953 (pre-requisite refactoring of ModelSet service start-up)
+ * Christian W. Damus (CEA) - bug 437217
*
*****************************************************************************/
package org.eclipse.papyrus.infra.core.sasheditor.editor;
@@ -33,6 +34,9 @@ import org.eclipse.ui.part.EditorPart; */
public abstract class AbstractMultiPageSashEditor extends EditorPart implements IMultiPageEditorPart, IMultiEditorManager {
+ /** The parent composite of my sash container. */
+ private Composite parentComposite;
+
/** The pageProvider */
private ISashWindowsContentProvider pageProvider;
@@ -116,7 +120,6 @@ public abstract class AbstractMultiPageSashEditor extends EditorPart implements public void init(IEditorSite site, IEditorInput input) throws PartInitException {
setSite(site);
setInput(input);
- site.setSelectionProvider(new MultiPageSelectionProvider(this));
}
/**
@@ -124,15 +127,10 @@ public abstract class AbstractMultiPageSashEditor extends EditorPart implements */
@Override
public void createPartControl(Composite parent) {
-
- // Create and intialize sash windows
- sashContainer = new SashWindowsContainer(this);
- sashContainer.setContentProvider(getContentProvider());
- sashContainer.createPartControl(parent);
-
- // Add double click menu
- tabMouseEventListener = new TabMouseEventListener(sashContainer, getSite());
-
+ parentComposite = parent;
+
+ getSite().setSelectionProvider(new MultiPageSelectionProvider(this));
+
activate();
}
@@ -143,6 +141,14 @@ public abstract class AbstractMultiPageSashEditor extends EditorPart implements */
protected void activate() {
+ // Create and initialize sash windows
+ sashContainer = new SashWindowsContainer(this);
+ sashContainer.setContentProvider(getContentProvider());
+ sashContainer.createPartControl(parentComposite);
+
+ // Add double click menu
+ tabMouseEventListener = new TabMouseEventListener(sashContainer, getSite());
+
tabsSynchronizer = new SashTabDecorationSynchronizer(sashContainer);
}
@@ -160,6 +166,16 @@ public abstract class AbstractMultiPageSashEditor extends EditorPart implements }
tabsSynchronizer.dispose();
tabsSynchronizer = null;
+
+ if(tabMouseEventListener != null) {
+ tabMouseEventListener.dispose(sashContainer);
+ tabMouseEventListener = null;
+ }
+
+ if(sashContainer != null) {
+ sashContainer.dispose();
+ }
+ pageProvider = null;
}
/**
@@ -171,18 +187,9 @@ public abstract class AbstractMultiPageSashEditor extends EditorPart implements @Override
public void dispose() {
deactivate();
-
- if(tabMouseEventListener != null) {
- tabMouseEventListener.dispose(sashContainer);
- tabMouseEventListener = null;
- }
-
+
//The selection provider keeps a reference to "this". It is not disposed.
getSite().setSelectionProvider(null);
- if(sashContainer != null) {
- sashContainer.dispose();
- }
- pageProvider = null;
super.dispose();
}
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/SashWindowsContainer.java b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/SashWindowsContainer.java index 35c7316ff8e..926883e994d 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/SashWindowsContainer.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/SashWindowsContainer.java @@ -1,6 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2009 CEA LIST & LIFL
- *
+ * Copyright (c) 2009, 2014 LIFL, 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
@@ -9,6 +8,7 @@ *
* Contributors:
* Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437217
*
*****************************************************************************/
package org.eclipse.papyrus.infra.core.sasheditor.internal;
@@ -284,7 +284,13 @@ public class SashWindowsContainer implements ISashWindowsContainer { // End disposing children's SWT controls.
// It is possible to recall the dispose() method on a Widget, even if we are called by the dispose event.
// Recalling the dispose method will continue disposing SWT children's.
- container.dispose();
+
+ // DO NOT dispose the container composite, as we did not create it!
+ if(container != null) {
+ for(Control next : container.getChildren()) {
+ next.dispose();
+ }
+ }
// dispose part children
if(rootPart!=null) {
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/META-INF/MANIFEST.MF b/plugins/infra/core/org.eclipse.papyrus.infra.core/META-INF/MANIFEST.MF index 72fe68e603a..b60b29d15a7 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/META-INF/MANIFEST.MF +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/META-INF/MANIFEST.MF @@ -1,8 +1,9 @@ Manifest-Version: 1.0
Export-Package: org.eclipse.papyrus.infra.core,
- org.eclipse.papyrus.infra.core.clipboard, + org.eclipse.papyrus.infra.core.clipboard,
org.eclipse.papyrus.infra.core.contentoutline,
org.eclipse.papyrus.infra.core.editor,
+ org.eclipse.papyrus.infra.core.editor.reload,
org.eclipse.papyrus.infra.core.editorsfactory,
org.eclipse.papyrus.infra.core.extension,
org.eclipse.papyrus.infra.core.extension.commands,
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/contentoutline/NestedEditorDelegatedOutlinePage.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/contentoutline/NestedEditorDelegatedOutlinePage.java index 491760a70d4..3e75bfbff41 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/contentoutline/NestedEditorDelegatedOutlinePage.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/contentoutline/NestedEditorDelegatedOutlinePage.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * 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
@@ -8,6 +8,7 @@ *
* Contributors:
* Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437217
*
*****************************************************************************/
package org.eclipse.papyrus.infra.core.contentoutline;
@@ -17,6 +18,7 @@ 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;
@@ -24,15 +26,25 @@ 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.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.editor.IReloadableEditor;
+import org.eclipse.papyrus.infra.core.editor.reload.EditorReloadEvent;
+import org.eclipse.papyrus.infra.core.editor.reload.IEditorReloadListener;
+import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider;
+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.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
@@ -50,10 +62,15 @@ 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 {
+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;
@@ -82,7 +99,16 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo * {@inheritDoc}
*/
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);
}
/**
@@ -103,6 +129,19 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo */
@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) {
@@ -122,9 +161,6 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo // remove listener and all refs to editor
sashWindowsContainer.removePageLifeCycleListener(this);
-
- // Run super.
- super.dispose();
}
/**
@@ -182,10 +218,12 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo */
@Override
public void createControl(Composite parent) {
- sashWindowsContainer.addPageLifeCycleListener(this);
-
sashEditorPageBook = new PageBook(parent, SWT.BORDER);
+ createContents();
+ }
+
+ protected void createContents() {
// Create the default page rec.
IContentOutlinePage defaultPage = createDefaultPage(sashEditorPageBook);
defaultPageRec = new OutlinePageRec(null, defaultPage);
@@ -274,11 +312,8 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo */
public void pageActivated(IPage page) {
// Activator.log.debug("Activated");
- // Create a page for the part.
- OutlinePageRec rec = getOutlinePageRec(page);
- if(rec == null) {
- rec = createPage(page);
- }
+ // Create a page for the partm, if necessary.
+ OutlinePageRec rec = getOutlinePageRec(page, true);
// Show the page, if it was successfully created
if(rec != null) {
@@ -309,6 +344,21 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo //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
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -537,6 +587,14 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo 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.
*
@@ -572,14 +630,15 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo control.dispose();
}
- // free the page
- doDestroyPage(rec.papyrusPage, rec);
-
+ // 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);
}
/*
@@ -952,4 +1011,67 @@ public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusCo }
}
+
+ 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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/CoreMultiDiagramEditor.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/CoreMultiDiagramEditor.java index 70800f02d49..50644e87186 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/CoreMultiDiagramEditor.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/CoreMultiDiagramEditor.java @@ -12,6 +12,7 @@ * 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
*
*****************************************************************************/
@@ -22,10 +23,14 @@ import static org.eclipse.papyrus.infra.core.Activator.log; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
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.Status;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.URI;
@@ -41,10 +46,13 @@ import org.eclipse.gef.ui.actions.ActionRegistry; import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.papyrus.infra.core.Activator;
import org.eclipse.papyrus.infra.core.contentoutline.ContentOutlineRegistry;
+import org.eclipse.papyrus.infra.core.editor.reload.EditorReloadEvent;
+import org.eclipse.papyrus.infra.core.editor.reload.IEditorReloadListener;
import org.eclipse.papyrus.infra.core.lifecycleevents.DoSaveEvent;
import org.eclipse.papyrus.infra.core.lifecycleevents.IEditorInputChangedListener;
import org.eclipse.papyrus.infra.core.lifecycleevents.ISaveAndDirtyService;
@@ -86,11 +94,15 @@ 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.IWorkbenchSiteProgressService;
+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 org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
+import com.google.common.collect.ImmutableList;
+
/**
* Multi diagram editor allowing to plug various kind of editors. Editors are
* registered with the help of the Eclipse extension mechanism. This
@@ -194,7 +206,7 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen }
}
- protected EditorInputChangedListener editorInputChangedListener = new EditorInputChangedListener(this);
+ protected EditorInputChangedListener editorInputChangedListener;
private TransactionalEditingDomain transactionalEditingDomain;
@@ -222,7 +234,7 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen /**
* A listener on model change events.
*/
- private ContentChangedListener contentChangedListener = new ContentChangedListener();
+ private ContentChangedListener contentChangedListener;
/**
* Undo context used to have the same undo context in all Papyrus related
@@ -233,6 +245,22 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen private IUndoContext undoContext;
/**
+ * Editor reload listeners.
+ */
+ private CopyOnWriteArrayList<IEditorReloadListener> reloadListeners = new CopyOnWriteArrayList<IEditorReloadListener>();
+
+ /**
+ * Whether a re-load is currently pending (awaiting next activation of the editor).
+ */
+ private boolean reloadPending;
+
+ public CoreMultiDiagramEditor() {
+ super();
+
+ addSelfReloadListener();
+ }
+
+ /**
* Get the contentOutlineRegistry. Create it if needed.
*
* @return the contentOutlineRegistry
@@ -431,6 +459,10 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen return getSite().getSelectionProvider().getSelection();
}
+ if(adapter == IReloadableEditor.class) {
+ return createReloadAdapter();
+ }
+
return super.getAdapter(adapter);
}
@@ -445,8 +477,7 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen // Set editor name
setPartName(input.getName());
- loadModelAndServices();
- loadNestedEditors();
+ initContents();
}
@Override
@@ -610,6 +641,7 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen // Listen on input changed from the ISaveAndDirtyService
+ editorInputChangedListener = new EditorInputChangedListener(this);
saveAndDirtyService.addInputChangedListener(editorInputChangedListener);
getLifecycleManager().firePostInit(this);
}
@@ -642,6 +674,9 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen setContentProvider(contentProvider);
// Listen on contentProvider changes
+ if(contentChangedListener == null) {
+ contentChangedListener = new ContentChangedListener();
+ }
sashModelMngr.getSashModelContentChangedProvider().addListener(contentChangedListener);
IEditorInput input = getEditorInput();
@@ -680,8 +715,8 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen */
@Override
protected void activate() {
- // TODO Auto-generated method stub
super.activate();
+
initFolderTabMenus();
try {
@@ -739,17 +774,77 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen */
@Override
public void dispose() {
+ for(IPropertySheetPage propertiesPage : this.propertiesPages) {
+ propertiesPage.dispose();
+ }
+ propertiesPages.clear();
+
+ super.dispose();
+ }
+
+ private IReloadableEditor createReloadAdapter() {
+ return new IReloadableEditor() {
+
+ @Override
+ public void reloadEditor(boolean save) throws CoreException {
+ reloadPending = true;
+
+ if(save) {
+ try {
+ ((IWorkbenchSiteProgressService)getSite().getService(IWorkbenchSiteProgressService.class)).busyCursorWhile(new IRunnableWithProgress() {
+
+ @Override
+ public void run(IProgressMonitor monitor) {
+ doSave(monitor);
+ }
+ });
+ } catch (Exception e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Save before re-load failed.", e)); //$NON-NLS-1$
+ }
+ }
+
+ // If I am already active, then re-load now
+ IWorkbenchPage page = getSite().getPage();
+ if(page.getActiveEditor() == CoreMultiDiagramEditor.this) {
+ doReload();
+ }
+ }
+
+ @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());
+ }
+ });
+ }
+
+ @Override
+ protected void deactivate() {
getLifecycleManager().fireBeforeClose(this);
if(sashModelMngr != null) {
sashModelMngr.getSashModelContentChangedProvider().removeListener(contentChangedListener);
}
- // Avoid memory leak
- // This call is done from the ServicesRegistry when it is disposed.
- // Don't need to do it there.
- // if(resourceSet != null) {
- // resourceSet.unload();
- // }
+ super.deactivate();
// dispose available service
if(servicesRegistry != null) {
@@ -781,13 +876,66 @@ public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implemen undoContext = null;
saveAndDirtyService = null;
sashModelMngr = null;
+ }
- for(IPropertySheetPage propertiesPage : this.propertiesPages) {
- propertiesPage.dispose();
+ void initContents() throws PartInitException {
+ loadModelAndServices();
+ loadNestedEditors();
+ }
+
+ @Override
+ public void setFocus() {
+ super.setFocus();
+
+ if(isReloadPending()) {
+ doReload();
+ }
+ }
+
+ boolean isReloadPending() {
+ return reloadPending;
+ }
+
+ private void doReload() {
+ reloadPending = false;
+
+ 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);
+ } catch (CoreException e) {
+ // Failed to properly unload/load in place, so just close
+ page.closeEditor(CoreMultiDiagramEditor.this, false);
+
+ StatusManager.getManager().handle(e.getStatus(), StatusManager.LOG | StatusManager.SHOW);
+ } 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);
+ }
}
- propertiesPages.clear();
- super.dispose();
}
/**
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/IReloadableEditor.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/IReloadableEditor.java new file mode 100644 index 00000000000..be3a7c7aca4 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/IReloadableEditor.java @@ -0,0 +1,106 @@ +/* + * 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.core.editor; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.papyrus.infra.core.Activator; +import org.eclipse.papyrus.infra.core.editor.reload.IEditorReloadListener; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +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 save + * whether to save before re-loading + * + * @throws CoreException + * on any failure to unload, reload, or whatever + */ + void reloadEditor(boolean save) throws CoreException; + + void addEditorReloadListener(IEditorReloadListener listener); + + void removeEditorReloadListener(IEditorReloadListener listener); + + /** + * 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 AdapterUtils.adapt(editor, IReloadableEditor.class, new Adapter(editor)); + } + + public void reloadEditor(boolean save) 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(); + + if(save) { + editor.doSave(new NullProgressMonitor()); + } + + page.closeEditor(editor, save); + + 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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/MultiDiagramEditorSelectionContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/MultiDiagramEditorSelectionContext.java new file mode 100644 index 00000000000..366b636e7c1 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/MultiDiagramEditorSelectionContext.java @@ -0,0 +1,218 @@ +/* + * 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.core.editor; + +import java.util.List; + +import org.eclipse.emf.common.util.URI; +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.editor.reload.CompositeReloadContext; +import org.eclipse.papyrus.infra.core.editor.reload.DelegatingReloadContext; +import org.eclipse.papyrus.infra.core.editor.reload.EMFSelectionContext; +import org.eclipse.papyrus.infra.core.editor.reload.EditorReloadEvent; +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 com.google.common.collect.Lists; + + +/** + * 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; + + MultiDiagramEditorSelectionContext(IMultiDiagramEditor editor) { + super(); + + init(editor); + + ActivePageSelectionProvider activePageSelectionProvider = new ActivePageSelectionProvider(); + IPage active = sashContainer.getActiveSashWindowsPage(); + DiagramPageContext activePage = null; + + List<IPage> visible = getAllPages(sashContainer); + + for(IPage page : visible) { + 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(activePageSelectionProvider, page, delegator); + activePage = context; + } else { + // We make sure always to restore the active page last + // so that its selection is certain to be set properly + context = new DiagramPageContext(EmptySelectionProvider.INSTANCE, page, delegator); + 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); + + ISelectionProvider selectionProvider = new ActivePageSelectionProvider(); + for(DiagramPageContext next : getReloadContexts(DiagramPageContext.class)) { + next.restore(selectionProvider); + } + } + + // + // 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 ActivePageSelectionProvider implements ISelectionProvider { + + ActivePageSelectionProvider() { + super(); + } + + @Override + public ISelection getSelection() { + IPage active = sashContainer.getActiveSashWindowsPage(); + + return (active == null) ? StructuredSelection.EMPTY : new StructuredSelection(active); + } + + @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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/CompositeReloadContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/CompositeReloadContext.java new file mode 100644 index 00000000000..57d99c9fd03 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/DelegatingReloadContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/DelegatingReloadContext.java new file mode 100644 index 00000000000..405c7c9977d --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EMFSelectionContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EMFSelectionContext.java new file mode 100644 index 00000000000..e625a97aad7 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EMFTreeViewerContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EMFTreeViewerContext.java new file mode 100644 index 00000000000..91b01e98d15 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EditorReloadAdapter.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EditorReloadAdapter.java new file mode 100644 index 00000000000..64a8445081c --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EditorReloadEvent.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EditorReloadEvent.java new file mode 100644 index 00000000000..20416bc86d8 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/EditorReloadEvent.java @@ -0,0 +1,189 @@ +/* + * 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.core.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.Activator; +import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor; +import org.eclipse.papyrus.infra.core.editor.IReloadableEditor; +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 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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IDisposableReloadContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IDisposableReloadContext.java new file mode 100644 index 00000000000..2e44d932fa6 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IEditorReloadListener.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IEditorReloadListener.java new file mode 100644 index 00000000000..27387a89c7c --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.editor.reload; + +import java.util.EventListener; + +import org.eclipse.papyrus.infra.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IInternalEMFSelectionContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IInternalEMFSelectionContext.java new file mode 100644 index 00000000000..c0c031a0378 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IInternalEMFSelectionContext.java @@ -0,0 +1,106 @@ +/* + * 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.core.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(); + } + + public void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier) { + this.resourceSetSupplier = Suppliers.memoize(resourceSetSupplier); + } + + public URI getToken(Object object) { + return (object instanceof EObject) ? EcoreUtil.getURI((EObject)object) : null; + } + + 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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IReloadContextProvider.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/IReloadContextProvider.java new file mode 100644 index 00000000000..281c629e023 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/SelectionContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/SelectionContext.java new file mode 100644 index 00000000000..cfe1e3be89a --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/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.core.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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/TreeViewerContext.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/TreeViewerContext.java new file mode 100644 index 00000000000..2c2ec8520cf --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/editor/reload/TreeViewerContext.java @@ -0,0 +1,62 @@ +/* + * 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.core.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); + } + } + } + + 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); + } + + 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/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/services/ResourceUpdateService.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/services/ResourceUpdateService.java index 3cf5783c524..74ac57d45c2 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/services/ResourceUpdateService.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/services/ResourceUpdateService.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,12 +9,14 @@ *
* Contributors:
* Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437217
*
*****************************************************************************/
package org.eclipse.papyrus.infra.core.services;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.concurrent.ConcurrentMap;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
@@ -23,14 +25,21 @@ 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.NullProgressMonitor;
+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.emf.edit.domain.EditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.infra.core.Activator;
import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.editor.IReloadableEditor;
import org.eclipse.papyrus.infra.core.lifecycleevents.DoSaveEvent;
import org.eclipse.papyrus.infra.core.lifecycleevents.ILifeCycleEventsProvider;
import org.eclipse.papyrus.infra.core.lifecycleevents.ISaveAndDirtyService;
@@ -38,12 +47,14 @@ import org.eclipse.papyrus.infra.core.lifecycleevents.ISaveEventListener; import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.ide.IDE;
+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
@@ -61,6 +72,8 @@ public class ResourceUpdateService implements IService, IPartListener { protected boolean isSaving;
+ protected ConcurrentMap<IMultiDiagramEditor, Job> pendingEditorCloseJobs = Maps.newConcurrentMap();
+
/**
* Update isSaving flag asynchronously to avoid race conditions, see bug 411574
*/
@@ -129,38 +142,49 @@ public class ResourceUpdateService implements IService, IPartListener { }
final IMultiDiagramEditor editor = registry.getService(IMultiDiagramEditor.class);
if(editor != null) {
- Runnable closeEditorRunnable = new Runnable() {
+ final IWorkbenchPartSite site = editor.getSite();
+ UIJob closeEditorJob = new UIJob(site.getShell().getDisplay(), NLS.bind("Reload editor {0}", editor.getTitle())) {
@Override
- public void run() {
- final IWorkbenchPage page = editor.getSite().getPage();
- final IEditorInput currentInput = editor.getEditorInput();
-
-
- final String editorId = editor.getSite().getId();
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ // Remove the pending job
+ pendingEditorCloseJobs.remove(editor);
+
+ IStatus result = Status.OK_STATUS;
+ monitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
+
+ try {
+ if(reopen) {
+ try {
+ IReloadableEditor.Adapter.getAdapter(editor).reloadEditor(save);
+ } catch (CoreException e) {
+ result = e.getStatus();
+ }
+ } else {
+ // Just close it
- if(save) {
- editor.doSave(new NullProgressMonitor());
- }
- page.closeEditor(editor, save);
- if(reopen) {
- Display.getCurrent().asyncExec(new Runnable() {
-
- @Override
- public void run() {
- try {
- IDE.openEditor(page, currentInput, editorId);
- } catch (PartInitException ex) {
- Activator.log.error(ex);
- }
+ if(save) {
+ editor.doSave(new NullProgressMonitor());
}
- });
+
+ final IWorkbenchPage page = editor.getSite().getPage();
+ page.closeEditor(editor, save);
+ }
+ } finally {
+ monitor.done();
}
+
+ return result;
}
};
- //Async execution to avoid lock conflicts on the Workspace (Probably owned by this thread, and not the UI thread)
- editor.getSite().getShell().getDisplay().asyncExec(closeEditorRunnable);
+ // 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 = (IWorkbenchSiteProgressService)site.getService(IWorkbenchSiteProgressService.class);
+ progressService.schedule(closeEditorJob);
+ }
}
} catch (ServiceException ex) {
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/plugin.xml b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/plugin.xml index ec5c2816412..d24fc3ff8eb 100644 --- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/plugin.xml +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/plugin.xml @@ -133,6 +133,13 @@ type="org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IOpenable"> </adapter> </factory> + <factory + adaptableType="org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor$DiagramOutlinePage" + class="org.eclipse.papyrus.infra.gmfdiag.common.adapter.DiagramOutlineAdapterFactory"> + <adapter + type="org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider"> + </adapter> + </factory> </extension> <!-- ElementType bindings for diagram duplication with paste command --> diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/DiagramReloadContextProvider.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/DiagramReloadContextProvider.java new file mode 100644 index 00000000000..0250f075318 --- /dev/null +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/DiagramReloadContextProvider.java @@ -0,0 +1,149 @@ +/* + * 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.gmfdiag.common; + +import java.util.Collection; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gef.EditDomain; +import org.eclipse.gef.EditPart; +import org.eclipse.gef.ui.palette.PaletteViewer; +import org.eclipse.gef.ui.views.palette.PalettePage; +import org.eclipse.papyrus.infra.core.editor.reload.EMFSelectionContext; +import org.eclipse.papyrus.infra.core.editor.reload.EditorReloadEvent; +import org.eclipse.papyrus.infra.core.editor.reload.IDisposableReloadContext; +import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; + +import com.google.common.collect.Iterables; + + +/** + * An {@linkplain EditorReloadEvent editor reload} context provider for nested diagram editors, providing + * a reload context that captures and restores the edit-part selection (tracked by URI of the selected + * edit parts' notation views) and palette state (delegated to a {@link PaletteViewerReloadContextProvider}). + */ +class DiagramReloadContextProvider implements IReloadContextProvider { + + private final SynchronizableGmfDiagramEditor editor; + + public DiagramReloadContextProvider(SynchronizableGmfDiagramEditor editor) { + this.editor = editor; + } + + @Override + public Object createReloadContext() { + return new DiagramSelectionContext(editor); + } + + @Override + public void restore(Object reloadContext) { + ((DiagramSelectionContext)reloadContext).restore(editor); + } + + // + // Nested types + // + + private static class DiagramSelectionContext extends EMFSelectionContext implements IDisposableReloadContext { + + private SynchronizableGmfDiagramEditor editor; + + private Object embeddedPaletteContext; + + private Object palettePageContext; + + DiagramSelectionContext(SynchronizableGmfDiagramEditor editor) { + super(editor.getDiagramGraphicalViewer()); + + PaletteViewer embedded = getEmbeddedPalette(editor); + if(embedded != null) { + embeddedPaletteContext = PaletteViewerReloadContextProvider.getInstance(embedded).createReloadContext(); + } + + PalettePage page = Iterables.getFirst(editor.getPalettePages(), null); + if(page != null) { + // Get one context for all the pages (there should be only one Palette view!) + IReloadContextProvider pageProvider = AdapterUtils.adapt(page, IReloadContextProvider.class, null); + if(pageProvider != null) { + palettePageContext = pageProvider.createReloadContext(); + } + } + } + + @Override + public void dispose() { + editor = null; + embeddedPaletteContext = null; + palettePageContext = null; + } + + void restore(SynchronizableGmfDiagramEditor editor) { + this.editor = editor; + + restore(editor.getDiagramGraphicalViewer()); + + if(embeddedPaletteContext != null) { + PaletteViewer palette = getEmbeddedPalette(editor); + if(palette != null) { + PaletteViewerReloadContextProvider.getInstance(palette).restore(embeddedPaletteContext); + } + } + + if(palettePageContext != null) { + Collection<? extends PalettePage> pages = editor.getPalettePages(); + if(pages.isEmpty()) { + // Defer until the page is created (which we assume it eventually will be, since evidently it + // was there when we captured the reload context) + editor.setDeferredPalettePageReloadContext(palettePageContext); + } else { + for(PalettePage page : pages) { + IReloadContextProvider pageProvider = AdapterUtils.adapt(page, IReloadContextProvider.class, null); + if(pageProvider != null) { + pageProvider.restore(palettePageContext); + } + } + } + } + } + + @Override + protected Object deresolveSelectableElement(Object selectableElement) { + Object result = null; + + if(selectableElement instanceof EditPart) { + Object model = ((EditPart)selectableElement).getModel(); + if(model instanceof EObject) { + result = model; + } + } + + return result; + } + + @Override + protected Object resolveSelectableElement(Object deresolved) { + return editor.getDiagramGraphicalViewer().getEditPartRegistry().get(deresolved); + } + + PaletteViewer getEmbeddedPalette(SynchronizableGmfDiagramEditor editor) { + PaletteViewer result = null; + + if(editor.getDiagramEditDomain() instanceof EditDomain) { + result = ((EditDomain)editor.getDiagramEditDomain()).getPaletteViewer(); + } + + return result; + } + } +} diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/PaletteViewerReloadContextProvider.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/PaletteViewerReloadContextProvider.java new file mode 100644 index 00000000000..630f4994d46 --- /dev/null +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/PaletteViewerReloadContextProvider.java @@ -0,0 +1,117 @@ +/* + * 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.gmfdiag.common; + +import java.util.List; + +import org.eclipse.gef.palette.PaletteContainer; +import org.eclipse.gef.palette.PaletteEntry; +import org.eclipse.gef.palette.PaletteStack; +import org.eclipse.gef.ui.palette.PaletteViewer; +import org.eclipse.papyrus.infra.core.editor.reload.EditorReloadEvent; +import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; +import org.eclipse.papyrus.infra.tools.util.UIUtil; +import org.eclipse.ui.IMemento; + + +/** + * An {@linkplain EditorReloadEvent editor reload} context provider for palette viewers, providing + * a reload context that captures and restores the expansion states of drawers and selection states + * of stacks and tools. + */ +class PaletteViewerReloadContextProvider implements IReloadContextProvider { + + private static final String MEMENTO_ACTIVE_ENTRY = "activeEntry"; //$NON-NLS-1$ + + private PaletteViewer palette; + + public PaletteViewerReloadContextProvider(PaletteViewer palette) { + super(); + + this.palette = palette; + } + + public static IReloadContextProvider getInstance(PaletteViewer palette) { + IReloadContextProvider result = AdapterUtils.adapt(palette, IReloadContextProvider.class, null); + + if(result == null) { + result = new PaletteViewerReloadContextProvider(palette); + } + + return result; + } + + @Override + public Object createReloadContext() { + IMemento result = UIUtil.createLocalMemento(); + palette.saveState(result); + saveMoreState(palette.getPaletteRoot(), result); + return result; + } + + @Override + public void restore(Object reloadContext) { + IMemento memento = (IMemento)reloadContext; + palette.restoreState(memento); + restoreMoreState(palette.getPaletteRoot(), memento); + } + + /** + * The palette's own memento doesn't record which tool of a stack is the stack's active tool. + */ + void saveMoreState(PaletteEntry entry, IMemento memento) { + if(entry instanceof PaletteStack) { + PaletteStack stack = (PaletteStack)entry; + memento.putInteger(MEMENTO_ACTIVE_ENTRY, stack.getChildren().indexOf(stack.getActiveEntry())); + } + + if(entry instanceof PaletteContainer) { + PaletteContainer container = (PaletteContainer)entry; + List<?> children = container.getChildren(); + IMemento[] mementos = memento.getChildren(); + + int max = Math.min(children.size(), mementos.length); + for(int i = 0; i < max; i++) { + saveMoreState((PaletteEntry)children.get(i), mementos[i]); + } + } + } + + /** + * @see #saveMoreState(PaletteEntry, IMemento) + */ + void restoreMoreState(PaletteEntry entry, IMemento memento) { + if(entry instanceof PaletteStack) { + PaletteStack stack = (PaletteStack)entry; + List<?> children = stack.getChildren(); + + int activeIndex = memento.getInteger(MEMENTO_ACTIVE_ENTRY); + if((activeIndex >= 0) && (activeIndex < children.size())) { + stack.setActiveEntry((PaletteEntry)children.get(activeIndex)); + } + } + + if(entry instanceof PaletteContainer) { + PaletteContainer container = (PaletteContainer)entry; + List<?> children = container.getChildren(); + IMemento[] mementos = memento.getChildren(); + + int max = Math.min(children.size(), mementos.length); + for(int i = 0; i < max; i++) { + restoreMoreState((PaletteEntry)children.get(i), mementos[i]); + } + } + } + +} diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/SynchronizableGmfDiagramEditor.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/SynchronizableGmfDiagramEditor.java index f1a007ac59d..42aa9c6f1bb 100644 --- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/SynchronizableGmfDiagramEditor.java +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/SynchronizableGmfDiagramEditor.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@ *
* Contributors:
* Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437217
*
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.common;
@@ -21,11 +22,14 @@ import java.util.Map; import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.emf.transaction.RollbackException;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.CommandStack;
+import org.eclipse.gef.ui.palette.PaletteViewer;
+import org.eclipse.gef.ui.views.palette.PalettePage;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
@@ -41,6 +45,7 @@ import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.papyrus.commands.CheckedDiagramCommandStack;
+import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider;
import org.eclipse.papyrus.infra.gmfdiag.common.preferences.PreferencesConstantsHelper;
import org.eclipse.papyrus.infra.gmfdiag.common.reconciler.DiagramReconciler;
import org.eclipse.papyrus.infra.gmfdiag.common.reconciler.DiagramReconcilersReader;
@@ -50,9 +55,18 @@ import org.eclipse.papyrus.infra.gmfdiag.common.utils.GMFUnsafe; import org.eclipse.papyrus.infra.tools.util.EclipseCommandUtils;
import org.eclipse.papyrus.infra.widgets.util.IRevealSemanticElement;
import org.eclipse.papyrus.infra.widgets.util.NavigationTarget;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IActionBars;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.part.IPageSite;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
/**
*
@@ -66,6 +80,10 @@ import org.eclipse.ui.commands.ICommandService; //suppress the warning for WorkspaceViewerProperties
public class SynchronizableGmfDiagramEditor extends DiagramDocumentEditor implements IRevealSemanticElement, NavigationTarget {
+ private Collection<PalettePageWrapper> palettePages;
+
+ private Object palettePageState;
+
public SynchronizableGmfDiagramEditor(boolean hasFlyoutPalette) {
super(hasFlyoutPalette);
}
@@ -151,9 +169,48 @@ public class SynchronizableGmfDiagramEditor extends DiagramDocumentEditor implem if(type == Diagram.class) {
return getDiagram();
}
+ if(type == IReloadContextProvider.class) {
+ return new DiagramReloadContextProvider(this);
+ }
+ if(type == PalettePage.class) {
+ if(palettePages == null) {
+ palettePages = Lists.newArrayListWithExpectedSize(1);
+ } else {
+ cleanUpPalettePages();
+ if(!palettePages.isEmpty()) {
+ // Make the new page look just like the last one (for continuity of the UI when the
+ // PapyrusPaletteSynchronizer causes a new page to be created)
+ Iterables.getLast(palettePages, null).saveState();
+ }
+ }
+ PalettePageWrapper result = new PalettePageWrapper((CustomPalettePage)super.getAdapter(type));
+ palettePages.add(result);
+ return result;
+ }
return super.getAdapter(type);
}
+ Collection<? extends PalettePage> getPalettePages() {
+ if(palettePages == null) {
+ return Collections.emptyList();
+ } else {
+ cleanUpPalettePages();
+ return Collections.unmodifiableCollection(palettePages);
+ }
+ }
+
+ void setDeferredPalettePageReloadContext(Object reloadContext) {
+ palettePageState = reloadContext;
+ }
+
+ private void cleanUpPalettePages() {
+ for(Iterator<PalettePageWrapper> iter = palettePages.iterator(); iter.hasNext();) {
+ if(iter.next().isDisposed()) {
+ iter.remove();
+ }
+ }
+ }
+
/**
* Configures my diagram edit domain with its command stack.
* This method has been completely overridden in order to use a proxy stack.
@@ -357,6 +414,109 @@ public class SynchronizableGmfDiagramEditor extends DiagramDocumentEditor implem }
}
+ protected class PalettePageWrapper implements PalettePage, IAdaptable {
+
+ private final CustomPalettePage delegate;
+
+ private boolean disposed;
+
+ protected PalettePageWrapper(CustomPalettePage delegate) {
+ this.delegate = delegate;
+ }
+
+ public void createControl(Composite parent) {
+ Control existing = getControl();
+ if((existing != null) && !existing.isDisposed()) {
+ // Attempting to creating the page controls again? Bail
+ return;
+ }
+
+ delegate.createControl(parent);
+
+ delegate.getControl().addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ disposed = true;
+
+ SynchronizableGmfDiagramEditor.this.palettePages.remove(PalettePageWrapper.this);
+ }
+ });
+
+ if(palettePageState != null) {
+ // We're re-creating the palette page after having closed it, either for editor re-load
+ // or the PapyrusPaletteSynchronizer forcing a palette refresh. Reinitialize from the
+ // last saved state
+ PaletteViewerReloadContextProvider.getInstance(getPaletteViewer()).restore(palettePageState);
+ palettePageState = null;
+ }
+ }
+
+ public void dispose() {
+ // Save current state for potential re-opening later
+ saveState();
+ delegate.dispose();
+ }
+
+ public boolean isDisposed() {
+ return disposed;
+ }
+
+ void saveState() {
+ PaletteViewer palette = getPaletteViewer();
+ if(palette != null) {
+ palettePageState = PaletteViewerReloadContextProvider.getInstance(palette).createReloadContext();
+ }
+ }
+
+ public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
+ if(adapter == IReloadContextProvider.class) {
+ return new IReloadContextProvider() {
+
+ @Override
+ public Object createReloadContext() {
+ return (getPaletteViewer() != null) ? PaletteViewerReloadContextProvider.getInstance(getPaletteViewer()).createReloadContext() : null;
+ }
+
+ @Override
+ public void restore(Object reloadContext) {
+ if(getPaletteViewer() != null) {
+ PaletteViewerReloadContextProvider.getInstance(getPaletteViewer()).restore(reloadContext);
+ } else {
+ // We'll defer this until the page control is created
+ palettePageState = reloadContext;
+ }
+ }
+ };
+ }
+ return delegate.getAdapter(adapter);
+ }
+
+ public Control getControl() {
+ // CustomPalettePage will NPE if asked for the control before the PaletteViewer is created
+ return (delegate.getPaletteViewer() == null) ? null : delegate.getControl();
+ }
+
+ public void setFocus() {
+ delegate.setFocus();
+ }
+
+ public void setActionBars(IActionBars actionBars) {
+ delegate.setActionBars(actionBars);
+ }
+ public void init(IPageSite pageSite) {
+ delegate.init(pageSite);
+ }
+
+ public IPageSite getSite() {
+ return delegate.getSite();
+ }
+
+ public PaletteViewer getPaletteViewer() {
+ return delegate.getPaletteViewer();
+ }
+
+ }
}
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/adapter/DiagramOutlineAdapterFactory.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/adapter/DiagramOutlineAdapterFactory.java new file mode 100644 index 00000000000..acf4fde39ae --- /dev/null +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/adapter/DiagramOutlineAdapterFactory.java @@ -0,0 +1,39 @@ +/* + * 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.gmfdiag.common.adapter; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider; + +/** + * An adapter factory for the outline page contributed by nested diagram editors. + */ +public class DiagramOutlineAdapterFactory implements IAdapterFactory { + + private static final Class<?>[] ADAPTERS = { IReloadContextProvider.class }; + + @SuppressWarnings("rawtypes") + public Class[] getAdapterList() { + return ADAPTERS; + } + + public Object getAdapter(Object adaptableObject, @SuppressWarnings("rawtypes") Class adapterType) { + if(adapterType == IReloadContextProvider.class) { + if(DiagramOutlineReloadContextProvider.isDiagramOutline(adaptableObject)) { + return new DiagramOutlineReloadContextProvider(adaptableObject); + } + } + return null; + } + +} diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/adapter/DiagramOutlineReloadContextProvider.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/adapter/DiagramOutlineReloadContextProvider.java new file mode 100644 index 00000000000..2e9d4f381c6 --- /dev/null +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/adapter/DiagramOutlineReloadContextProvider.java @@ -0,0 +1,135 @@ +/* + * 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.gmfdiag.common.adapter; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor; +import org.eclipse.jface.action.IAction; +import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider; +import org.eclipse.papyrus.infra.gmfdiag.common.Activator; + + +/** + * A {@linkplain IReloadContextProvider reload context provider} for nested diagram outline pages that records and restores the selection of + * which presentation mode (tree outline or thumbnail overview) is active for each outline page. This implementation uses reflection to access + * internals (non API) of the outline page. On any problem in initializing this reflective access, the adapter basically disables itself and + * never participates in editor re-load, so that the system continues normally but with reduced functionality. + */ +class DiagramOutlineReloadContextProvider implements IReloadContextProvider { + + private static final int ID_OUTLINE = 0; + + private static final int ID_OVERVIEW = 1; + + private static final Class<?> diagramOutlinePage; + + private static final Method showPage; + + private static final Field showOutlineAction; + + static { + Class<?> diagramOutlinePageClass = null; + Method showPageMethod = null; + Field showOutlineActionField = null; + + for(Class<?> next : DiagramEditor.class.getDeclaredClasses()) { + if("DiagramOutlinePage".equals(next.getSimpleName())) { //$NON-NLS-1$ + diagramOutlinePageClass = next; + + try { + showPageMethod = diagramOutlinePageClass.getDeclaredMethod("showPage", int.class); //$NON-NLS-1$ + showPageMethod.setAccessible(true); + + showOutlineActionField = diagramOutlinePageClass.getDeclaredField("showOutlineAction"); //$NON-NLS-1$ + showOutlineActionField.setAccessible(true); + } catch (Exception e) { + // Can't reflect? Then abandon all hope + Activator.log.error(e); + diagramOutlinePageClass = null; + } + + break; + } + } + + diagramOutlinePage = diagramOutlinePageClass; + showPage = showPageMethod; + showOutlineAction = showOutlineActionField; + } + + private final Object diagramOutline; + + public DiagramOutlineReloadContextProvider(Object diagramOutline) { + super(); + + this.diagramOutline = diagramOutline; + } + + @Override + public Object createReloadContext() { + return new ReloadContext(diagramOutline); + } + + @Override + public void restore(Object reloadContext) { + ((ReloadContext)reloadContext).restore(diagramOutline); + } + + static boolean isDiagramOutline(Object o) { + // If we couldn't reflect on DiagramOutline class, then we will never detect a diagram outline + // instance, so we will never try to create an adapter, and all is safe. The only consequence + // will be that we don't get diagram outline state properly restored. That's fine + return (diagramOutlinePage != null) && diagramOutlinePage.isInstance(o); + } + + // + // Nested types + // + + private static class ReloadContext { + + private final int pageID; + + public ReloadContext(Object diagramOutline) { + super(); + + try { + this.pageID = ((IAction)showOutlineAction.get(diagramOutline)).isChecked() ? ID_OUTLINE : ID_OVERVIEW; + } catch (IllegalAccessException e) { + // We wouldn't be here if we couldn't make it accessible. Something is very wrong + throw new Error(e); + } + } + + void restore(Object diagramOutline) { + try { + showPage.invoke(diagramOutline, pageID); + } catch (IllegalAccessException e) { + // We wouldn't be here if we couldn't make it accessible. Something is very wrong + throw new Error(e); + } catch (InvocationTargetException e) { + Throwable target = e.getTargetException(); + if(target instanceof RuntimeException) { + throw (RuntimeException)target; + } else if(target instanceof Error) { + throw (Error)target; + } else { + Activator.log.error(target); + } + } + } + } +} diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.outline/src/org/eclipse/papyrus/infra/gmfdiag/outline/DiagramOutline.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.outline/src/org/eclipse/papyrus/infra/gmfdiag/outline/DiagramOutline.java index a9b1798347c..dfe7cebb9b1 100644 --- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.outline/src/org/eclipse/papyrus/infra/gmfdiag/outline/DiagramOutline.java +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.outline/src/org/eclipse/papyrus/infra/gmfdiag/outline/DiagramOutline.java @@ -1,5 +1,5 @@ /***********************************************************************
- * Copyright (c) 2008, 2009 Anyware Technologies, Obeo, CEA LIST
+ * Copyright (c) 2008, 2014 Anyware Technologies, Obeo, 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
@@ -10,10 +10,13 @@ * Anyware Technologies - initial API and implementation
* Obeo
* CEA LIST - synchronization between selection and outline content
+ * Christian W. Damus (CEA) - bug 437217
*
**********************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.outline;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.GraphicalViewer;
@@ -31,6 +34,7 @@ import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.papyrus.infra.core.contentoutline.IPapyrusContentOutlinePage;
import org.eclipse.papyrus.infra.core.editor.BackboneException;
import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.gmfdiag.outline.internal.Activator;
import org.eclipse.papyrus.infra.gmfdiag.outline.internal.Messages;
@@ -56,7 +60,7 @@ import org.eclipse.ui.plugin.AbstractUIPlugin; */
//FIXME: The outline is broken in Eclipse 4.2. #createControl(Composite) is never called.
//See #refresh()
-public class DiagramOutline extends Page implements IPapyrusContentOutlinePage, ISelectionListener {
+public class DiagramOutline extends Page implements IPapyrusContentOutlinePage, ISelectionListener, IAdaptable {
private final class ShowAllAction extends Action {
@@ -451,4 +455,52 @@ public class DiagramOutline extends Page implements IPapyrusContentOutlinePage, return showActionMode;
}
+
+ private void setShowActionMode(int showAction) {
+ switch(showAction) {
+ case SHOW_TREE:
+ showTreeItem.getAction().setChecked(true);
+ break;
+ case SHOW_OVERVIEW:
+ showOverviewItem.getAction().setChecked(true);
+ break;
+ case SHOW_BOTH:
+ showAllItem.getAction().setChecked(true);
+ break;
+ default:
+ throw new IllegalArgumentException("showAction"); //$NON-NLS-1$
+ }
+
+ performShowAction();
+ }
+
+ public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
+ if(adapter == IReloadContextProvider.class) {
+ return new IReloadContextProvider() {
+
+ public Object createReloadContext() {
+ return new ReloadContext(DiagramOutline.this);
+ }
+
+ public void restore(Object reloadContext) {
+ ((ReloadContext)reloadContext).restore(DiagramOutline.this);
+ }
+ };
+ }
+
+ return Platform.getAdapterManager().getAdapter(this, adapter);
+ }
+
+ private static class ReloadContext {
+
+ private final int showAction;
+
+ ReloadContext(DiagramOutline outline) {
+ this.showAction = outline.getShowActionMode();
+ }
+
+ void restore(DiagramOutline outline) {
+ outline.setShowActionMode(showAction);
+ }
+ }
}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/META-INF/MANIFEST.MF b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/META-INF/MANIFEST.MF index f087767b49f..c47c1807a79 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/META-INF/MANIFEST.MF +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/META-INF/MANIFEST.MF @@ -22,7 +22,8 @@ Require-Bundle: org.eclipse.ui, org.eclipse.e4.core.contexts,
org.eclipse.core.expressions,
org.eclipse.emf.edit.ui,
- org.eclipse.papyrus.infra.viewpoints.policy;bundle-version="1.0.0"
+ org.eclipse.papyrus.infra.viewpoints.policy;bundle-version="1.0.0",
+ com.google.guava;bundle-version="11.0.0"
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
Bundle-Version: 1.0.0.qualifier
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/editor/AbstractEMFNattableEditor.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/editor/AbstractEMFNattableEditor.java index 21a651b8585..f3d56f24321 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/editor/AbstractEMFNattableEditor.java +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/editor/AbstractEMFNattableEditor.java @@ -11,6 +11,7 @@ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
* Vincent Lorenzo (CEA-LIST) vincent.lorenzo@cea.fr
* Christian W. Damus (CEA) - bug 430880
+ * Christian W. Damus (CEA) - bug 437217
*
*****************************************************************************/
package org.eclipse.papyrus.infra.nattable.common.editor;
@@ -30,6 +31,7 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
@@ -228,6 +230,10 @@ public abstract class AbstractEMFNattableEditor extends EditorPart { return this.tableManager.getTable();
}
}
+
+ if(adapter == IReloadContextProvider.class) {
+ return new NattableReloadContextProvider(this);
+ }
return super.getAdapter(adapter);
}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/editor/NattableReloadContextProvider.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/editor/NattableReloadContextProvider.java new file mode 100644 index 00000000000..a3123d9add2 --- /dev/null +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/editor/NattableReloadContextProvider.java @@ -0,0 +1,90 @@ +/* + * 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.nattable.common.editor; + +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.selection.command.SelectColumnCommand; +import org.eclipse.nebula.widgets.nattable.selection.command.SelectRowsCommand; +import org.eclipse.papyrus.infra.core.editor.reload.EMFSelectionContext; +import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider; +import org.eclipse.papyrus.infra.core.utils.AdapterUtils; +import org.eclipse.papyrus.infra.nattable.manager.table.INattableModelManager; + + +/** + * A {@linkplain IReloadContextProvider reload context provider} for {@link NatTable} selection state. + */ +class NattableReloadContextProvider implements IReloadContextProvider { + + private final AbstractEMFNattableEditor editor; + + NattableReloadContextProvider(AbstractEMFNattableEditor editor) { + super(); + + this.editor = editor; + } + + @Override + public Object createReloadContext() { + return new NatTableSelectionContext(getSelectionProvider(), getSelectionLayer()); + } + + @Override + public void restore(Object reloadContext) { + ((NatTableSelectionContext)reloadContext).restore(getSelectionProvider(), getSelectionLayer()); + } + + private ISelectionProvider getSelectionProvider() { + // The table editor registers its table-selection provider in its site + return editor.getSite().getSelectionProvider(); + } + + private SelectionLayer getSelectionLayer() { + INattableModelManager mgr = AdapterUtils.adapt(editor, INattableModelManager.class, null); + return mgr.getBodyLayerStack().getSelectionLayer(); + } + + // + // Nested types + // + + private static class NatTableSelectionContext extends EMFSelectionContext { + + private final int[] selectedRows; + + private final int[] selectedColumns; + + NatTableSelectionContext(ISelectionProvider structuredSelectionProvider, SelectionLayer selectionLayer) { + super(structuredSelectionProvider); + + selectedRows = selectionLayer.getFullySelectedRowPositions(); + selectedColumns = selectionLayer.getFullySelectedColumnPositions(); + } + + void restore(ISelectionProvider structuredSelectionProvider, SelectionLayer selectionLayer) { + selectionLayer.clear(); + if(selectedColumns.length > 0) { + for(int i = 0; i < selectedColumns.length; i++) { + selectionLayer.doCommand(new SelectColumnCommand(selectionLayer, selectedColumns[i], Integer.MAX_VALUE, false, true)); + } + } + if(selectedRows.length > 0) { + selectionLayer.doCommand(new SelectRowsCommand(selectionLayer, Integer.MAX_VALUE, selectedRows, false, true, selectedRows[selectedRows.length - 1])); + } + + restore(structuredSelectionProvider); + } + } +} diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/LocalMemento.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/LocalMemento.java new file mode 100644 index 00000000000..c456b15a49f --- /dev/null +++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/LocalMemento.java @@ -0,0 +1,284 @@ +/* + * 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.tools.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); + } + + @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.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java index 051bb4dba11..10d4ea7054f 100644 --- a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java +++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java @@ -27,6 +27,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IMemento; /** @@ -54,6 +55,16 @@ public class UIUtil { return new UIExecutorService(display); } + /** + * 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$ + } + // // Nested types // diff --git a/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerTreeViewerContext.java b/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerTreeViewerContext.java new file mode 100644 index 00000000000..e81398f494a --- /dev/null +++ b/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerTreeViewerContext.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2010, 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: + * CEA LIST - Initial API and implementation + * Christian W. Damus (CEA) - adapted from ModelExplorerView::reveal(...) API + * + */ +package org.eclipse.papyrus.views.modelexplorer; + +import java.util.ArrayList; +import java.util.Collection; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.jface.viewers.AbstractTreeViewer; +import org.eclipse.papyrus.infra.core.editor.reload.EMFTreeViewerContext; +import org.eclipse.papyrus.infra.core.resource.ModelSet; +import org.eclipse.papyrus.infra.core.resource.additional.AdditionalResourcesModel; +import org.eclipse.papyrus.infra.emf.utils.EMFHelper; +import org.eclipse.papyrus.views.modelexplorer.matching.IMatchingItem; +import org.eclipse.papyrus.views.modelexplorer.matching.LinkItemMatchingItem; +import org.eclipse.papyrus.views.modelexplorer.matching.ModelElementItemMatchingItem; +import org.eclipse.papyrus.views.modelexplorer.matching.ReferencableMatchingItem; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + + +/** + * A specialization of the editor re-load tree viewer context that knows how to expand and select nodes + * in the EMF Facet-based Model Explorer view. + */ +class ModelExplorerTreeViewerContext extends EMFTreeViewerContext { + + public ModelExplorerTreeViewerContext(AbstractTreeViewer viewer) { + super(viewer); + } + + public Object deresolveSelectableElement(Object selectableElement) { + return EMFHelper.getEObject(selectableElement); + } + + public Object resolveSelectableElement(Object object) { + return new ModelElementItemMatchingItemWithElement((EObject)object); + } + + @Override + protected void setExpandedElements(AbstractTreeViewer viewer, Collection<?> toExpand) { + // EMF Facet makes expanding tree elements very complicated + if(viewer.getContentProvider() != null) { + for(ModelElementItemMatchingItemWithElement next : Iterables.filter(toExpand, ModelElementItemMatchingItemWithElement.class)) { + + // retrieve the ancestors to reveal them + // and allow the selection of the object + EObject currentEObject = next.element(); + ArrayList<EObject> parents = new ArrayList<EObject>(); + EObject tmp = currentEObject.eContainer(); + while(tmp != null) { + parents.add(tmp); + tmp = tmp.eContainer(); + } + + Iterable<EObject> reverseParents = Lists.reverse(parents); + + // reveal the resource if necessary + Resource r = null; + if(!parents.isEmpty()) { + r = parents.get(parents.size() - 1).eResource(); + } else { + r = currentEObject.eResource(); + } + + if(r != null) { + final ResourceSet rs = r.getResourceSet(); + final Resource resource = r; + if(rs instanceof ModelSet && AdditionalResourcesModel.isAdditionalResource((ModelSet)rs, r.getURI())) { + viewer.expandToLevel(new ReferencableMatchingItem(rs), 1); + viewer.expandToLevel(new ReferencableMatchingItem(resource), 1); + } + } + + /* + * reveal the ancestors tree using expandToLevel on each of them + * in the good order. This is a lot faster than going through the whole tree + * using getChildren of the ContentProvider since our Viewer uses a Hashtable + * to keep track of the revealed elements. + * + * However we need to use a dedicated MatchingItem to do the matching, + * and a specific comparer in our viewer so than the equals of MatchingItem is + * used in priority. + * + * Please refer to MatchingItem for more infos. + */ + EObject previousParent = null; + for(EObject parent : reverseParents) { + if(parent.eContainingFeature() != null && previousParent != null) { + viewer.expandToLevel(new LinkItemMatchingItem(previousParent, parent.eContainmentFeature()), 1); + } + + final IMatchingItem itemToExpand = new ModelElementItemMatchingItem(parent); + viewer.expandToLevel(itemToExpand, 1); + + previousParent = parent; + } + + // expand a reference-link item, if necessary + final IMatchingItem linkItem = new LinkItemMatchingItem(currentEObject.eContainer(), currentEObject.eContainmentFeature()); + viewer.expandToLevel(linkItem, 1); + + // and the actual element + viewer.expandToLevel(next, 1); + } + } + } + + // + // Nested types + // + + static class ModelElementItemMatchingItemWithElement extends ModelElementItemMatchingItem { + + private EObject element; + + ModelElementItemMatchingItemWithElement(EObject element) { + super(element); + + this.element = element; + } + + EObject element() { + return element; + } + } +} diff --git a/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerView.java b/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerView.java index 7f2a6262cf1..b7f71045b88 100644 --- a/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerView.java +++ b/plugins/views/modelexplorer/org.eclipse.papyrus.views.modelexplorer/src/org/eclipse/papyrus/views/modelexplorer/ModelExplorerView.java @@ -12,6 +12,7 @@ * Christian W. Damus (CEA) - post refreshes for transaction commit asynchronously (CDO)
* Christian W. Damus (CEA) - bug 429826
* Christian W. Damus (CEA) - bug 434635
+ * Christian W. Damus (CEA) - bug 437217
*
*****************************************************************************/
package org.eclipse.papyrus.views.modelexplorer;
@@ -53,6 +54,10 @@ import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerColumn;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.editor.IReloadableEditor;
+import org.eclipse.papyrus.infra.core.editor.reload.EditorReloadAdapter;
+import org.eclipse.papyrus.infra.core.editor.reload.EditorReloadEvent;
+import org.eclipse.papyrus.infra.core.editor.reload.TreeViewerContext;
import org.eclipse.papyrus.infra.core.lifecycleevents.IEditorInputChangedListener;
import org.eclipse.papyrus.infra.core.lifecycleevents.ISaveAndDirtyService;
import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
@@ -127,7 +132,7 @@ import com.google.common.collect.Lists; public class ModelExplorerView extends CommonNavigator implements IRevealSemanticElement, IEditingDomainProvider, IPageLifeCycleEventsListener {
private SharedModelExplorerState sharedState;
-
+
private SharedModelExplorerState.StateChangedListener sharedStateListener;
/**
@@ -138,16 +143,10 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti public static final String LABEL_PROVIDER_SERVICE_CONTEXT = "org.eclipse.papyrus.views.modelexplorer.labelProvider.context";
/**
- * The associated EditorPart
- * The View is associated to the ServicesRegistry rather than to an editor.
- * */
- // private IMultiDiagramEditor editorPart;
-
- /**
* The {@link ServicesRegistry} associated to the Editor. This view is associated to the
* ServicesRegistry rather than to the EditorPart.
*/
- private final ServicesRegistry serviceRegistry;
+ private ServicesRegistry serviceRegistry;
/** The save aservice associated to the editor. */
private ISaveAndDirtyService saveAndDirtyService;
@@ -217,10 +216,37 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti throw new IllegalArgumentException("A part should be provided.");
}
+ init(part);
+
+ IReloadableEditor.Adapter.getAdapter(part).addEditorReloadListener(new EditorReloadAdapter() {
+
+ @Override
+ public void editorAboutToReload(EditorReloadEvent event) {
+ // Stash expansion and selection state of the common viewer
+ event.putContext(new ModelExplorerTreeViewerContext(getCommonViewer()));
+
+ deactivate();
+ }
+
+ @Override
+ public void editorReloaded(EditorReloadEvent event) {
+ init(event.getEditor());
+
+ activate();
+
+ initCommonViewer(getCommonViewer());
+
+ // Restore expansion and selection state of the common viewer
+ ((TreeViewerContext<?>)event.getContext()).restore(getCommonViewer());
+ }
+ });
+ }
+
+ private void init(IMultiDiagramEditor editor) {
// Try to get the ServicesRegistry
- serviceRegistry = part.getServicesRegistry();
+ serviceRegistry = editor.getServicesRegistry();
if(serviceRegistry == null) {
- throw new IllegalArgumentException("The part should have a ServiceRegistry.");
+ throw new IllegalArgumentException("The editor should have a ServiceRegistry.");
}
// Get required services from ServicesRegistry
@@ -228,7 +254,7 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti saveAndDirtyService = serviceRegistry.getService(ISaveAndDirtyService.class);
undoContext = serviceRegistry.getService(IUndoContext.class);
} catch (ServiceException e) {
- e.printStackTrace();
+ Activator.log.error(e);
}
}
@@ -341,6 +367,41 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti @Override
protected CommonViewer createCommonViewerObject(Composite aParent) {
CommonViewer viewer = new CustomCommonViewer(getViewSite().getId(), aParent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+
+ initCommonViewer(viewer);
+
+ viewer.getNavigatorContentService().getActivationService().addExtensionActivationListener(new IExtensionActivationListener() {
+
+ public void onExtensionActivation(String aViewerId, String[] theNavigatorExtensionIds, boolean isActive) {
+ sharedState.updateNavigatorContentExtensions(theNavigatorExtensionIds, isActive);
+ }
+ });
+
+ ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
+
+ return viewer;
+ }
+
+ private void installEMFFacetTreePainter(Tree tree) {
+ // Install the EMFFacet Custom Tree Painter
+ //org.eclipse.papyrus.infra.emf.Activator.getDefault().getCustomizationManager().installCustomPainter(tree);
+
+ // The EMF Facet MeasureItem Listener is incompatible with the NavigatorDecoratingLabelProvider. Remove it.
+ // Symptoms: ModelElementItems with an EMF Facet Overlay have a small selection size
+ // Removal also fixes bug 400012: no scrollbar although tree is larger than visible area
+ Collection<Listener> listenersToRemove = new LinkedList<Listener>();
+ for(Listener listener : tree.getListeners(SWT.MeasureItem)) {
+ if(listener.getClass().getName().contains("org.eclipse.papyrus.emf.facet.infra.browser.uicore.internal.CustomTreePainter")) {
+ listenersToRemove.add(listener);
+ }
+ }
+
+ for(Listener listener : listenersToRemove) {
+ tree.removeListener(SWT.MeasureItem, listener);
+ }
+ }
+
+ private void initCommonViewer(CommonViewer viewer) {
// enable tool-tips
// workaround for bug 311827: the Common Viewer always uses NavigatorDecoratingLabelProvider
// as a wrapper for the LabelProvider provided by the application. The NavigatorDecoratingLabelProvider
@@ -375,36 +436,6 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti }
}
contentService.dispose(); // No longer need this
-
- viewer.getNavigatorContentService().getActivationService().addExtensionActivationListener(new IExtensionActivationListener() {
-
- public void onExtensionActivation(String aViewerId, String[] theNavigatorExtensionIds, boolean isActive) {
- sharedState.updateNavigatorContentExtensions(theNavigatorExtensionIds, isActive);
- }
- });
-
- ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
-
- return viewer;
- }
-
- private void installEMFFacetTreePainter(Tree tree) {
- // Install the EMFFacet Custom Tree Painter
- //org.eclipse.papyrus.infra.emf.Activator.getDefault().getCustomizationManager().installCustomPainter(tree);
-
- // The EMF Facet MeasureItem Listener is incompatible with the NavigatorDecoratingLabelProvider. Remove it.
- // Symptoms: ModelElementItems with an EMF Facet Overlay have a small selection size
- // Removal also fixes bug 400012: no scrollbar although tree is larger than visible area
- Collection<Listener> listenersToRemove = new LinkedList<Listener>();
- for(Listener listener : tree.getListeners(SWT.MeasureItem)) {
- if(listener.getClass().getName().contains("org.eclipse.papyrus.emf.facet.infra.browser.uicore.internal.CustomTreePainter")) {
- listenersToRemove.add(listener);
- }
- }
-
- for(Listener listener : listenersToRemove) {
- tree.removeListener(SWT.MeasureItem, listener);
- }
}
@Override
@@ -625,6 +656,19 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti super.init(site, aMemento);
activate();
+
+ // Self-listen for property changes
+ addPropertyListener(new IPropertyListener() {
+
+ public void propertyChanged(Object source, int propId) {
+ switch(propId) {
+ case IS_LINKING_ENABLED_PROPERTY:
+ // Propagate to other instances
+ sharedState.setLinkingEnabled(isLinkingEnabled());
+ break;
+ }
+ }
+ });
}
/**
@@ -753,8 +797,6 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti * Activate specified Part.
*/
private void activate() {
-
-
try {
this.editingDomain = ServiceUtils.getInstance().getTransactionalEditingDomain(serviceRegistry);
@@ -777,19 +819,6 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti if(this.getCommonViewer() != null) {
syncRefresh();
}
-
- // Self-listen for property changes
- addPropertyListener(new IPropertyListener() {
-
- public void propertyChanged(Object source, int propId) {
- switch(propId) {
- case IS_LINKING_ENABLED_PROPERTY:
- // Propagate to other instances
- sharedState.setLinkingEnabled(isLinkingEnabled());
- break;
- }
- }
- });
}
/**
@@ -801,6 +830,15 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti Activator.log.debug("deactivate ModelExplorerView"); //$NON-NLS-1$
}
+ try {
+ ISashWindowsContainer sashWindowsContainer = serviceRegistry.getService(ISashWindowsContainer.class);
+ if(sashWindowsContainer != null) {
+ sashWindowsContainer.removePageLifeCycleListener(this);
+ }
+ } catch (ServiceException ex) {
+ //Ignore
+ }
+
// Stop listening on change events
getSite().getPage().removeSelectionListener(pageSelectionListener);
// Stop Listening to isDirty flag
@@ -811,6 +849,11 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti editingDomain = null;
}
+ saveAndDirtyService = null;
+ undoContext = null;
+ editingDomain = null;
+ editingDomain = null;
+ lastTrans = null;
}
/**
@@ -828,31 +871,19 @@ public class ModelExplorerView extends CommonNavigator implements IRevealSemanti sharedState.removeListener(sharedStateListener);
}
- try {
- ISashWindowsContainer sashWindowsContainer = serviceRegistry.getService(ISashWindowsContainer.class);
- if(sashWindowsContainer != null) {
- sashWindowsContainer.removePageLifeCycleListener(this);
- }
- } catch (ServiceException ex) {
- //Ignore
+ if(getSite() != null) {
+ getSite().getPage().removeSelectionListener(pageSelectionListener);
}
deactivate();
- saveAndDirtyService = null;
- undoContext = null;
- editingDomain = null;
- pageSelectionListener = null;
- editingDomain = null;
- lastTrans = null;
-
for(IPropertySheetPage propertySheetPage : this.propertySheetPages) {
propertySheetPage.dispose();
}
propertySheetPages.clear();
-
+ pageSelectionListener = null;
super.dispose();
diff --git a/plugins/views/validation/org.eclipse.papyrus.views.validation/src/org/eclipse/papyrus/views/validation/internal/providers/ProblemsContentProvider.java b/plugins/views/validation/org.eclipse.papyrus.views.validation/src/org/eclipse/papyrus/views/validation/internal/providers/ProblemsContentProvider.java index 23b5f5c347c..c47c5d83a33 100644 --- a/plugins/views/validation/org.eclipse.papyrus.views.validation/src/org/eclipse/papyrus/views/validation/internal/providers/ProblemsContentProvider.java +++ b/plugins/views/validation/org.eclipse.papyrus.views.validation/src/org/eclipse/papyrus/views/validation/internal/providers/ProblemsContentProvider.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2013 CEA LIST. + * 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 @@ -8,6 +8,8 @@ * * Contributors: * CEA LIST - Initial API and implementation + * Christian W. Damus (CEA) - bug 437217 + * *****************************************************************************/ package org.eclipse.papyrus.views.validation.internal.providers; @@ -31,8 +33,7 @@ import com.google.common.collect.Iterables; /** * This is the ProblemsContentProvider type. Enjoy. */ -public class ProblemsContentProvider - implements IStructuredContentProvider { +public class ProblemsContentProvider implements IStructuredContentProvider { private static final Object[] NONE = {}; @@ -53,31 +54,30 @@ public class ProblemsContentProvider } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - this.viewer = (AbstractTableViewer) viewer; + this.viewer = (AbstractTableViewer)viewer; - if (oldInput instanceof ValidationMarkersService) { - ValidationMarkersService service = (ValidationMarkersService) oldInput; + if(oldInput instanceof ValidationMarkersService) { + ValidationMarkersService service = (ValidationMarkersService)oldInput; unhookMarkers(service); - unhookResourceSet(service.getModelSet() - .getTransactionalEditingDomain()); + + // The old service may have been disposed if its editor was closed + if(service.getModelSet() != null) { + unhookResourceSet(service.getModelSet().getTransactionalEditingDomain()); + } + this.service = null; } - if (newInput instanceof ValidationMarkersService) { - ValidationMarkersService service = (ValidationMarkersService) newInput; + if(newInput instanceof ValidationMarkersService) { + ValidationMarkersService service = (ValidationMarkersService)newInput; this.service = service; hookMarkers(service); - hookResourceSet(service.getModelSet() - .getTransactionalEditingDomain()); + hookResourceSet(service.getModelSet().getTransactionalEditingDomain()); } } public Object[] getElements(Object inputElement) { - return (inputElement instanceof ValidationMarkersService) - ? Iterables.toArray( - ((ValidationMarkersService) inputElement).getMarkers(), - IPapyrusMarker.class) - : NONE; + return (inputElement instanceof ValidationMarkersService) ? Iterables.toArray(((ValidationMarkersService)inputElement).getMarkers(), IPapyrusMarker.class) : NONE; } protected void hookMarkers(ValidationMarkersService service) { @@ -89,19 +89,18 @@ public class ProblemsContentProvider } private IValidationMarkerListener getValidationMarkerListener() { - if (listener == null) { + if(listener == null) { listener = new IValidationMarkerListener() { - public void notifyMarkerChange(IPapyrusMarker marker, - MarkerChangeKind kind) { - if (viewer != null) { - switch (kind) { - case ADDED : - viewer.add(marker); - break; - case REMOVED : - viewer.remove(marker); - break; + public void notifyMarkerChange(IPapyrusMarker marker, MarkerChangeKind kind) { + if(viewer != null) { + switch(kind) { + case ADDED: + viewer.add(marker); + break; + case REMOVED: + viewer.remove(marker); + break; } } } @@ -120,42 +119,36 @@ public class ProblemsContentProvider } private ResourceSetListener getResourceSetListener() { - if (resourceSetListener == null) { + if(resourceSetListener == null) { resourceSetListener = new DemultiplexingListener() { @Override - protected void handleNotification( - TransactionalEditingDomain domain, - Notification notification) { + protected void handleNotification(TransactionalEditingDomain domain, Notification notification) { // handle containment changes of problem elements to update // labels Object feature = notification.getFeature(); - if ((feature instanceof EReference) - && ((EReference) feature).isContainment()) { - - switch (notification.getEventType()) { - case Notification.ADD : - handleContainment((EObject) notification - .getNewValue()); - break; - case Notification.ADD_MANY : - for (Object next : (Collection<?>) notification - .getNewValue()) { - handleContainment((EObject) next); - } - break; - case Notification.SET : - handleContainment((EObject) notification - .getNewValue()); - break; + if((feature instanceof EReference) && ((EReference)feature).isContainment()) { + + switch(notification.getEventType()) { + case Notification.ADD: + handleContainment((EObject)notification.getNewValue()); + break; + case Notification.ADD_MANY: + for(Object next : (Collection<?>)notification.getNewValue()) { + handleContainment((EObject)next); + } + break; + case Notification.SET: + handleContainment((EObject)notification.getNewValue()); + break; } } } private void handleContainment(EObject object) { Object[] markers = service.getMarkers(object).toArray(); - if (markers.length > 0) { + if(markers.length > 0) { viewer.update(markers, null); } } diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/META-INF/MANIFEST.MF b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/META-INF/MANIFEST.MF index 8da92919d49..3f6472f23ea 100644 --- a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/META-INF/MANIFEST.MF +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/META-INF/MANIFEST.MF @@ -29,7 +29,8 @@ Require-Bundle: org.eclipse.ui, org.eclipse.papyrus.infra.nattable.common;bundle-version="1.0.0",
org.eclipse.papyrus.infra.nattable;bundle-version="1.0.0",
org.eclipse.papyrus.uml.nattable.menu;bundle-version="1.0.0",
- org.eclipse.papyrus.uml.diagram.sequence;bundle-version="1.0.0"
+ org.eclipse.papyrus.uml.diagram.sequence;bundle-version="1.0.0",
+ org.eclipse.papyrus.infra.emf;bundle-version="1.0.0"
Export-Package: org.eclipse.papyrus.editor.integration.tests,
org.eclipse.papyrus.editor.integration.tests.tests
Bundle-Vendor: Eclipse Modeling Project
diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.di b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.di new file mode 100644 index 00000000000..db3312a6d7a --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.di @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<di:SashWindowsMngr xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.eclipse.org/papyrus/0.7.0/sashdi"> + <sashModel currentSelection="//@sashModel/@windows.0/@children.0"> + <windows> + <children xsi:type="di:TabFolder"> + <children> + <emfPageIdentifier href="banking.notation#_z6rXcPlAEeOEp7Wro2yWpw"/> + </children> + </children> + </windows> + </sashModel> +</di:SashWindowsMngr> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.notation b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.notation new file mode 100644 index 00000000000..7a00061ce0e --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.notation @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<notation:Diagram xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.2/notation" xmlns:style="http://www.eclipse.org/papyrus/infra/viewpoints/policy/style" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_z6rXcPlAEeOEp7Wro2yWpw" type="PapyrusUMLClassDiagram" name="classes" measurementUnit="Pixel"> + <children xmi:type="notation:Shape" xmi:id="_5wKkIPlAEeOEp7Wro2yWpw" type="2008"> + <children xmi:type="notation:DecorationNode" xmi:id="_5wKkIvlAEeOEp7Wro2yWpw" type="5029"/> + <children xmi:type="notation:BasicCompartment" xmi:id="_5wKkI_lAEeOEp7Wro2yWpw" type="7017"> + <children xmi:type="notation:Shape" xmi:id="_CClGQPlBEeOEp7Wro2yWpw" type="3012"> + <element xmi:type="uml:Property" href="banking.uml#_CCiC8PlBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_CClGQflBEeOEp7Wro2yWpw"/> + </children> + <styles xmi:type="notation:TitleStyle" xmi:id="_5wKkJPlAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_5wKkJflAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_5wKkJvlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_5wKkJ_lAEeOEp7Wro2yWpw"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_5wKkKPlAEeOEp7Wro2yWpw" type="7018"> + <styles xmi:type="notation:TitleStyle" xmi:id="_5wKkKflAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_5wKkKvlAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_5wKkK_lAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_5wKkLPlAEeOEp7Wro2yWpw"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_5wKkLflAEeOEp7Wro2yWpw" type="7019"> + <styles xmi:type="notation:TitleStyle" xmi:id="_5wKkLvlAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_5wKkL_lAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_5wLLMPlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_5wLLMflAEeOEp7Wro2yWpw"/> + </children> + <element xmi:type="uml:Class" href="banking.uml#_5wJWAPlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_5wKkIflAEeOEp7Wro2yWpw" x="44" y="65"/> + </children> + <children xmi:type="notation:Shape" xmi:id="_YViK8PlBEeOEp7Wro2yWpw" type="2008"> + <children xmi:type="notation:DecorationNode" xmi:id="_YViK8vlBEeOEp7Wro2yWpw" type="5029"/> + <children xmi:type="notation:BasicCompartment" xmi:id="_YViK8_lBEeOEp7Wro2yWpw" type="7017"> + <children xmi:type="notation:Shape" xmi:id="_amgIAPlBEeOEp7Wro2yWpw" type="3012"> + <element xmi:type="uml:Property" href="banking.uml#_amdrwPlBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_amgIAflBEeOEp7Wro2yWpw"/> + </children> + <children xmi:type="notation:Shape" xmi:id="_cxbHcPlBEeOEp7Wro2yWpw" type="3012"> + <element xmi:type="uml:Property" href="banking.uml#_cxZ5UPlBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_cxbHcflBEeOEp7Wro2yWpw"/> + </children> + <styles xmi:type="notation:TitleStyle" xmi:id="_YViK9PlBEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_YViK9flBEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_YViK9vlBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_YViK9_lBEeOEp7Wro2yWpw"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_YViK-PlBEeOEp7Wro2yWpw" type="7018"> + <styles xmi:type="notation:TitleStyle" xmi:id="_YViK-flBEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_YViK-vlBEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_YViK-_lBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_YViK_PlBEeOEp7Wro2yWpw"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_YViyAPlBEeOEp7Wro2yWpw" type="7019"> + <styles xmi:type="notation:TitleStyle" xmi:id="_YViyAflBEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_YViyAvlBEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_YViyA_lBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_YViyBPlBEeOEp7Wro2yWpw"/> + </children> + <element xmi:type="uml:Class" href="banking.uml#_YVg80PlBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_YViK8flBEeOEp7Wro2yWpw" x="305" y="61"/> + </children> + <styles xmi:type="notation:StringValueStyle" xmi:id="_z6rXcflAEeOEp7Wro2yWpw" name="diagram_compatibility_version" stringValue="1.0.0"/> + <styles xmi:type="notation:DiagramStyle" xmi:id="_z6rXcvlAEeOEp7Wro2yWpw"/> + <styles xmi:type="style:PapyrusViewStyle" xmi:id="_z6rXc_lAEeOEp7Wro2yWpw"> + <owner xmi:type="uml:Model" href="banking.uml#_vtQUwPlAEeOEp7Wro2yWpw"/> + </styles> + <element xmi:type="uml:Model" href="banking.uml#_vtQUwPlAEeOEp7Wro2yWpw"/> + <edges xmi:type="notation:Connector" xmi:id="_kGAvYPlBEeOEp7Wro2yWpw" type="4001" source="_5wKkIPlAEeOEp7Wro2yWpw" target="_YViK8PlBEeOEp7Wro2yWpw"> + <children xmi:type="notation:DecorationNode" xmi:id="_kGBWcPlBEeOEp7Wro2yWpw" type="6001"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_kGBWcflBEeOEp7Wro2yWpw" y="-20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_kGBWcvlBEeOEp7Wro2yWpw" visible="false" type="6002"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_kGBWc_lBEeOEp7Wro2yWpw" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_kGBWdPlBEeOEp7Wro2yWpw" type="6003"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_kGBWdflBEeOEp7Wro2yWpw" x="10" y="-20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_kGB9gPlBEeOEp7Wro2yWpw" type="6005"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_kGB9gflBEeOEp7Wro2yWpw" x="-11" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_kGB9gvlBEeOEp7Wro2yWpw" type="6033"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_kGB9g_lBEeOEp7Wro2yWpw" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_kGB9hPlBEeOEp7Wro2yWpw" type="6034"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_kGB9hflBEeOEp7Wro2yWpw" y="-20"/> + </children> + <styles xmi:type="notation:FontStyle" xmi:id="_kGAvYflBEeOEp7Wro2yWpw"/> + <element xmi:type="uml:Association" href="banking.uml#_kF-6MPlBEeOEp7Wro2yWpw"/> + <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_kGAvYvlBEeOEp7Wro2yWpw" points="[50, -8, -186, 0]$[211, -17, -25, -9]"/> + <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_kGOKwPlBEeOEp7Wro2yWpw" id="(0.22522522522522523,0.4107142857142857)"/> + </edges> +</notation:Diagram> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.uml b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.uml new file mode 100644 index 00000000000..ed2c9d13f1b --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/banking.uml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xmi:XMI xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ActionLanguage="http://www.omg.org/spec/ALF/20120827/ActionLanguage-Profile" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xsi:schemaLocation="http://www.omg.org/spec/ALF/20120827/ActionLanguage-Profile pathmap://PAPYRUS_ACTIONLANGUAGE_PROFILE/ActionLanguage-Profile.profile.uml#_sYse0YZLEeKyw49uR6nx3g"> + <uml:Model xmi:id="_vtQUwPlAEeOEp7Wro2yWpw" name="banking"> + <packageImport xmi:type="uml:PackageImport" xmi:id="_vtQUwflAEeOEp7Wro2yWpw"> + <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/> + </packageImport> + <packagedElement xmi:type="uml:Class" xmi:id="_5wJWAPlAEeOEp7Wro2yWpw" name="Account"> + <ownedAttribute xmi:type="uml:Property" xmi:id="_CCiC8PlBEeOEp7Wro2yWpw" name="id" visibility="public" isUnique="false"> + <type xmi:type="uml:PrimitiveType" href="library.uml#_9VhhQPlAEeOEp7Wro2yWpw"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_X0ky8PlBEeOEp7Wro2yWpw" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_X0laAPlBEeOEp7Wro2yWpw" value="1"/> + </ownedAttribute> + <ownedAttribute xmi:type="uml:Property" xmi:id="_kF-TIPlBEeOEp7Wro2yWpw" name="signatory" type="_YVg80PlBEeOEp7Wro2yWpw" association="_kF-6MPlBEeOEp7Wro2yWpw"> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_kF-TIflBEeOEp7Wro2yWpw"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_kF-TIvlBEeOEp7Wro2yWpw" value="*"/> + </ownedAttribute> + </packagedElement> + <packagedElement xmi:type="uml:Class" xmi:id="_YVg80PlBEeOEp7Wro2yWpw" name="Person"> + <ownedAttribute xmi:type="uml:Property" xmi:id="_amdrwPlBEeOEp7Wro2yWpw" name="ssn" visibility="public" isUnique="false"> + <type xmi:type="uml:DataType" href="library.uml#_AtaNAPJEEeOWJr1T78jdJA"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_cTywQPlBEeOEp7Wro2yWpw" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_cUEdEPlBEeOEp7Wro2yWpw" value="1"/> + </ownedAttribute> + <ownedAttribute xmi:type="uml:Property" xmi:id="_cxZ5UPlBEeOEp7Wro2yWpw" name="name" visibility="public" isUnique="false"> + <type xmi:type="uml:DataType" href="library.uml#_vCcKoPJEEeOWJr1T78jdJA"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_jHClsPlBEeOEp7Wro2yWpw" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_jHLIkPlBEeOEp7Wro2yWpw" value="1"/> + </ownedAttribute> + </packagedElement> + <packagedElement xmi:type="uml:Association" xmi:id="_kF-6MPlBEeOEp7Wro2yWpw" name="A_account_person_1" memberEnd="_kF-6MflBEeOEp7Wro2yWpw _kF-TIPlBEeOEp7Wro2yWpw" navigableOwnedEnd="_kF-6MflBEeOEp7Wro2yWpw"> + <ownedEnd xmi:type="uml:Property" xmi:id="_kF-6MflBEeOEp7Wro2yWpw" name="account" type="_5wJWAPlAEeOEp7Wro2yWpw" association="_kF-6MPlBEeOEp7Wro2yWpw"> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_kF-6MvlBEeOEp7Wro2yWpw"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_kF-6M_lBEeOEp7Wro2yWpw" value="*"/> + </ownedEnd> + </packagedElement> + <profileApplication xmi:type="uml:ProfileApplication" xmi:id="_FFYv8PlBEeOEp7Wro2yWpw"> + <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_FGT9APlBEeOEp7Wro2yWpw" source="http://www.eclipse.org/uml2/2.0.0/UML"> + <references xmi:type="ecore:EPackage" href="pathmap://PAPYRUS_ACTIONLANGUAGE_PROFILE/ActionLanguage-Profile.profile.uml#_sYse0YZLEeKyw49uR6nx3g"/> + </eAnnotations> + <appliedProfile xmi:type="uml:Profile" href="pathmap://PAPYRUS_ACTIONLANGUAGE_PROFILE/ActionLanguage-Profile.profile.uml#ActionLanguage"/> + </profileApplication> + </uml:Model> + <ActionLanguage:TextualRepresentation xmi:id="_FJGyUPlBEeOEp7Wro2yWpw" language="org.eclipse.papyrus.uml.textedit.property.xtext.UmlProperty"/> + <ActionLanguage:TextualRepresentation xmi:id="_QzhLAPlBEeOEp7Wro2yWpw" language="org.eclipse.papyrus.uml.textedit.property.xtext.UmlProperty"/> + <ActionLanguage:TextualRepresentation xmi:id="_fuKlYPlBEeOEp7Wro2yWpw" language="org.eclipse.papyrus.uml.textedit.property.xtext.UmlProperty"/> +</xmi:XMI> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.di b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.di new file mode 100644 index 00000000000..d94f1fa4ed4 --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.di @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<di:SashWindowsMngr xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.eclipse.org/papyrus/0.7.0/sashdi"> + <sashModel currentSelection="//@sashModel/@windows.0/@children.0"> + <windows> + <children xsi:type="di:TabFolder"> + <children> + <emfPageIdentifier href="employment.notation#_6l9toPJDEeOWJr1T78jdJA"/> + </children> + <children> + <emfPageIdentifier href="employment.notation#_4hrxoPJXEeOWJr1T78jdJA"/> + </children> + <children> + <emfPageIdentifier href="employment.notation#_HvMBoPrfEeOjArr2x5XJOA"/> + </children> + </children> + </windows> + </sashModel> +</di:SashWindowsMngr> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.notation b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.notation new file mode 100644 index 00000000000..ed846af8855 --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.notation @@ -0,0 +1,415 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:configuration="http://www.eclipse.org/papyrus/infra/viewpoints/configuration" xmlns:css="http://www.eclipse.org/papyrus/infra/gmfdiag/css" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:nattable="http://www.eclipse.org/papyrus/nattable/model" xmlns:nattableaxis="http://www.eclipse.org/papyrus/nattable/model/table/nattableaxis" xmlns:nattableaxisconfiguration="http://www.eclipse.org/papyrus/nattable/model/table/nattableaxisconfiguration" xmlns:nattableaxisprovider="http://www.eclipse.org/papyrus/nattable/model/table/nattableaxisprovider" xmlns:nattableconfiguration="http://www.eclipse.org/papyrus/nattable/model/nattableconfiguration" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.2/notation" xmlns:style="http://www.eclipse.org/papyrus/infra/viewpoints/policy/style" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xsi:schemaLocation="http://www.eclipse.org/papyrus/nattable/model/table/nattableaxis http://www.eclipse.org/papyrus/nattable/model#//nattableaxis http://www.eclipse.org/papyrus/nattable/model/table/nattableaxisconfiguration http://www.eclipse.org/papyrus/nattable/model#//nattableaxisconfiguration http://www.eclipse.org/papyrus/nattable/model/table/nattableaxisprovider http://www.eclipse.org/papyrus/nattable/model#//nattableaxisprovider http://www.eclipse.org/papyrus/nattable/model/nattableconfiguration http://www.eclipse.org/papyrus/nattable/model#//nattableconfiguration"> + <notation:Diagram xmi:id="_6l9toPJDEeOWJr1T78jdJA" type="PapyrusUMLClassDiagram" name="classes" measurementUnit="Pixel"> + <children xmi:type="notation:Shape" xmi:id="_YCT24PJEEeOWJr1T78jdJA" type="2008"> + <children xmi:type="notation:DecorationNode" xmi:id="_YCT24vJEEeOWJr1T78jdJA" type="5029"/> + <children xmi:type="notation:BasicCompartment" xmi:id="_YCUd8PJEEeOWJr1T78jdJA" type="7017"> + <children xmi:type="notation:Shape" xmi:id="_mLpwIPJEEeOWJr1T78jdJA" type="3012"> + <element xmi:type="uml:Property" href="employment.uml#_mLn68PJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_mLpwIfJEEeOWJr1T78jdJA"/> + </children> + <children xmi:type="notation:Shape" xmi:id="_SDVpkPlAEeOEp7Wro2yWpw" type="3012"> + <element xmi:type="uml:Property" href="employment.uml#_SDT0YPlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_SDVpkflAEeOEp7Wro2yWpw"/> + </children> + <styles xmi:type="notation:TitleStyle" xmi:id="_YCUd8fJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_YCUd8vJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_YCUd8_JEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_YCUd9PJEEeOWJr1T78jdJA"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_YCUd9fJEEeOWJr1T78jdJA" type="7018"> + <styles xmi:type="notation:TitleStyle" xmi:id="_YCUd9vJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_YCUd9_JEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_YCUd-PJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_YCUd-fJEEeOWJr1T78jdJA"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_YCUd-vJEEeOWJr1T78jdJA" type="7019"> + <styles xmi:type="notation:TitleStyle" xmi:id="_YCUd-_JEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_YCUd_PJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_YCUd_fJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_YCUd_vJEEeOWJr1T78jdJA"/> + </children> + <element xmi:type="uml:Class" href="employment.uml#_YCTP0PJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_YCT24fJEEeOWJr1T78jdJA" x="348" y="71"/> + </children> + <children xmi:type="notation:Shape" xmi:id="__LIHkPMXEeOa2u9_4wMSZA" type="2008"> + <children xmi:type="notation:DecorationNode" xmi:id="__LJVsPMXEeOa2u9_4wMSZA" type="5029"/> + <children xmi:type="notation:BasicCompartment" xmi:id="__LJVsfMXEeOa2u9_4wMSZA" type="7017"> + <children xmi:type="notation:Shape" xmi:id="_M4Z1wPlAEeOEp7Wro2yWpw" type="3012"> + <element xmi:type="uml:Property" href="employment.uml#_M1fEoPlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_M4Z1wflAEeOEp7Wro2yWpw"/> + </children> + <styles xmi:type="notation:TitleStyle" xmi:id="__LJVsvMXEeOa2u9_4wMSZA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="__LJVs_MXEeOa2u9_4wMSZA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="__LJVtPMXEeOa2u9_4wMSZA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="__LJVtfMXEeOa2u9_4wMSZA"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="__LJVtvMXEeOa2u9_4wMSZA" type="7018"> + <styles xmi:type="notation:TitleStyle" xmi:id="__LJVt_MXEeOa2u9_4wMSZA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="__LJVuPMXEeOa2u9_4wMSZA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="__LJVufMXEeOa2u9_4wMSZA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="__LJVuvMXEeOa2u9_4wMSZA"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="__LJ8wPMXEeOa2u9_4wMSZA" type="7019"> + <styles xmi:type="notation:TitleStyle" xmi:id="__LJ8wfMXEeOa2u9_4wMSZA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="__LJ8wvMXEeOa2u9_4wMSZA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="__LJ8w_MXEeOa2u9_4wMSZA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="__LJ8xPMXEeOa2u9_4wMSZA"/> + </children> + <element xmi:type="uml:Class" href="employment.uml#__JZpQPMXEeOa2u9_4wMSZA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="__LIHkfMXEeOa2u9_4wMSZA" x="50" y="70"/> + </children> + <styles xmi:type="notation:StringValueStyle" xmi:id="_6l9tofJDEeOWJr1T78jdJA" name="diagram_compatibility_version" stringValue="1.0.0"/> + <styles xmi:type="notation:DiagramStyle" xmi:id="_6l9tovJDEeOWJr1T78jdJA"/> + <styles xmi:type="style:PapyrusViewStyle" xmi:id="_6l9to_JDEeOWJr1T78jdJA"> + <owner xmi:type="uml:Model" href="employment.uml#_6iAasPJDEeOWJr1T78jdJA"/> + </styles> + <element xmi:type="uml:Model" href="employment.uml#_6iAasPJDEeOWJr1T78jdJA"/> + <edges xmi:type="notation:Connector" xmi:id="_AsPVAPMYEeOa2u9_4wMSZA" type="4001" source="__LIHkPMXEeOa2u9_4wMSZA" target="_YCT24PJEEeOWJr1T78jdJA"> + <children xmi:type="notation:DecorationNode" xmi:id="_AsP8EPMYEeOa2u9_4wMSZA" type="6001"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_AsP8EfMYEeOa2u9_4wMSZA" y="-20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_AsP8EvMYEeOa2u9_4wMSZA" visible="false" type="6002"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_AsQjIPMYEeOa2u9_4wMSZA" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_AsQjIfMYEeOa2u9_4wMSZA" type="6003"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_AsQjIvMYEeOa2u9_4wMSZA" x="7" y="-15"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_AsRKMPMYEeOa2u9_4wMSZA" type="6005"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_AsRKMfMYEeOa2u9_4wMSZA" x="-7" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_AsRKMvMYEeOa2u9_4wMSZA" type="6033"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_AsRKM_MYEeOa2u9_4wMSZA" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_AsRxQPMYEeOa2u9_4wMSZA" type="6034"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_AsRxQfMYEeOa2u9_4wMSZA" y="-20"/> + </children> + <styles xmi:type="notation:FontStyle" xmi:id="_AsPVAfMYEeOa2u9_4wMSZA"/> + <element xmi:type="uml:Association" href="employment.uml#_AsIAQPMYEeOa2u9_4wMSZA"/> + <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_AsPVAvMYEeOa2u9_4wMSZA" points="[0, 0, -188, -63]$[188, 63, 0, 0]"/> + <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_fYcuMPMZEeOa2u9_4wMSZA" id="(1.0,0.22)"/> + <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_fYdVQPMZEeOa2u9_4wMSZA" id="(0.0,0.1875)"/> + </edges> + </notation:Diagram> + <notation:Diagram xmi:id="_4hrxoPJXEeOWJr1T78jdJA" type="PapyrusUMLActivityDiagram" name="ActivityDiagram" measurementUnit="Pixel"> + <children xmi:type="notation:Shape" xmi:id="_4hrxofJXEeOWJr1T78jdJA" type="2001"> + <children xmi:type="notation:DecorationNode" xmi:id="_4hrxovJXEeOWJr1T78jdJA" type="5001"/> + <children xmi:type="notation:DecorationNode" xmi:id="_4hrxpPJXEeOWJr1T78jdJA" type="7001"> + <styles xmi:type="notation:SortingStyle" xmi:id="_4hrxpfJXEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_4hrxpvJXEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_4hrxp_JXEeOWJr1T78jdJA"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_4hrxqPJXEeOWJr1T78jdJA" type="7002"> + <styles xmi:type="notation:SortingStyle" xmi:id="_4hrxqfJXEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_4hrxqvJXEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_4hrxq_JXEeOWJr1T78jdJA"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_4hrxrPJXEeOWJr1T78jdJA" type="7003"> + <styles xmi:type="notation:SortingStyle" xmi:id="_4hrxrfJXEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_4hrxrvJXEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_4hrxr_JXEeOWJr1T78jdJA"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_4hrxsPJXEeOWJr1T78jdJA" type="7004"> + <children xmi:type="notation:Shape" xmi:id="_6IPfwPJXEeOWJr1T78jdJA" type="3071"> + <children xmi:type="notation:DecorationNode" xmi:id="_6IPfw_JXEeOWJr1T78jdJA" type="5121"/> + <children xmi:type="notation:DecorationNode" xmi:id="_6IQG0PJXEeOWJr1T78jdJA" type="7010"> + <children xmi:type="notation:Shape" xmi:id="_DuvQoPlCEeOEp7Wro2yWpw" type="3007"> + <children xmi:type="notation:DecorationNode" xmi:id="_DuvQo_lCEeOEp7Wro2yWpw" type="5003"/> + <styles xmi:type="notation:HintedDiagramLinkStyle" xmi:id="_DuvQoflCEeOEp7Wro2yWpw"/> + <element xmi:type="uml:OpaqueAction" href="employment.uml#_DupxEPlCEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_DuvQovlCEeOEp7Wro2yWpw" x="19" y="24" width="55" height="30"/> + </children> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_6IQG0fJXEeOWJr1T78jdJA"/> + </children> + <styles xmi:type="notation:HintedDiagramLinkStyle" xmi:id="_6IPfwfJXEeOWJr1T78jdJA"/> + <element xmi:type="uml:LoopNode" href="employment.uml#_6IKnQPJXEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_6IPfwvJXEeOWJr1T78jdJA" x="146" y="59" width="109" height="70"/> + </children> + <children xmi:type="notation:Shape" xmi:id="_x7_nwPlBEeOEp7Wro2yWpw" type="3004"> + <children xmi:type="notation:DecorationNode" xmi:id="_x8AO0PlBEeOEp7Wro2yWpw" type="5080"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_x8AO0flBEeOEp7Wro2yWpw" y="5"/> + </children> + <styles xmi:type="notation:HintedDiagramLinkStyle" xmi:id="_x7_nwflBEeOEp7Wro2yWpw"/> + <element xmi:type="uml:InitialNode" href="employment.uml#_x5npMPlBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_x7_nwvlBEeOEp7Wro2yWpw" x="28" y="67"/> + </children> + <children xmi:type="notation:Shape" xmi:id="_2YAgEPlBEeOEp7Wro2yWpw" type="3006"> + <children xmi:type="notation:DecorationNode" xmi:id="_2YBHIPlBEeOEp7Wro2yWpw" type="5082"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_2YBHIflBEeOEp7Wro2yWpw" y="5"/> + </children> + <styles xmi:type="notation:HintedDiagramLinkStyle" xmi:id="_2YAgEflBEeOEp7Wro2yWpw"/> + <element xmi:type="uml:FlowFinalNode" href="employment.uml#_2X-D0PlBEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_2YAgEvlBEeOEp7Wro2yWpw" x="350" y="80"/> + </children> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_4hrxsfJXEeOWJr1T78jdJA"/> + </children> + <element xmi:type="uml:Activity" href="employment.uml#_2W4uAPJXEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_4hrxsvJXEeOWJr1T78jdJA"/> + </children> + <styles xmi:type="notation:StringValueStyle" xmi:id="_4hrxs_JXEeOWJr1T78jdJA" name="diagram_compatibility_version" stringValue="1.0.0"/> + <styles xmi:type="notation:DiagramStyle" xmi:id="_4hrxtPJXEeOWJr1T78jdJA"/> + <styles xmi:type="style:PapyrusViewStyle" xmi:id="_4hrxtfJXEeOWJr1T78jdJA"> + <owner xmi:type="uml:Activity" href="employment.uml#_2W4uAPJXEeOWJr1T78jdJA"/> + </styles> + <element xmi:type="uml:Activity" href="employment.uml#_2W4uAPJXEeOWJr1T78jdJA"/> + <edges xmi:type="notation:Connector" xmi:id="_zIi6cPlBEeOEp7Wro2yWpw" type="4004" source="_x7_nwPlBEeOEp7Wro2yWpw" target="_6IPfwPJXEeOWJr1T78jdJA"> + <children xmi:type="notation:DecorationNode" xmi:id="_zIi6c_lBEeOEp7Wro2yWpw" visible="false" type="6003"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_zIi6dPlBEeOEp7Wro2yWpw" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_zIjhgPlBEeOEp7Wro2yWpw" visible="false" type="6004"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_zIjhgflBEeOEp7Wro2yWpw" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_zIjhgvlBEeOEp7Wro2yWpw" visible="false" type="6009"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_zIjhg_lBEeOEp7Wro2yWpw" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_zIjhhPlBEeOEp7Wro2yWpw" visible="false" type="6011"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_zIjhhflBEeOEp7Wro2yWpw" y="-20"/> + </children> + <styles xmi:type="notation:FontStyle" xmi:id="_zIi6cflBEeOEp7Wro2yWpw"/> + <element xmi:type="uml:ControlFlow" href="employment.uml#_zIVfEPlBEeOEp7Wro2yWpw"/> + <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_zIi6cvlBEeOEp7Wro2yWpw" points="[10, 0, -114, 0]$[108, 7, -16, 7]"/> + <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_zPwVsPlBEeOEp7Wro2yWpw" id="(0.0,0.5142857142857142)"/> + </edges> + <edges xmi:type="notation:Connector" xmi:id="_4S2cIPlBEeOEp7Wro2yWpw" type="4004" source="_6IPfwPJXEeOWJr1T78jdJA" target="_2YAgEPlBEeOEp7Wro2yWpw"> + <children xmi:type="notation:DecorationNode" xmi:id="_4S2cI_lBEeOEp7Wro2yWpw" visible="false" type="6003"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_4S2cJPlBEeOEp7Wro2yWpw" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_4S2cJflBEeOEp7Wro2yWpw" visible="false" type="6004"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_4S3DMPlBEeOEp7Wro2yWpw" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_4S3DMflBEeOEp7Wro2yWpw" visible="false" type="6009"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_4S3DMvlBEeOEp7Wro2yWpw" y="20"/> + </children> + <children xmi:type="notation:DecorationNode" xmi:id="_4S3DM_lBEeOEp7Wro2yWpw" visible="false" type="6011"> + <layoutConstraint xmi:type="notation:Location" xmi:id="_4S3DNPlBEeOEp7Wro2yWpw" y="-20"/> + </children> + <styles xmi:type="notation:FontStyle" xmi:id="_4S2cIflBEeOEp7Wro2yWpw"/> + <element xmi:type="uml:ControlFlow" href="employment.uml#_4Sgd4PlBEeOEp7Wro2yWpw"/> + <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_4S2cIvlBEeOEp7Wro2yWpw" points="[18, -2, -131, -2]$[152, -10, 3, -10]"/> + <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_4S-_APlBEeOEp7Wro2yWpw" id="(0.76,0.475)"/> + </edges> + </notation:Diagram> + <css:ModelStyleSheets xmi:id="_fBUnoPMZEeOa2u9_4wMSZA"/> + <nattable:Table xmi:id="_HvMBoPrfEeOjArr2x5XJOA" name="classes" currentRowAxisProvider="_HvMosfrfEeOjArr2x5XJOA" currentColumnAxisProvider="_HvMosPrfEeOjArr2x5XJOA"> + <context xmi:type="uml:Model" href="employment.uml#_6iAasPJDEeOWJr1T78jdJA"/> + <owner xmi:type="uml:Model" href="employment.uml#_6iAasPJDEeOWJr1T78jdJA"/> + <prototype xmi:type="configuration:PapyrusSyncTable" href="platform:/plugin/org.eclipse.papyrus.infra.viewpoints.policy/builtin/default.configuration#_7wNb2NxhEeOqHvRyiN87hA"/> + <tableConfiguration xmi:type="nattableconfiguration:TableConfiguration" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#/"/> + <columnAxisProvidersHistory xmi:type="nattableaxisprovider:SlaveObjectAxisProvider" xmi:id="_HvMosPrfEeOjArr2x5XJOA" description="This axis provider provides available columns according to the rows of the table (features of the object displayed on the other axis)" name="UML Feature axis provider"> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kkPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EAttribute" href="http://www.eclipse.org/uml2/5.0.0/UML#//NamedElement/visibility"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kkfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/useCase"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kkvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/substitution"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kk_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/general"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58klPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Namespace/importedMember"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58klfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//TemplateableElement/ownedTemplateSignature"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58klvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Namespace/member"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kl_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//StructuredClassifier/part"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kmPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Element/owner"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kmfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/feature"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kmvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EAttribute" href="http://www.eclipse.org/uml2/5.0.0/UML#//NamedElement/name"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58km_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Class/ownedOperation"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58knPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//BehavioredClassifier/interfaceRealization"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58knfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//TemplateableElement/templateBinding"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58knvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/redefinedClassifier"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kn_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//StructuredClassifier/ownedConnector"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58koPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//BehavioredClassifier/ownedBehavior"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kofrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Namespace/elementImport"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kovrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/attribute"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ko_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Class/nestedClassifier"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kpPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//RedefinableElement/redefinedElement"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kpfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Class/extension"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kpvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//NamedElement/nameExpression"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kp_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//ParameterableElement/owningTemplateParameter"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kqPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//BehavioredClassifier/classifierBehavior"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kqfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Namespace/ownedRule"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kqvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/generalization"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kq_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EAttribute" href="http://www.eclipse.org/uml2/5.0.0/UML#//RedefinableElement/isLeaf"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58krPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/collaborationUse"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58krfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//EncapsulatedClassifier/ownedPort"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58krvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//NamedElement/namespace"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kr_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//StructuredClassifier/role"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ksPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//ParameterableElement/templateParameter"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ksfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Class/superClass"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ksvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Namespace/ownedMember"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ks_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Element/ownedComment"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ktPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EAttribute" href="http://www.eclipse.org/uml2/5.0.0/UML#//Class/isActive"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ktfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/powertypeExtent"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ktvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Element/ownedElement"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kt_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//NamedElement/clientDependency"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kuPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/inheritedMember"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kufrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EAttribute" href="http://www.eclipse.org/uml2/5.0.0/UML#//NamedElement/qualifiedName"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kuvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//RedefinableElement/redefinitionContext"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58ku_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Namespace/packageImport"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kvPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EAttribute" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/isAbstract"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kvfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EAttribute" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/isFinalSpecialization"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kvvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Class/ownedReception"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kv_rfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//StructuredClassifier/ownedAttribute"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kwPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/representation"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kwfrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Classifier/ownedUseCase"/> + </axis> + <axis xmi:type="nattableaxis:EStructuralFeatureAxis" xmi:id="_I58kwvrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@columnHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Type/package"/> + </axis> + </columnAxisProvidersHistory> + <rowAxisProvidersHistory xmi:type="nattableaxisprovider:MasterObjectAxisProvider" xmi:id="_HvMosfrfEeOjArr2x5XJOA" description="This axis provider contains the object dropped by the user into the table" name="DroppedElementAxisProvider"> + <axis xmi:type="nattableaxis:EObjectAxis" xmi:id="_I56vYPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@rowHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="uml:Class" href="employment.uml#_YCTP0PJEEeOWJr1T78jdJA"/> + </axis> + <axis xmi:type="nattableaxis:EObjectAxis" xmi:id="_I57WcPrfEeOjArr2x5XJOA"> + <manager xmi:type="nattableaxisconfiguration:AxisManagerRepresentation" href="platform:/plugin/org.eclipse.papyrus.uml.nattable.generic.config/configs/generic.nattableconfiguration#//@rowHeaderAxisConfiguration/@axisManagers.0"/> + <element xmi:type="uml:Class" href="employment.uml#__JZpQPMXEeOa2u9_4wMSZA"/> + </axis> + </rowAxisProvidersHistory> + </nattable:Table> +</xmi:XMI> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.uml b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.uml new file mode 100644 index 00000000000..4ff766e905a --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/employment.uml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_6iAasPJDEeOWJr1T78jdJA" name="employment"> + <packageImport xmi:type="uml:PackageImport" xmi:id="_6iAasfJDEeOWJr1T78jdJA"> + <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/> + </packageImport> + <packagedElement xmi:type="uml:Class" xmi:id="_YCTP0PJEEeOWJr1T78jdJA" name="Person"> + <ownedAttribute xmi:type="uml:Property" xmi:id="_mLn68PJEEeOWJr1T78jdJA" name="ssn" visibility="public" isUnique="false"> + <type xmi:type="uml:DataType" href="library.uml#_AtaNAPJEEeOWJr1T78jdJA"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_opwxUPJEEeOWJr1T78jdJA" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_op4tIPJEEeOWJr1T78jdJA" value="1"/> + </ownedAttribute> + <ownedAttribute xmi:type="uml:Property" xmi:id="_SDT0YPlAEeOEp7Wro2yWpw" name="name" visibility="public" isUnique="false"> + <type xmi:type="uml:DataType" href="library.uml#_vCcKoPJEEeOWJr1T78jdJA"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_S4X0IPlAEeOEp7Wro2yWpw" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_S4izQPlAEeOEp7Wro2yWpw" value="1"/> + </ownedAttribute> + <ownedBehavior xmi:type="uml:Activity" xmi:id="_2W4uAPJXEeOWJr1T78jdJA" name="Activity" node="_6IKnQPJXEeOWJr1T78jdJA _x5npMPlBEeOEp7Wro2yWpw _2X-D0PlBEeOEp7Wro2yWpw" group="_6IKnQPJXEeOWJr1T78jdJA"> + <edge xmi:type="uml:ControlFlow" xmi:id="_zIVfEPlBEeOEp7Wro2yWpw" name="ControlFlow" target="_6IKnQPJXEeOWJr1T78jdJA" source="_x5npMPlBEeOEp7Wro2yWpw"/> + <edge xmi:type="uml:ControlFlow" xmi:id="_4Sgd4PlBEeOEp7Wro2yWpw" name="ControlFlow1" target="_2X-D0PlBEeOEp7Wro2yWpw" source="_6IKnQPJXEeOWJr1T78jdJA"/> + <structuredNode xmi:type="uml:LoopNode" xmi:id="_6IKnQPJXEeOWJr1T78jdJA" name="work" incoming="_zIVfEPlBEeOEp7Wro2yWpw" outgoing="_4Sgd4PlBEeOEp7Wro2yWpw"> + <node xmi:type="uml:OpaqueAction" xmi:id="_DupxEPlCEeOEp7Wro2yWpw" name="do work"/> + </structuredNode> + <node xmi:type="uml:InitialNode" xmi:id="_x5npMPlBEeOEp7Wro2yWpw" name="InitialNode" outgoing="_zIVfEPlBEeOEp7Wro2yWpw"/> + <node xmi:type="uml:FlowFinalNode" xmi:id="_2X-D0PlBEeOEp7Wro2yWpw" name="FlowFinalNode" incoming="_4Sgd4PlBEeOEp7Wro2yWpw"/> + </ownedBehavior> + </packagedElement> + <packagedElement xmi:type="uml:Class" xmi:id="__JZpQPMXEeOa2u9_4wMSZA" name="Company"> + <ownedAttribute xmi:type="uml:Property" xmi:id="_AsHZMPMYEeOa2u9_4wMSZA" name="employee" type="_YCTP0PJEEeOWJr1T78jdJA" subsettedProperty="_mLn68PJEEeOWJr1T78jdJA" association="_AsIAQPMYEeOa2u9_4wMSZA"> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_AsHZMfMYEeOa2u9_4wMSZA"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_AsHZMvMYEeOa2u9_4wMSZA" value="*"/> + </ownedAttribute> + <ownedAttribute xmi:type="uml:Property" xmi:id="_M1fEoPlAEeOEp7Wro2yWpw" name="name" visibility="public" isUnique="false"> + <type xmi:type="uml:DataType" href="library.uml#_vCcKoPJEEeOWJr1T78jdJA"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_Q5IgQPlAEeOEp7Wro2yWpw" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_Q5YX4PlAEeOEp7Wro2yWpw" value="1"/> + </ownedAttribute> + </packagedElement> + <packagedElement xmi:type="uml:Association" xmi:id="_AsIAQPMYEeOa2u9_4wMSZA" name="A_company_person_1" memberEnd="_AsIAQfMYEeOa2u9_4wMSZA _AsHZMPMYEeOa2u9_4wMSZA"> + <ownedEnd xmi:type="uml:Property" xmi:id="_AsIAQfMYEeOa2u9_4wMSZA" name="employer" visibility="public" type="__JZpQPMXEeOa2u9_4wMSZA" association="_AsIAQPMYEeOa2u9_4wMSZA"> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_AsIAQvMYEeOa2u9_4wMSZA" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_AsIAQ_MYEeOa2u9_4wMSZA" value="1"/> + </ownedEnd> + </packagedElement> +</uml:Model> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.di b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.di new file mode 100644 index 00000000000..42ec9bffb56 --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.di @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<di:SashWindowsMngr xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.eclipse.org/papyrus/0.7.0/sashdi"> + <sashModel currentSelection="//@sashModel/@windows.0/@children.0"> + <windows> + <children xsi:type="di:TabFolder"> + <children> + <emfPageIdentifier href="library.notation#__mWeUPJDEeOWJr1T78jdJA"/> + </children> + </children> + </windows> + </sashModel> +</di:SashWindowsMngr> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.notation b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.notation new file mode 100644 index 00000000000..97b9536a1e0 --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.notation @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<notation:Diagram xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.2/notation" xmlns:style="http://www.eclipse.org/papyrus/infra/viewpoints/policy/style" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="__mWeUPJDEeOWJr1T78jdJA" type="PapyrusUMLClassDiagram" name="classes" measurementUnit="Pixel"> + <children xmi:type="notation:Shape" xmi:id="_AuLpEPJEEeOWJr1T78jdJA" type="2010"> + <children xmi:type="notation:DecorationNode" xmi:id="_AuMQIPJEEeOWJr1T78jdJA" type="5035"/> + <children xmi:type="notation:BasicCompartment" xmi:id="_AuMQIfJEEeOWJr1T78jdJA" type="7020"> + <children xmi:type="notation:Shape" xmi:id="_eT1fUPJEEeOWJr1T78jdJA" type="3018"> + <element xmi:type="uml:Property" href="library.uml#_eThWQPJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_eT1fUfJEEeOWJr1T78jdJA"/> + </children> + <styles xmi:type="notation:TitleStyle" xmi:id="_AuMQIvJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_AuMQI_JEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_AuMQJPJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_AuMQJfJEEeOWJr1T78jdJA"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_AuM3MPJEEeOWJr1T78jdJA" type="7021"> + <styles xmi:type="notation:TitleStyle" xmi:id="_AuM3MfJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_AuM3MvJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_AuM3M_JEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_AuM3NPJEEeOWJr1T78jdJA"/> + </children> + <element xmi:type="uml:DataType" href="library.uml#_AtaNAPJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_AuLpEfJEEeOWJr1T78jdJA" x="67" y="55"/> + </children> + <children xmi:type="notation:Shape" xmi:id="_vCdYwPJEEeOWJr1T78jdJA" type="2010"> + <children xmi:type="notation:DecorationNode" xmi:id="_vCdYwvJEEeOWJr1T78jdJA" type="5035"/> + <children xmi:type="notation:BasicCompartment" xmi:id="_vCdYw_JEEeOWJr1T78jdJA" type="7020"> + <children xmi:type="notation:Shape" xmi:id="_W7AjIPlAEeOEp7Wro2yWpw" type="3018"> + <element xmi:type="uml:Property" href="library.uml#_W65OYPlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_W7AjIflAEeOEp7Wro2yWpw"/> + </children> + <children xmi:type="notation:Shape" xmi:id="_YtLrYPlAEeOEp7Wro2yWpw" type="3018"> + <element xmi:type="uml:Property" href="library.uml#_YtJ2MPlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Location" xmi:id="_YtLrYflAEeOEp7Wro2yWpw"/> + </children> + <styles xmi:type="notation:TitleStyle" xmi:id="_vCdYxPJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_vCdYxfJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_vCdYxvJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_vCdYx_JEEeOWJr1T78jdJA"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_vCdYyPJEEeOWJr1T78jdJA" type="7021"> + <styles xmi:type="notation:TitleStyle" xmi:id="_vCdYyfJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_vCdYyvJEEeOWJr1T78jdJA"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_vCdYy_JEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_vCdYzPJEEeOWJr1T78jdJA"/> + </children> + <element xmi:type="uml:DataType" href="library.uml#_vCcKoPJEEeOWJr1T78jdJA"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_vCdYwfJEEeOWJr1T78jdJA" x="276" y="54"/> + </children> + <children xmi:type="notation:Shape" xmi:id="_9VjWcPlAEeOEp7Wro2yWpw" type="2009"> + <children xmi:type="notation:DecorationNode" xmi:id="_9VjWcvlAEeOEp7Wro2yWpw" type="5032"/> + <children xmi:type="notation:BasicCompartment" xmi:id="_9VjWc_lAEeOEp7Wro2yWpw" type="7039"> + <styles xmi:type="notation:TitleStyle" xmi:id="_9VjWdPlAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_9VjWdflAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_9VjWdvlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_9VjWd_lAEeOEp7Wro2yWpw"/> + </children> + <children xmi:type="notation:BasicCompartment" xmi:id="_9VjWePlAEeOEp7Wro2yWpw" type="7040"> + <styles xmi:type="notation:TitleStyle" xmi:id="_9VjWeflAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:SortingStyle" xmi:id="_9VjWevlAEeOEp7Wro2yWpw"/> + <styles xmi:type="notation:FilteringStyle" xmi:id="_9VjWe_lAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_9VjWfPlAEeOEp7Wro2yWpw"/> + </children> + <element xmi:type="uml:PrimitiveType" href="library.uml#_9VhhQPlAEeOEp7Wro2yWpw"/> + <layoutConstraint xmi:type="notation:Bounds" xmi:id="_9VjWcflAEeOEp7Wro2yWpw" x="498" y="55"/> + </children> + <styles xmi:type="notation:StringValueStyle" xmi:id="__mWeUfJDEeOWJr1T78jdJA" name="diagram_compatibility_version" stringValue="1.0.0"/> + <styles xmi:type="notation:DiagramStyle" xmi:id="__mWeUvJDEeOWJr1T78jdJA"/> + <styles xmi:type="style:PapyrusViewStyle" xmi:id="__mWeU_JDEeOWJr1T78jdJA"> + <owner xmi:type="uml:Model" href="library.uml#__mBuMPJDEeOWJr1T78jdJA"/> + </styles> + <element xmi:type="uml:Model" href="library.uml#__mBuMPJDEeOWJr1T78jdJA"/> +</notation:Diagram> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.uml b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.uml new file mode 100644 index 00000000000..3be4c8d6dc4 --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/model/reload/library.uml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xmi:XMI xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ActionLanguage="http://www.omg.org/spec/ALF/20120827/ActionLanguage-Profile" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xsi:schemaLocation="http://www.omg.org/spec/ALF/20120827/ActionLanguage-Profile pathmap://PAPYRUS_ACTIONLANGUAGE_PROFILE/ActionLanguage-Profile.profile.uml#_sYse0YZLEeKyw49uR6nx3g"> + <uml:Model xmi:id="__mBuMPJDEeOWJr1T78jdJA" name="types"> + <packageImport xmi:type="uml:PackageImport" xmi:id="__mBuMfJDEeOWJr1T78jdJA"> + <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/> + </packageImport> + <packagedElement xmi:type="uml:DataType" xmi:id="_AtaNAPJEEeOWJr1T78jdJA" name="SSN"> + <ownedAttribute xmi:type="uml:Property" xmi:id="_eThWQPJEEeOWJr1T78jdJA" name="ssn" visibility="public" isUnique="false"> + <type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_gmTRMPJEEeOWJr1T78jdJA" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_gmcbIPJEEeOWJr1T78jdJA" value="1"/> + </ownedAttribute> + </packagedElement> + <packagedElement xmi:type="uml:DataType" xmi:id="_vCcKoPJEEeOWJr1T78jdJA" name="Name"> + <ownedAttribute xmi:type="uml:Property" xmi:id="_W65OYPlAEeOEp7Wro2yWpw" name="lastName" visibility="public" isUnique="false"> + <type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_YAKNUPlAEeOEp7Wro2yWpw" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_YAWakPlAEeOEp7Wro2yWpw" value="1"/> + </ownedAttribute> + <ownedAttribute xmi:type="uml:Property" xmi:id="_YtJ2MPlAEeOEp7Wro2yWpw" name="firstName" visibility="public" isUnique="false"> + <type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/> + <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_b6Vj4PlAEeOEp7Wro2yWpw" value="1"/> + <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_b6kNYPlAEeOEp7Wro2yWpw" value="1"/> + </ownedAttribute> + </packagedElement> + <packagedElement xmi:type="uml:PrimitiveType" xmi:id="_9VhhQPlAEeOEp7Wro2yWpw" name="Identifier"/> + <profileApplication xmi:type="uml:ProfileApplication" xmi:id="_ZdS5sPlAEeOEp7Wro2yWpw"> + <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_ZeInMPlAEeOEp7Wro2yWpw" source="http://www.eclipse.org/uml2/2.0.0/UML"> + <references xmi:type="ecore:EPackage" href="pathmap://PAPYRUS_ACTIONLANGUAGE_PROFILE/ActionLanguage-Profile.profile.uml#_sYse0YZLEeKyw49uR6nx3g"/> + </eAnnotations> + <appliedProfile xmi:type="uml:Profile" href="pathmap://PAPYRUS_ACTIONLANGUAGE_PROFILE/ActionLanguage-Profile.profile.uml#ActionLanguage"/> + </profileApplication> + </uml:Model> + <ActionLanguage:TextualRepresentation xmi:id="_ZeLDcPlAEeOEp7Wro2yWpw" language="org.eclipse.papyrus.uml.textedit.property.xtext.UmlProperty"/> +</xmi:XMI> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/org.eclipse.papyrus.editor.integration.tests.launch b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/org.eclipse.papyrus.editor.integration.tests.launch index d3fbfd43b01..53fb6cee559 100644 --- a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/org.eclipse.papyrus.editor.integration.tests.launch +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/org.eclipse.papyrus.editor.integration.tests.launch @@ -1,43 +1,43 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
-<booleanAttribute key="append.args" value="true"/>
-<booleanAttribute key="askclear" value="false"/>
-<booleanAttribute key="automaticAdd" value="true"/>
-<booleanAttribute key="automaticValidate" value="false"/>
-<stringAttribute key="bootstrap" value=""/>
-<stringAttribute key="checked" value="[NONE]"/>
-<booleanAttribute key="clearConfig" value="true"/>
-<booleanAttribute key="clearws" value="true"/>
-<booleanAttribute key="clearwslog" value="false"/>
-<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
-<booleanAttribute key="default" value="true"/>
-<booleanAttribute key="includeOptional" value="true"/>
-<stringAttribute key="location" value="${workspace_loc}/../junit-workspace-editor"/>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/AllTests.java"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="1"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
-<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.papyrus.editor.integration.tests.AllTests"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.papyrus.editor.integration.tests"/>
-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dosgi.requiredJavaVersion=1.5 -Xms1024m -Xmx4086m -XX:MaxPermSize=1024M"/>
-<stringAttribute key="pde.version" value="3.3"/>
-<stringAttribute key="product" value="org.eclipse.sdk.ide"/>
-<booleanAttribute key="run_in_ui_thread" value="false"/>
-<booleanAttribute key="show_selected_only" value="false"/>
-<stringAttribute key="templateConfig" value="${target_home}\configuration\config.ini"/>
-<booleanAttribute key="tracing" value="false"/>
-<booleanAttribute key="useCustomFeatures" value="false"/>
-<booleanAttribute key="useDefaultConfig" value="true"/>
-<booleanAttribute key="useDefaultConfigArea" value="false"/>
-<booleanAttribute key="useProduct" value="true"/>
-</launchConfiguration>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig"> +<booleanAttribute key="append.args" value="true"/> +<booleanAttribute key="askclear" value="false"/> +<booleanAttribute key="automaticAdd" value="true"/> +<booleanAttribute key="automaticValidate" value="false"/> +<stringAttribute key="bootstrap" value=""/> +<stringAttribute key="checked" value="[NONE]"/> +<booleanAttribute key="clearConfig" value="true"/> +<booleanAttribute key="clearws" value="true"/> +<booleanAttribute key="clearwslog" value="false"/> +<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/> +<booleanAttribute key="default" value="true"/> +<booleanAttribute key="includeOptional" value="true"/> +<stringAttribute key="location" value="${workspace_loc}/../junit-workspace-editor"/> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> +<listEntry value="/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/AllTests.java"/> +</listAttribute> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> +<listEntry value="1"/> +</listAttribute> +<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/> +<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/> +<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/> +<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/> +<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/> +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> +<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.papyrus.editor.integration.tests.AllTests"/> +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/> +<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.papyrus.editor.integration.tests"/> +<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/> +<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dosgi.requiredJavaVersion=1.5 -Xms1024m -Xmx4086m -XX:MaxPermSize=1024M"/> +<stringAttribute key="pde.version" value="3.3"/> +<stringAttribute key="product" value="org.eclipse.sdk.ide"/> +<booleanAttribute key="run_in_ui_thread" value="true"/> +<booleanAttribute key="show_selected_only" value="false"/> +<stringAttribute key="templateConfig" value="${target_home}\configuration\config.ini"/> +<booleanAttribute key="tracing" value="false"/> +<booleanAttribute key="useCustomFeatures" value="false"/> +<booleanAttribute key="useDefaultConfig" value="true"/> +<booleanAttribute key="useDefaultConfigArea" value="false"/> +<booleanAttribute key="useProduct" value="true"/> +</launchConfiguration> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/AllTests.java b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/AllTests.java index a4023007aa9..761bd723d37 100644 --- a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/AllTests.java +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/AllTests.java @@ -10,12 +10,14 @@ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - bug 422257
* Christian W. Damus (CEA) - bug 432813
+ * Christian W. Damus (CEA) - bug 437217
*
*****************************************************************************/
package org.eclipse.papyrus.editor.integration.tests;
import org.eclipse.papyrus.editor.integration.tests.tests.EditingScenariosMemoryLeakTest;
import org.eclipse.papyrus.editor.integration.tests.tests.EditorMemoryLeakTest;
+import org.eclipse.papyrus.editor.integration.tests.tests.EditorReloadTest;
import org.eclipse.papyrus.editor.integration.tests.tests.ModelSetTests;
import org.eclipse.papyrus.editor.integration.tests.tests.PageManagerTests;
import org.eclipse.papyrus.editor.integration.tests.tests.RecoveryTest;
@@ -26,12 +28,14 @@ import org.junit.runners.Suite.SuiteClasses; /**
* The {@link EditorMemoryLeakTest} suite <b>must</b> run first, because some test case in one of the other suites
- * breaks the Outline view: it causes a pair of Overview/Outline actions from some diagram editor to linger in
+ * breaks the Outline view: it causes a pair of Overview/Outline actions from some diagram editor to linger in
* the outline view's toolbar even after the editor was closed, and these persistent actions cause leaks of
* models opened later.
*/
@RunWith(Suite.class)
-@SuiteClasses({ EditorMemoryLeakTest.class, EditingScenariosMemoryLeakTest.class, PageManagerTests.class, RecoveryTest.class, ModelSetTests.class })
+@SuiteClasses({ EditorMemoryLeakTest.class, EditingScenariosMemoryLeakTest.class, //
+PageManagerTests.class, RecoveryTest.class, ModelSetTests.class, //
+EditorReloadTest.class })
public class AllTests {
}
diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/tests/EditorReloadTest.java b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/tests/EditorReloadTest.java new file mode 100644 index 00000000000..315031ed396 --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.editor.integration.tests/src/org/eclipse/papyrus/editor/integration/tests/tests/EditorReloadTest.java @@ -0,0 +1,530 @@ +/* + * 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.editor.integration.tests.tests; + +import static org.eclipse.papyrus.junit.matchers.DiagramMatchers.collapsedIn; +import static org.eclipse.papyrus.junit.matchers.DiagramMatchers.editPartSelected; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.edit.command.CommandParameter; +import org.eclipse.emf.edit.command.SetCommand; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.gef.EditPart; +import org.eclipse.gef.palette.PaletteContainer; +import org.eclipse.gef.palette.PaletteDrawer; +import org.eclipse.gef.palette.PaletteEntry; +import org.eclipse.gef.palette.PaletteStack; +import org.eclipse.gef.palette.ToolEntry; +import org.eclipse.gef.ui.palette.PaletteViewer; +import org.eclipse.gef.ui.views.palette.PaletteView; +import org.eclipse.jface.viewers.AbstractTreeViewer; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor; +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.emf.utils.EMFHelper; +import org.eclipse.papyrus.junit.utils.Duck; +import org.eclipse.papyrus.junit.utils.classification.ExpensiveTest; +import org.eclipse.papyrus.junit.utils.rules.PapyrusEditorFixture; +import org.eclipse.papyrus.junit.utils.rules.PluginResource; +import org.eclipse.papyrus.junit.utils.rules.ShowView; +import org.eclipse.papyrus.junit.utils.rules.ShowView.Location; +import org.eclipse.papyrus.junit.utils.tests.AbstractPapyrusTest; +import org.eclipse.papyrus.views.modelexplorer.ModelExplorerPageBookView; +import org.eclipse.swt.widgets.Item; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.navigator.CommonViewer; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.OpaqueAction; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.Type; +import org.eclipse.uml2.uml.UMLPackage; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + + +/** + * Test cases checking that various different scenarios in Papyrus editor re-loading for changes in resource dependencies. + * + * @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=437217">bug 437217</a> + */ +@ExpensiveTest +@PluginResource({ EditorReloadTest.EMPLOYMENT_MODEL, EditorReloadTest.BANKING_MODEL, EditorReloadTest.LIBRARY_MODEL }) +public class EditorReloadTest extends AbstractPapyrusTest { + + static final String EMPLOYMENT_MODEL = "model/reload/employment.di"; + + static final String BANKING_MODEL = "model/reload/banking.di"; + + static final String LIBRARY_MODEL = "model/reload/library.di"; + + @Rule + public final PapyrusEditorFixture editorFixture = new PapyrusEditorFixture(); + + private IMultiDiagramEditor employmentEditor; + + private IMultiDiagramEditor bankingEditor; + + private IMultiDiagramEditor libraryEditor; + + public EditorReloadTest() { + super(); + } + + /** + * Verify that dependent editors are not re-loaded immediately (this is deferred until they are activated). + */ + @Test + public void testReloadIsDeferred() { + final ReloadAssertion reload = new ReloadAssertion(employmentEditor, bankingEditor); + + pokeLibraryModel(); + editorFixture.save(libraryEditor); + + reload.assertNotReloaded(); + } + + /** + * Verify that re-loading two dependent editors doesn't mess up the perspective layout. + */ + @Test + public void testPerspectiveLayoutUnperturbed() { + final ReloadAssertion reload = new ReloadAssertion(employmentEditor, bankingEditor); + + pokeLibraryModel(); + reload.save(libraryEditor); + + // The ordering and separation of editor stacks is unchanged + assertThat(editorFixture.getPartStack(employmentEditor), is(Arrays.<IWorkbenchPart> asList(employmentEditor, libraryEditor))); + assertThat(editorFixture.getPartStack(bankingEditor), is(Arrays.<IWorkbenchPart> asList(bankingEditor))); + } + + /** + * Verify that, after a <em>Save All</em> action that saves a non-active editor causing the active editor to re-load in place, + * the originally active editor is active once again. + */ + @Test + public void testActiveEditorRestoredSaveAll() { + final ReloadAssertion reload = new ReloadAssertion(employmentEditor); + + pokeLibraryModel(); + editorFixture.activate(employmentEditor); + editorFixture.saveAll(); + + reload.assertReloaded(); // The editor is reloaded immediately because it is already active + + assertThat(employmentEditor.getSite().getPage().getActiveEditor(), is((IEditorPart)employmentEditor)); + } + + /** + * Verify that the nested editor that was active is active again after the re-load. + */ + @Test + public void testActiveDiagramRestored() { + final String diagramTitle = "ActivityDiagram"; + final ReloadAssertion reload = new ReloadAssertion(employmentEditor); + + editorFixture.activate(employmentEditor); + editorFixture.activateDiagram(employmentEditor, diagramTitle); + + pokeLibraryModel(); + reload.save(libraryEditor); + + editorFixture.activate(employmentEditor); + assertThat(employmentEditor.getActiveEditor(), notNullValue()); + assertThat(employmentEditor.getActiveEditor().getTitle(), is(diagramTitle)); + } + + /** + * Verify that edit-part selections in a diagram are restored after the re-load. + */ + @Test + public void testEditPartSelectionRestored() { + final String diagramTitle = "ActivityDiagram"; + final String nodeName = "do work"; + final ReloadAssertion reload = new ReloadAssertion(employmentEditor); + + EditPart activityNode = editorFixture.activateDiagram(employmentEditor, diagramTitle).findEditPart(nodeName, OpaqueAction.class); + editorFixture.select(activityNode); + + pokeLibraryModel(); + reload.save(libraryEditor); + + activityNode = editorFixture.activateDiagram(employmentEditor, diagramTitle).findEditPart(nodeName, OpaqueAction.class); + + assertThat(activityNode, notNullValue()); + assertThat(activityNode, editPartSelected()); + } + + /** + * Verify that drawer, stack, and tool state in the palette is restored after editor re-load. + */ + @Test + public void testPaletteStateRestored() { + doTestPaletteStateRestored(); + } + + /** + * Verify that drawer, stack, and tool state in the <em>Palette View</em> is restored after editor re-load. + */ + @ShowView(PaletteView.ID) + @Test + public void testPaletteStateRestored_paletteView() { + doTestPaletteStateRestored(); + } + + void doTestPaletteStateRestored() { + final String diagramTitle = "ActivityDiagram"; + final String drawerLabel = "Edges"; + final String stackLabel = "ControlNodes"; + final String stackEntryLabel = "Activity final"; + final String activeToolLabel = "Comment"; + final ReloadAssertion reload = new ReloadAssertion(employmentEditor); + + PaletteViewer palette = editorFixture.activateDiagram(employmentEditor, diagramTitle).getPalette(); + + // Collapse the Edges drawer + PaletteDrawer edges = find(palette.getPaletteRoot(), drawerLabel, PaletteDrawer.class); + new Duck(palette.getEditPartRegistry().get(edges)).quack("setExpanded", false); + + // Select the Activity Final Node in the control nodes stack + PaletteStack stack = find(palette.getPaletteRoot(), stackLabel, PaletteStack.class); + stack.setActiveEntry(find(stack, stackEntryLabel, ToolEntry.class)); + + // And make the Comment tool active + palette.setActiveTool(find(palette.getPaletteRoot(), activeToolLabel, ToolEntry.class)); + + editorFixture.flushDisplayEvents(); + + pokeLibraryModel(); + reload.save(libraryEditor); + + palette = editorFixture.activateDiagram(employmentEditor, diagramTitle).getPalette(); + + // Verify the Edges drawer + edges = find(palette.getPaletteRoot(), drawerLabel, PaletteDrawer.class); + assertThat(edges, collapsedIn(palette)); + + // Verify Activity Final Node selection in its stack + stack = find(palette.getPaletteRoot(), stackLabel, PaletteStack.class); + assertThat(stack.getActiveEntry().getLabel(), is(stackEntryLabel)); + + // Verify the active tool + assertThat(palette.getActiveTool().getLabel(), is(activeToolLabel)); + } + + @ShowView(value = ModelExplorerPageBookView.VIEW_ID, location = Location.LEFT) + @Test + public void testModelExplorerSelectionRestored() { + final ReloadAssertion reload = new ReloadAssertion(employmentEditor); + + editorFixture.activate(employmentEditor); + + CommonViewer explorer = editorFixture.getModelExplorerView().getCommonViewer(); + Set<String> selectedLabels = ImmutableSet.of("employment::Company", "types::Name::firstName"); + explorer.getTree().setSelection(getItems(explorer, selectedLabels)); + Set<URI> selectedObjects = Sets.newHashSet(); + for(Object next : ((IStructuredSelection)explorer.getSelection()).toList()) { + EObject object = EMFHelper.getEObject(next); + selectedObjects.add(EcoreUtil.getURI(object)); + } + + pokeLibraryModel(); + reload.save(libraryEditor); + + editorFixture.activate(employmentEditor); + + explorer = editorFixture.getModelExplorerView().getCommonViewer(); + Set<URI> selectedAgain = Sets.newHashSet(); + for(Object next : ((IStructuredSelection)explorer.getSelection()).toList()) { + EObject object = EMFHelper.getEObject(next); + selectedAgain.add(EcoreUtil.getURI(object)); + } + assertThat(selectedAgain, is(selectedObjects)); + } + + @ShowView(value = ModelExplorerPageBookView.VIEW_ID, location = Location.LEFT) + @Test + public void testModelExplorerExpansionRestored() { + final ReloadAssertion reload = new ReloadAssertion(employmentEditor); + + editorFixture.activate(employmentEditor); + + CommonViewer explorer = editorFixture.getModelExplorerView().getCommonViewer(); + Set<String> expandedLabels = ImmutableSet.of("employment::A_company_person_1", "types::UML Primitive Types::PrimitiveTypes::Real"); + for(TreeItem next : getItems(explorer, expandedLabels)) { + next.setExpanded(true); + } + Set<URI> expandedObjects = Sets.newHashSet(); + for(Object next : explorer.getExpandedElements()) { + EObject object = EMFHelper.getEObject(next); + expandedObjects.add(EcoreUtil.getURI(object)); + } + + pokeLibraryModel(); + reload.save(libraryEditor); + + editorFixture.activate(employmentEditor); + + explorer = editorFixture.getModelExplorerView().getCommonViewer(); + Set<URI> expandedAgain = Sets.newHashSet(); + for(Object next : explorer.getExpandedElements()) { + EObject object = EMFHelper.getEObject(next); + expandedAgain.add(EcoreUtil.getURI(object)); + } + assertThat(expandedAgain, is(expandedObjects)); + } + + // + // Test framework + // + + @Before + public void layOutWorkbenchPage() { + employmentEditor = editorFixture.getEditor(EMPLOYMENT_MODEL); + bankingEditor = editorFixture.getEditor(BANKING_MODEL); + libraryEditor = editorFixture.getEditor(LIBRARY_MODEL); + + // Move the banking editor into its own part of the editor area + editorFixture.splitEditorArea(bankingEditor, false); + } + + void pokeLibraryModel() { + // First, make sure that the library editor is active (user can't edit it, otherwise!) + editorFixture.activate(libraryEditor); + + Package library = editorFixture.getModel(libraryEditor); + Type ssn = library.getOwnedType("SSN"); + EditingDomain domain = editorFixture.getEditingDomain(libraryEditor); + domain.getCommandStack().execute(domain.createCommand(SetCommand.class, new CommandParameter(ssn, UMLPackage.Literals.NAMED_ELEMENT__NAME, "SocialSecurityNumber"))); + } + + <P extends PaletteEntry> P find(PaletteContainer container, String label, Class<P> type) { + P result = null; + + for(P next : Iterables.filter(container.getChildren(), type)) { + if(label.equalsIgnoreCase(next.getLabel())) { + result = next; + break; + } + } + + if(result == null) { + for(PaletteContainer next : Iterables.filter(container.getChildren(), PaletteContainer.class)) { + result = find(next, label, type); + if(result != null) { + break; + } + } + } + + return result; + } + + Set<String> getLabels(Item... items) { + Set<String> result = Sets.newHashSet(); + + for(Item next : items) { + result.add(getLabel(next)); + } + + return result; + } + + TreeItem[] getItems(AbstractTreeViewer tree, Collection<String> labels) { + List<TreeItem> result = Lists.newArrayListWithCapacity(labels.size()); + + for(String next : labels) { + Widget search = tree.getControl(); + for(String part : Splitter.on(NamedElement.SEPARATOR).split(next)) { + search = findItem(tree, search, part); + } + + if(search instanceof TreeItem) { + result.add((TreeItem)search); + } + } + + return Iterables.toArray(result, TreeItem.class); + } + + static final Pattern METACLASS_QUALIFIER = Pattern.compile("<.+>"); + + static final Pattern STEREOTYPE_QUALIFIER = Pattern.compile("«.+»"); + + static String getLabel(Item item) { + String result = item.getText(); + + if(result != null) { + result = METACLASS_QUALIFIER.matcher(result).replaceAll(""); + result = STEREOTYPE_QUALIFIER.matcher(result).replaceAll(""); + result = result.trim(); + } + + return result; + } + + private Item findItem(AbstractTreeViewer tree, Widget parent, String label) { + Item result = null; + + if(parent != null) { + if(parent instanceof TreeItem) { + tree.expandToLevel(parent.getData(), 1); + } + + for(Item next : (Item[])new Duck(parent).quack("getItems")) { + if(label.equals(getLabel(next))) { + result = next; + break; + } + } + } + + return result; + } + + private class ReloadAssertion { + + private final Set<IMultiDiagramEditor> editors; + + private final Set<IMultiDiagramEditor> unloaded = Sets.newHashSet(); + + ReloadAssertion(IMultiDiagramEditor... editor) { + this.editors = Sets.newHashSet(editor); + + for(IMultiDiagramEditor next : editors) { + ServicesRegistry services = next.getServicesRegistry(); + + try { + services.add(Canary.class, 1, new Canary(next)); + services.startServicesByClassKeys(Canary.class); + } catch (ServiceException e) { + e.printStackTrace(); + fail("Failed to start Canary service: " + e.getLocalizedMessage()); + } + } + } + + /** + * Saves the specified editor, kicks the registered dependent editors by activating them, and asserts that they were re-loaded. + */ + void save(IMultiDiagramEditor editor) { + editorFixture.save(editor); + kick(); + assertReloaded(); + } + + void kick() { + if(!editors.isEmpty()) { + IWorkbenchPage page = Iterables.getFirst(editors, null).getSite().getPage(); + IEditorPart active = page.getActiveEditor(); + + for(IEditorPart next : editors) { + // Activate this editor to trigger reload + page.activate(next); + } + + if(active != null) { + // Restore the active editor + page.activate(active); + } + + editorFixture.flushDisplayEvents(); + } + } + + void assertUnloaded() { + assertThat("Some editors were not unloaded", unloaded, is(editors)); + } + + void assertLoaded() { + for(IMultiDiagramEditor next : editors) { + try { + boolean loaded = next.getServicesRegistry().isStarted(ModelSet.class.getName()); + assertThat("Editor not loaded: " + next.getTitle(), loaded, is(true)); + } catch (ServiceException e) { + e.printStackTrace(); + fail("Editor not loaded: " + next.getTitle()); + } + } + } + + void assertReloaded() { + assertUnloaded(); + assertLoaded(); + } + + void assertNotUnloaded() { + assertThat("Some editors were unloaded", Sets.difference(editors, unloaded), is(editors)); + } + + void assertNotReloaded() { + assertNotUnloaded(); + assertLoaded(); + } + + private class Canary implements IService { + + private final IMultiDiagramEditor editor; + + private ServicesRegistry services; + + Canary(IMultiDiagramEditor editor) { + this.editor = editor; + } + + public void init(ServicesRegistry servicesRegistry) throws ServiceException { + services = servicesRegistry; + + // For symmetry only; this never actually has any effect + unloaded.remove(editor); + } + + public void disposeService() throws ServiceException { + unloaded.add(editor); + services = null; + } + + public void startService() throws ServiceException { + // Load everything in the resource set so that we are sure to know of the dependency on the library model + EcoreUtil.resolveAll(services.getService(ModelSet.class)); + } + } + + } +} diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/META-INF/MANIFEST.MF b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/META-INF/MANIFEST.MF index ae8017b314c..58e9c06e0d5 100644 --- a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/META-INF/MANIFEST.MF +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/META-INF/MANIFEST.MF @@ -18,8 +18,12 @@ Require-Bundle: org.eclipse.ui, org.eclipse.papyrus.infra.tools;bundle-version="1.0.0", org.eclipse.papyrus.infra.emf;bundle-version="1.0.0", com.google.guava;bundle-version="11.0.0", - org.eclipse.papyrus.infra.nattable.model;bundle-version="1.0.0" -Export-Package: org.eclipse.papyrus.junit.utils, + org.eclipse.papyrus.infra.nattable.model;bundle-version="1.0.0", + org.eclipse.e4.ui.workbench;bundle-version="1.1.0", + org.eclipse.e4.ui.model.workbench;bundle-version="1.1.0", + org.eclipse.e4.core.contexts;bundle-version="1.3.0" +Export-Package: org.eclipse.papyrus.junit.matchers, + org.eclipse.papyrus.junit.utils, org.eclipse.papyrus.junit.utils.classification, org.eclipse.papyrus.junit.utils.resources, org.eclipse.papyrus.junit.utils.rules, diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/DiagramMatchers.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/DiagramMatchers.java new file mode 100644 index 00000000000..b78720e078a --- /dev/null +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/DiagramMatchers.java @@ -0,0 +1,104 @@ +/* + * 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.junit.matchers; + +import org.eclipse.gef.EditPart; +import org.eclipse.gef.EditPartViewer; +import org.eclipse.gef.palette.PaletteDrawer; +import org.eclipse.gef.ui.palette.PaletteViewer; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; + + +/** + * Hamcrest matchers for assertions on GMF diagrams. + */ +public class DiagramMatchers { + + private DiagramMatchers() { + super(); + } + + /** + * Match an edit part that is selected in its viewer. + */ + public static Matcher<EditPart> editPartSelected() { + return EditPartSelected.INSTANCE; + } + + /** + * Match a drawer that is expanded in the specified {@code viewer}. + */ + public static Matcher<PaletteDrawer> expandedIn(PaletteViewer viewer) { + return new DrawerExpansion(viewer, true); + } + + /** + * Match a drawer that is collapsed (closed) in the specified {@code viewer}. + */ + public static Matcher<PaletteDrawer> collapsedIn(PaletteViewer viewer) { + return new DrawerExpansion(viewer, false); + } + + // + // Nested types + // + + static class EditPartSelected extends BaseMatcher<EditPart> { + + private static final EditPartSelected INSTANCE = new EditPartSelected(); + + private EditPartSelected() { + super(); + } + + public void describeTo(Description description) { + description.appendText("edit-part is selected"); + } + + public boolean matches(Object item) { + return (item instanceof EditPart) && isSelected((EditPart)item); + } + + boolean isSelected(EditPart editPart) { + EditPartViewer viewer = editPart.getViewer(); + return (viewer != null) && viewer.getSelectedEditParts().contains(editPart); + } + } + + static class DrawerExpansion extends BaseMatcher<PaletteDrawer> { + + private final PaletteViewer viewer; + + private final boolean expanded; + + DrawerExpansion(PaletteViewer viewer, boolean expanded) { + this.viewer = viewer; + this.expanded = expanded; + } + + public void describeTo(Description description) { + description.appendText("drawer is "); + description.appendText(expanded ? "expanded" : "collapsed"); + } + + public boolean matches(Object item) { + return (item instanceof PaletteDrawer) && (isExpanded((PaletteDrawer)item) == expanded); + } + + boolean isExpanded(PaletteDrawer drawer) { + return viewer.isExpanded(drawer); + } + } +} diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Duck.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Duck.java index b7a253b003b..1abd00dea18 100644 --- a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Duck.java +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Duck.java @@ -159,7 +159,7 @@ public class Duck { Method[] scope = target.getClass().getMethods(); for(int i = 0; (result == null) && (i < scope.length); i++) { Method next = scope[i]; - if(next.getName().equals(methodName) && (returning == null) && match(next, signature)) { + if(next.getName().equals(methodName) && matchReturn(next.getReturnType(), returning) && match(next, signature)) { result = next; } } diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java index 231adc4f384..5d0da4a751d 100644 --- a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java @@ -24,6 +24,7 @@ import java.net.URL; import java.util.Enumeration; import java.util.HashSet; import java.util.LinkedList; +import java.util.List; import java.util.Queue; import java.util.Set; @@ -55,6 +56,7 @@ import org.osgi.framework.FrameworkUtil; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.google.common.io.ByteStreams; @@ -87,6 +89,8 @@ public abstract class AbstractModelFixture<T extends EditingDomain> extends Test private Class<?> testClass; + private Iterable<URI> initialResourceURIs; + public AbstractModelFixture() { super(); } @@ -146,15 +150,44 @@ public abstract class AbstractModelFixture<T extends EditingDomain> extends Test @Override protected void starting(Description description) { domain = createEditingDomain(); - model = (Package)initModelResource(description).getContents().get(0); + model = (Package)Iterables.getFirst(initModelResources(description), null).getContents().get(0); + + // We have finished initializing + initialResourceURIs = null; } - protected Resource initModelResource(Description description) { - Annotation resourceAnnotation = getResourceAnnotation(description); - ResourceKind kind = ResourceKind.getResourceKind(resourceAnnotation); + protected Iterable<Resource> initModelResources(Description description) { + List<Resource> result; + + // Don't initialize the resources more than once (subclasses such as PapyrusEditorFixture can repeat this) + if(initialResourceURIs == null) { + Annotation resourceAnnotation = getResourceAnnotation(description); + ResourceKind kind = ResourceKind.getResourceKind(resourceAnnotation); + + final String[] paths = kind.getResourcePaths(resourceAnnotation); + result = Lists.newArrayListWithCapacity(paths.length); + + for(String path : paths) { + result.add(initModelResource(new Path(path), kind)); + } + + List<URI> uris = Lists.newArrayListWithCapacity(result.size()); + for(Resource next : result) { + uris.add(next.getURI()); + } + initialResourceURIs = uris; + } else { + ResourceSet rset = getResourceSet(); + result = Lists.newArrayList(); + for(URI next : initialResourceURIs) { + result.add(rset.getResource(next, true)); + } + } - IPath resourcePath = new Path(kind.getResourcePath(resourceAnnotation)); + return result; + } + private Resource initModelResource(IPath resourcePath, ResourceKind kind) { String targetResourceName = "model"; if(isDIModel(resourcePath)) { // We will be initializing all three resources, and they have cross-references, so must not change @@ -309,6 +342,7 @@ public abstract class AbstractModelFixture<T extends EditingDomain> extends Test protected void finished(Description description) { final ResourceSet resourceSet = getResourceSet(); + initialResourceURIs = null; model = null; if(domain instanceof TransactionalEditingDomain) { @@ -359,7 +393,7 @@ public abstract class AbstractModelFixture<T extends EditingDomain> extends Test return (resourceAnnotation instanceof JavaResource) ? JAVA : (resourceAnnotation instanceof PluginResource) ? BUNDLE : null; } - String getResourcePath(Annotation resourceAnnotation) { + String[] getResourcePaths(Annotation resourceAnnotation) { switch(this) { case JAVA: return ((JavaResource)resourceAnnotation).value(); diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java index d9aa6b14340..23d870281ba 100644 --- a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java @@ -19,7 +19,7 @@ import java.lang.annotation.Target; /** - * Annotation indicating the classpath-relative path to a resource from which to load the test model of an {@link AbstractModelFixture}. + * Annotation indicating the classpath-relative path to one or more resources from which to load the test model of an {@link AbstractModelFixture}. * * @see AbstractModelFixture * @see PluginResource @@ -28,5 +28,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface JavaResource { - String value(); + String[] value(); } diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PapyrusEditorFixture.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PapyrusEditorFixture.java index c0f21173585..de24d1c0d43 100644 --- a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PapyrusEditorFixture.java +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PapyrusEditorFixture.java @@ -17,26 +17,44 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; +import java.util.Collection; import java.util.Iterator; +import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPartStack; +import org.eclipse.e4.ui.model.application.ui.basic.MStackElement; +import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; +import org.eclipse.gef.ui.palette.PaletteViewer; import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; +import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor; +import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditorWithFlyOutPalette; import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart; -import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.papyrus.editor.PapyrusMultiDiagramEditor; import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor; import org.eclipse.papyrus.infra.core.resource.ModelSet; import org.eclipse.papyrus.infra.core.resource.sasheditor.DiModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageManager; +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.IPageVisitor; +import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer; import org.eclipse.papyrus.infra.core.services.ServiceException; import org.eclipse.papyrus.infra.core.services.ServicesRegistry; import org.eclipse.papyrus.infra.core.utils.AdapterUtils; @@ -48,14 +66,18 @@ import org.eclipse.papyrus.views.modelexplorer.ModelExplorerPageBookView; import org.eclipse.papyrus.views.modelexplorer.ModelExplorerView; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IPartListener; +import org.eclipse.ui.ISaveablePart; import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.IPage; +import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.UMLPackage; import org.junit.runner.Description; @@ -63,7 +85,10 @@ import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; /** @@ -72,14 +97,20 @@ import com.google.common.collect.Iterables; */ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEditingDomain> { + private final Collection<IEditorPart> editorsToClose = Lists.newArrayList(); + private IMultiDiagramEditor editor; + private DiagramEditorWithFlyOutPalette activeDiagramEditor; + private ModelExplorerView modelExplorer; private Class<?> testClass; private Description testDescription; + private Collection<IViewPart> viewsToClose; + public PapyrusEditorFixture() { super(); } @@ -88,12 +119,29 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit return editor; } + public IMultiDiagramEditor getEditor(String path) { + IMultiDiagramEditor result = null; + + final String fileName = new Path(path).lastSegment(); + for(IEditorReference next : getWorkbenchPage().getEditorReferences()) { + if(PapyrusMultiDiagramEditor.EDITOR_ID.equals(next.getId()) && fileName.equals(next.getName())) { + result = (IMultiDiagramEditor)next.getEditor(true); + } + } + + return result; + } + @Override protected void starting(Description description) { testClass = description.getTestClass(); testDescription = description; - open(description); + if(hasRequiredViews()) { + openRequiredViews(); + } + + openAll(description); super.starting(description); } @@ -101,12 +149,34 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit @Override protected void finished(Description description) { try { - if(editor != null) { - close(editor); - editor = null; + Exception exception = null; + + for(IEditorPart editor : ImmutableList.copyOf(editorsToClose)) { + try { + close(editor); + } catch (Exception e) { + if(exception == null) { + exception = e; + } + } + } + + if(exception != null) { + exception.printStackTrace(); + fail("Failed to close an editor: " + exception.getLocalizedMessage()); } } finally { - super.finished(description); + editorsToClose.clear(); + editor = null; + activeDiagramEditor = null; + + try { + if(hasRequiredViews()) { + closeRequiredViews(); + } + } finally { + super.finished(description); + } } } @@ -115,15 +185,23 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit TransactionalEditingDomain result = null; if(editor != null) { - try { - result = getServiceRegistry().getService(TransactionalEditingDomain.class); - } catch (ServiceException e) { - e.printStackTrace(); - fail("Failed to get editing domain from Papyrus editor: " + e.getLocalizedMessage()); - } + result = getEditingDomain(editor); } + return result; + } + + public TransactionalEditingDomain getEditingDomain(IMultiDiagramEditor editor) { + TransactionalEditingDomain result = null; + try { + result = getServiceRegistry(editor).getService(TransactionalEditingDomain.class); + } catch (ServiceException e) { + e.printStackTrace(); + fail("Failed to get editing domain from Papyrus editor: " + e.getLocalizedMessage()); + } + + return result; } @Override @@ -133,11 +211,14 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit } protected IMultiDiagramEditor open(final IFile modelFile) { + final boolean firstEditor = editorsToClose.isEmpty(); + Display.getDefault().syncExec(new Runnable() { public void run() { try { editor = EditorUtils.openPapyrusEditor(modelFile); + editorsToClose.add(editor); } catch (Exception e) { e.printStackTrace(); fail("Failed to open Papyrus editor: " + e.getLocalizedMessage()); @@ -145,45 +226,63 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit } }); - final IWorkbenchPage page = editor.getSite().getPage(); - page.addPartListener(new IPartListener() { + if(firstEditor && !editorsToClose.isEmpty()) { + final IWorkbenchPage page = editor.getSite().getPage(); + page.addPartListener(new IPartListener() { + + public void partClosed(IWorkbenchPart part) { + editorsToClose.remove(part); + + if(part == editor) { + editor = null; + } - public void partClosed(IWorkbenchPart part) { - if(part == editor) { - editor = null; + if(editorsToClose.isEmpty()) { + page.removePartListener(this); + } } - page.removePartListener(this); - } - public void partOpened(IWorkbenchPart part) { - // Pass - } + public void partOpened(IWorkbenchPart part) { + // Pass + } - public void partDeactivated(IWorkbenchPart part) { - // Pass - } + public void partDeactivated(IWorkbenchPart part) { + // Pass + } - public void partBroughtToTop(IWorkbenchPart part) { - // Pass - } + public void partBroughtToTop(IWorkbenchPart part) { + // Pass + } - public void partActivated(IWorkbenchPart part) { - // Pass - } - }); + public void partActivated(IWorkbenchPart part) { + // Pass + } + }); + } flushDisplayEvents(); return editor; } - protected IMultiDiagramEditor open(Description description) { - IFile papyrusModel = getProject().getFile(initModelResource(description).getURI().trimFileExtension().appendFileExtension(DiModel.DI_FILE_EXTENSION)); + protected IMultiDiagramEditor openOne(Description description) { + IFile papyrusModel = getProject().getFile(Iterables.getOnlyElement(initModelResources(description)).getURI().trimFileExtension().appendFileExtension(DiModel.DI_FILE_EXTENSION)); return open(papyrusModel); } + protected Iterable<IMultiDiagramEditor> openAll(Description description) { + List<IMultiDiagramEditor> result = Lists.newArrayList(); + + for(Resource resource : initModelResources(description)) { + IFile papyrusModel = getProject().getFile(resource.getURI().trimFileExtension().appendFileExtension(DiModel.DI_FILE_EXTENSION)); + result.add(open(papyrusModel)); + } + + return result; + } + public IMultiDiagramEditor open() { - return open(testDescription); + return openOne(testDescription); } public IMultiDiagramEditor open(String resourcePath) { @@ -206,7 +305,12 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit } public void activate(IWorkbenchPart part) { - part.getSite().getPage().activate(part); + IWorkbenchPage page = part.getSite().getPage(); + + if(page.getActivePart() != part) { + page.activate(part); + flushDisplayEvents(); + } } public void close() { @@ -226,11 +330,9 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit Display.getDefault().syncExec(new Runnable() { public void run() { - IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - ModelExplorerPageBookView view; try { - view = (ModelExplorerPageBookView)activeWorkbenchWindow.getActivePage().showView(AbstractEditorTest.MODELEXPLORER_VIEW_ID); + view = (ModelExplorerPageBookView)getWorkbenchPage().showView(AbstractEditorTest.MODELEXPLORER_VIEW_ID); } catch (PartInitException e) { e.printStackTrace(); return; @@ -246,13 +348,30 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit return modelExplorer; } + protected final IWorkbenchPage getWorkbenchPage() { + IWorkbench bench = PlatformUI.getWorkbench(); + IWorkbenchWindow window = bench.getActiveWorkbenchWindow(); + if(window == null) { + window = bench.getWorkbenchWindows()[0]; + } + return window.getActivePage(); + } + public ServicesRegistry getServiceRegistry() { + return getServiceRegistry(editor); + } + + public ServicesRegistry getServiceRegistry(IMultiDiagramEditor editor) { return editor.getServicesRegistry(); } public ModelSet getModelSet() { + return getModelSet(editor); + } + + public ModelSet getModelSet(IMultiDiagramEditor editor) { try { - return getServiceRegistry().getService(ModelSet.class); + return getServiceRegistry(editor).getService(ModelSet.class); } catch (ServiceException e) { e.printStackTrace(); fail("Failed to get model set from Papyrus editor: " + e.getLocalizedMessage()); @@ -262,9 +381,14 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit @Override public Package getModel() { + return getModel(editor); + } + + public Package getModel(IMultiDiagramEditor editor) { Package result = null; - UmlModel uml = (UmlModel)getModelSet().getModel(UmlModel.MODEL_ID); + ModelSet modelSet = getModelSet(editor); + UmlModel uml = (UmlModel)modelSet.getModel(UmlModel.MODEL_ID); assertThat("No UML model present in resource set", uml.getResource(), notNullValue()); result = (Package)EcoreUtil.getObjectByType(uml.getResource().getContents(), UMLPackage.Literals.PACKAGE); @@ -274,8 +398,12 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit } public IPageManager getPageManager() { + return getPageManager(editor); + } + + public IPageManager getPageManager(IMultiDiagramEditor editor) { try { - return getServiceRegistry().getService(IPageManager.class); + return getServiceRegistry(editor).getService(IPageManager.class); } catch (ServiceException e) { e.printStackTrace(); fail("Failed to get page manager from Papyrus editor: " + e.getLocalizedMessage()); @@ -284,20 +412,67 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit } public PapyrusEditorFixture activateDiagram(String name) { - for(Diagram diagram : Iterables.filter(getPageManager().allPages(), Diagram.class)) { - if(name.equals(diagram.getName())) { - getPageManager().selectPage(diagram); - break; + return activateDiagram(editor, name); + } + + public PapyrusEditorFixture activateDiagram(IMultiDiagramEditor editor, final String name) { + activate(editor); + + final ISashWindowsContainer sashContainer = AdapterUtils.adapt(editor, ISashWindowsContainer.class, null); + final org.eclipse.papyrus.infra.core.sasheditor.editor.IPage[] select = { null }; + + sashContainer.visit(new IPageVisitor() { + + public void accept(IEditorPage page) { + if(name.equals(page.getPageTitle()) && (page.getIEditorPart() instanceof DiagramEditorWithFlyOutPalette)) { + select[0] = page; + activeDiagramEditor = (DiagramEditorWithFlyOutPalette)page.getIEditorPart(); + } + } + + public void accept(IComponentPage page) { + // Pass } + }); + + if(select[0] != null) { + sashContainer.selectPage(select[0]); + flushDisplayEvents(); } return this; } + public DiagramEditorWithFlyOutPalette getActiveDiagramEditor() { + DiagramEditorWithFlyOutPalette result = activeDiagramEditor; + + if(result == null) { + IEditorPart activeEditor = getWorkbenchPage().getActiveEditor(); + if(activeEditor instanceof IMultiDiagramEditor) { + activeEditor = ((IMultiDiagramEditor)activeEditor).getActiveEditor(); + if(activeEditor instanceof DiagramEditorWithFlyOutPalette) { + result = (DiagramEditorWithFlyOutPalette)activeEditor; + } + } + } + + assertThat("No diagram active", result, notNullValue()); + + return result; + } + public EditPart findEditPart(EObject modelElement) { - IEditorPart activeEditor = getEditor().getActiveEditor(); - assertThat("No diagram active", activeEditor, instanceOf(IDiagramWorkbenchPart.class)); - DiagramEditPart diagram = ((IDiagramWorkbenchPart)activeEditor).getDiagramEditPart(); + return findEditPart(getActiveDiagramEditor(), modelElement); + } + + public EditPart findEditPart(IMultiDiagramEditor editor, EObject modelElement) { + IEditorPart activeEditor = editor.getActiveEditor(); + assertThat("No diagram active", activeEditor, instanceOf(DiagramEditor.class)); + return findEditPart((DiagramEditor)activeEditor, modelElement); + } + + public EditPart findEditPart(IDiagramWorkbenchPart editor, EObject modelElement) { + DiagramEditPart diagram = editor.getDiagramEditPart(); return findEditPart(diagram, modelElement); } @@ -326,6 +501,49 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit return result; } + public EditPart findEditPart(String name, Class<? extends NamedElement> type) { + return findEditPart(getActiveDiagramEditor(), name, type); + } + + public EditPart findEditPart(IMultiDiagramEditor editor, String name, Class<? extends NamedElement> type) { + IEditorPart activeEditor = editor.getActiveEditor(); + assertThat("No diagram active", activeEditor, instanceOf(DiagramEditor.class)); + return findEditPart((DiagramEditor)activeEditor, name, type); + } + + public EditPart findEditPart(IDiagramWorkbenchPart editor, String name, Class<? extends NamedElement> type) { + EditPart result = null; + + for(Iterator<View> views = Iterators.filter(editor.getDiagram().eAllContents(), View.class); views.hasNext();) { + View next = views.next(); + EObject element = next.getElement(); + if(type.isInstance(element) && name.equals(type.cast(element).getName())) { + result = (EditPart)editor.getDiagramGraphicalViewer().getEditPartRegistry().get(next); + break; + } + } + + return result; + } + + public void select(EditPart editPart) { + editPart.getViewer().getSelectionManager().appendSelection(editPart); + } + + public PaletteViewer getPalette() { + return getPalette(getActiveDiagramEditor()); + } + + public PaletteViewer getPalette(IMultiDiagramEditor editor) { + IEditorPart activeEditor = editor.getActiveEditor(); + assertThat("No diagram active", activeEditor, instanceOf(DiagramEditor.class)); + return getPalette((DiagramEditor)activeEditor); + } + + public PaletteViewer getPalette(IDiagramWorkbenchPart editor) { + return editor.getDiagramEditPart().getViewer().getEditDomain().getPaletteViewer(); + } + public void flushDisplayEvents() { for(;;) { try { @@ -342,12 +560,12 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit public IViewPart getView(String id, boolean open) { IViewPart result = null; - IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + IWorkbenchPage wbPage = getWorkbenchPage(); try { - result = activeWorkbenchWindow.getActivePage().findView(id); + result = wbPage.findView(id); if((result == null) && open) { - result = activeWorkbenchWindow.getActivePage().showView(id); + result = wbPage.showView(id); } if(result != null) { @@ -363,4 +581,189 @@ public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEdit return result; } + + public void save(ISaveablePart part) { + if(part.isDirty()) { + try { + part.doSave(new NullProgressMonitor()); + } catch (Exception e) { + e.printStackTrace(); + fail("Failed to save editor/view: " + e.getLocalizedMessage()); + } finally { + // Must flush display events because some steps (e.g. dependent editor reload) + // are done asynchronously in a UI job + flushDisplayEvents(); + } + } + } + + public void saveAll() { + try { + IWorkbenchPage page = editor.getSite().getPage(); + page.saveAllEditors(false); + } finally { + // Must flush display events because some steps (e.g. dependent editor reload) + // are done asynchronously in a UI job + flushDisplayEvents(); + } + } + + public void splitEditorArea(IEditorPart editorToMove, boolean splitHorizontally) { + MPart editorPart = (MPart)editorToMove.getSite().getService(MPart.class); + EModelService modelService = editorPart.getContext().get(EModelService.class); + MPartStack oldStack = (MPartStack)modelService.getContainer(editorPart); + MPartStack newStack = modelService.createModelElement(MPartStack.class); + modelService.insert(newStack, oldStack, splitHorizontally ? EModelService.RIGHT_OF : EModelService.BELOW, 0.5f); + newStack.getChildren().add(editorPart); + + activate(editorToMove); + } + + public List<IWorkbenchPart> getPartStack(IWorkbenchPart part) { + List<IWorkbenchPart> result; + + MPart mpart = (MPart)part.getSite().getService(MPart.class); + EModelService modelService = mpart.getContext().get(EModelService.class); + MPartStack stack = (MPartStack)modelService.getContainer(mpart); + + result = Lists.newArrayListWithCapacity(stack.getChildren().size()); + for(MPart next : Iterables.filter(stack.getChildren(), MPart.class)) { + IWorkbenchPart wbPart = next.getContext().get(IWorkbenchPart.class); + if(wbPart != null) { + result.add(wbPart); + } + } + + return result; + } + + protected final boolean hasRequiredViews() { + return getRequiredViews() != null; + } + + protected final ShowView getRequiredViews() { + ShowView result = testDescription.getAnnotation(ShowView.class); + + if(result == null) { + for(Class<?> clazz = testClass; (result == null) && (clazz != null) && (clazz != Object.class); clazz = clazz.getSuperclass()) { + result = clazz.getAnnotation(ShowView.class); + } + } + + return result; + } + + protected void openRequiredViews() { + IWorkbenchPage page = getWorkbenchPage(); + + for(ShowViewDescriptor next : ShowViewDescriptor.getDescriptors(getRequiredViews())) { + IViewPart part = page.findView(next.viewID()); + if(part == null) { + // Must open it + try { + part = page.showView(next.viewID()); + movePartRelativeTo(part, next.relativeTo(), next.location()); + + if(viewsToClose == null) { + viewsToClose = Lists.newArrayListWithExpectedSize(1); + } + viewsToClose.add(part); + } catch (PartInitException e) { + e.printStackTrace(); + fail("Failed to open required view: " + e.getLocalizedMessage()); + } + } + } + + flushDisplayEvents(); + } + + private void movePartRelativeTo(IWorkbenchPart part, String relativeTo, int where) { + MPart mPart = (MPart)part.getSite().getService(MPart.class); + EModelService modelService = mPart.getContext().get(EModelService.class); + MUIElement relativePart = modelService.find(relativeTo, modelService.getTopLevelWindowFor(mPart)); + if(relativePart instanceof MPartSashContainerElement) { + MStackElement toMove = mPart; + MPlaceholder placeHolder = mPart.getCurSharedRef(); + if(placeHolder != null) { + toMove = placeHolder; + } + + if(where < 0) { + // Add it to the relative part's containing stack + if(relativePart instanceof MPart) { + MPart relativeMPart = (MPart)relativePart; + if(relativeMPart.getCurSharedRef() != null) { + // This is where the part is stacked + relativePart = relativeMPart.getCurSharedRef(); + } + } + relativePart.getParent().getChildren().add(toMove); + } else { + // Insert it next to the relative part + MPartStack newStack = modelService.createModelElement(MPartStack.class); + newStack.getChildren().add(toMove); + modelService.insert(newStack, (MPartSashContainerElement)relativePart, where, 0.3f); + } + } + } + + protected void closeRequiredViews() { + // Only close the Palette view if we opened it + if(viewsToClose != null) { + for(IViewPart closeMe : viewsToClose) { + closeMe.getSite().getPage().hideView(closeMe); + } + viewsToClose = null; + flushDisplayEvents(); + } + } + + private static final class ShowViewDescriptor { + + private static final String DEFAULT_RELATIVE_TO = "org.eclipse.ui.editorss"; //$NON-NLS-1$ + + private static final ShowView.Location DEFAULT_LOCATION_EDITORS = ShowView.Location.RIGHT; + + private static final ShowView.Location DEFAULT_LOCATION_VIEW = ShowView.Location.STACKED; + + private final String viewID; + + private final String relativeTo; + + private final ShowView.Location location; + + private ShowViewDescriptor(ShowView annotation, int index) { + this.viewID = annotation.value()[index]; + + String[] relativeTo = annotation.relativeTo(); + this.relativeTo = (relativeTo.length == 0) ? null : (relativeTo.length == 1) ? relativeTo[0] : relativeTo[index]; + + ShowView.Location[] location = annotation.location(); + this.location = (location.length == 0) ? null : (location.length == 1) ? location[0] : location[index]; + } + + static Iterable<ShowViewDescriptor> getDescriptors(final ShowView annotation) { + ImmutableList.Builder<ShowViewDescriptor> result = ImmutableList.builder(); + + String[] ids = annotation.value(); + for(int i = 0; i < ids.length; i++) { + result.add(new ShowViewDescriptor(annotation, i)); + } + + return result.build(); + } + + String viewID() { + return viewID; + } + + String relativeTo() { + return (relativeTo != null) ? relativeTo : DEFAULT_RELATIVE_TO; + } + + int location() { + return ((location != null) ? location : (relativeTo == null) ? DEFAULT_LOCATION_EDITORS : DEFAULT_LOCATION_VIEW).toModelServiceLocation(); + } + } } diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java index dc1e7e6eacd..aba01b2b74e 100644 --- a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java @@ -19,7 +19,7 @@ import java.lang.annotation.Target; /** - * Annotation indicating the bundle-relative path to a resource from which to load the test model of an {@link AbstractModelFixture}. + * Annotation indicating the bundle-relative path to one or more resources from which to load the test model of an {@link AbstractModelFixture}. * * @see AbstractModelFixture * @see JavaResource @@ -28,5 +28,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface PluginResource { - String value(); + String[] value(); } diff --git a/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowView.java b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowView.java new file mode 100644 index 00000000000..103db0b1d37 --- /dev/null +++ b/tests/junit/plugins/junit/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowView.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.junit.utils.rules; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.eclipse.e4.ui.workbench.modeling.EModelService; + + +/** + * An annotation on tests using the {@link PapyrusEditorFixture} that need the palette view to be open before initializing the + * test (which generally entails opening one or more editors). + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ShowView { + + /** The IDs of the views to show before the editor is opened. */ + String[] value(); + + /** + * The IDs of workbench parts relative to which the views specified by the annotation are to be shown. If unspecified, + * the default is the workbench's editor area. If exactly part ID is specified, it is used for all views. Otherwise, a + * corresponding value is required for each view ID to be shown. + */ + String[] relativeTo() default {}; + + /** + * The relative locations of the views to show. If unspecified, the default is {@link Location#STACKED} when the {@linkplain #relativeTo() + * relative part} is a view, otherwise {@link Location#RIGHT} when the relative part is the editor area. + * If exactly one value is specified, it is used for all views. Otherwise, a corresponding value is + * required for each view ID. + */ + Location[] location() default {}; + + /** + * Enumeration of locations in which to open a view relative to some other workbench part. + */ + enum Location { + /** Stacked with the relative part. */ + STACKED(-1), + /** To the left of the relative part. */ + LEFT(EModelService.LEFT_OF), + /** To the right of the relative part. */ + RIGHT(EModelService.RIGHT_OF), + /** Above the relative part. */ + ABOVE(EModelService.ABOVE), + /** Below the relative part. */ + BELOW(EModelService.BELOW); + + private final int modelServiceLocation; + + private Location(int modelServiceLocation) { + this.modelServiceLocation = modelServiceLocation; + } + + public int toModelServiceLocation() { + return modelServiceLocation; + } + } +} |