Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcdumoulin2009-04-21 14:07:57 +0000
committercdumoulin2009-04-21 14:07:57 +0000
commit6fbf546117397919154b4d9f9a61835ddf0b6e90 (patch)
tree0aac9e271afcaa7cc672b32176cf62e79c154eb5
parent4f46b40cc6a84ac4bbd93885607bd8168a542fd7 (diff)
downloadorg.eclipse.papyrus-6fbf546117397919154b4d9f9a61835ddf0b6e90.tar.gz
org.eclipse.papyrus-6fbf546117397919154b4d9f9a61835ddf0b6e90.tar.xz
org.eclipse.papyrus-6fbf546117397919154b4d9f9a61835ddf0b6e90.zip
NEW - bug 268775: [Sash Editor] Improve and finalize plugin
https://bugs.eclipse.org/bugs/show_bug.cgi?id=268775 First attempt to refactor the sasheditor. Create a new src2 repository containing the new version. This src2 will be renamed to src later. The new sources are not used yet in Papyrus. There is two examples plugins.
-rw-r--r--org.eclipse.papyrus.sasheditor/.classpath2
-rw-r--r--org.eclipse.papyrus.sasheditor/META-INF/MANIFEST.MF7
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IAbstractPanelModel.java15
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IComponentModel.java22
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IContentChangedListener.java76
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IEditorModel.java31
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IPageModel.java38
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ISashPanelModel.java34
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ISashWindowsContentProvider.java109
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ITabFolderModel.java30
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/AbstractModel.java43
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/AbstractPanelModel.java64
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/RootModel.java82
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/SashPanelModel.java160
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/SimpleSashWindowsContentProvider.java416
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/TabFolderModel.java227
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/singlefolder/SingleFolderContentProvider.java234
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/singlefolder/SingleFolderModel.java133
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/AbstractMultiPageSashEditor.java170
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/IMultiPageEditorActionBarContributor.java40
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/IMultiPageEditorPart.java45
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/MultiPageEditorActionBarContributor.java63
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/AbstractPanelPart.java139
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/AbstractPart.java85
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ActiveEditorAndPageTracker.java238
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ActivePageTracker.java138
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ComponentPart.java396
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/Copyright.java23
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/EditorPart.java547
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IMultiEditorManager.java67
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IPanelParent.java40
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IPartVisitor.java62
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ImageToolTipManager.java281
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/NotFoundException.java61
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PTabFolder.java572
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PagePart.java153
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PartLists.java104
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PartVisitor.java130
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ReplaceableSashForm.java71
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/RootPart.java307
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashPanelPart.java481
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashWindowsContainer.java554
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashWindowsException.java56
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ShowPartStatusVisitor.java112
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/TabFolderPart.java1041
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/TabItemPart.java280
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/AbstractTabFolderPart.java510
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/MultiPageEditorSite.java551
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/MultiPageSelectionProvider.java169
-rw-r--r--org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/multipage/editor/MultiPageEditor.java292
-rw-r--r--org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/contentprovider/simple/FakePageModel.java63
-rw-r--r--org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/contentprovider/simple/SimpleSashWindowsContentProviderTest.java172
-rw-r--r--org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/CompareTreeVisitor.java224
-rw-r--r--org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/MessagePartModel.java80
-rw-r--r--org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/SashMultiPageEditorTest.java21
-rw-r--r--org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/ShellEditor.java116
56 files changed, 10176 insertions, 1 deletions
diff --git a/org.eclipse.papyrus.sasheditor/.classpath b/org.eclipse.papyrus.sasheditor/.classpath
index 2d1a4302f04..69cfad4a8c6 100644
--- a/org.eclipse.papyrus.sasheditor/.classpath
+++ b/org.eclipse.papyrus.sasheditor/.classpath
@@ -3,5 +3,7 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="src2"/>
+ <classpathentry kind="src" path="test"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/org.eclipse.papyrus.sasheditor/META-INF/MANIFEST.MF b/org.eclipse.papyrus.sasheditor/META-INF/MANIFEST.MF
index 954f3dba714..b0e9b99ca64 100644
--- a/org.eclipse.papyrus.sasheditor/META-INF/MANIFEST.MF
+++ b/org.eclipse.papyrus.sasheditor/META-INF/MANIFEST.MF
@@ -7,13 +7,18 @@ Bundle-ClassPath: .
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.papyrus.sasheditor,
+ org.eclipse.papyrus.sasheditor.contentprovider,
+ org.eclipse.papyrus.sasheditor.contentprovider.simple,
org.eclipse.papyrus.sasheditor.eclipsecopy,
+ org.eclipse.papyrus.sasheditor.editor,
org.eclipse.papyrus.sasheditor.extension,
org.eclipse.papyrus.sasheditor.gef,
+ org.eclipse.papyrus.sasheditor.multipage.editor,
org.eclipse.papyrus.sasheditor.sash
Bundle-ActivationPolicy: lazy
Bundle-Activator: org.eclipse.papyrus.sasheditor.Activator
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
- org.eclipse.gef
+ org.eclipse.gef,
+ org.junit
Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IAbstractPanelModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IAbstractPanelModel.java
new file mode 100644
index 00000000000..563c1820bd6
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IAbstractPanelModel.java
@@ -0,0 +1,15 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.sasheditor.contentprovider;
+
+/**
+ * A Panel represent a SashPanel or a TabFolder.
+ * This interface is the common ancestor of the Panel models used in sash system.
+ * @author dumoulin
+ *
+ */
+public abstract interface IAbstractPanelModel {
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IComponentModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IComponentModel.java
new file mode 100644
index 00000000000..4010b822047
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IComponentModel.java
@@ -0,0 +1,22 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.sasheditor.contentprovider;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * This model represent a ui Component to be shown in a sash window folder.
+ * @author dumoulin
+ *
+ */
+public interface IComponentModel extends IPageModel {
+
+ /**
+ * Create the Control corresponding to this model.
+ * @param parent The parent of the created container.
+ * @return
+ */
+ public Composite createPartControl(Composite parent);
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IContentChangedListener.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IContentChangedListener.java
new file mode 100644
index 00000000000..e8649d55fd9
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IContentChangedListener.java
@@ -0,0 +1,76 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.sasheditor.contentprovider;
+
+
+/**
+ * Interface to be implemented by classes needing to be notified
+ * when the SashContent model has changed.
+ * This interface is not used by the sashesWindows itself. It exists to allows ContentProvider
+ * implementation to provide a common notification mechanism.
+ *
+ * @author dumoulin
+ */
+public interface IContentChangedListener {
+
+ /**
+ * Event indicating the change.
+ * @author dumoulin
+ */
+ public class ContentEvent {
+
+ public static final int ADDED = 0;
+ public static final int REMOVED = 1;
+ public static final int CHANGED = 2;
+ public static final int MOVED = 3;
+
+ /** type of event */
+ private int type;
+ /** model to which the event apply */
+ private Object model;
+ /** object added or removed or modified */
+ private Object object;
+
+ /**
+ * @param type
+ * @param model
+ * @param object
+ */
+ public ContentEvent(int type, Object model, Object object) {
+ this.type = type;
+ this.model = model;
+ this.object = object;
+ }
+
+
+ /**
+ * @return the type
+ */
+ public int getType() {
+ return type;
+ }
+
+
+ /**
+ * @return the model
+ */
+ public Object getModel() {
+ return model;
+ }
+
+
+ /**
+ * @return the object
+ */
+ public Object getObject() {
+ return object;
+ }
+
+ }
+
+ /**
+ * Method called when the content has changed.
+ */
+ public void contentChanged(ContentEvent event);
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IEditorModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IEditorModel.java
new file mode 100644
index 00000000000..0834136a9ce
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IEditorModel.java
@@ -0,0 +1,31 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.sasheditor.contentprovider;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * This model indicate that an Editor should be drawn in the sash window folder.
+ * @author dumoulin
+ *
+ */
+public interface IEditorModel extends IPageModel {
+
+ /**
+ * Create the IEditor that should be shown.
+ * Editor life cycle methods are not called.
+ * @return A new instance of the IEditor.
+ */
+ public IEditorPart createIEditorPart() throws PartInitException;
+
+ /**
+ * Get the EditorActionBarContributor that should be associated with the editor .
+ *
+ * @return
+ */
+ public EditorActionBarContributor getActionBarContributor();
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IPageModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IPageModel.java
new file mode 100644
index 00000000000..43bd1e273d0
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/IPageModel.java
@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.sasheditor.contentprovider;
+
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * This interface is the root of the hierarchy of models representing Pages.
+ * This represent the final element shown in the sashes window.
+ * It can be an Editor or a simple control.
+ * This interface is used by the sashes window to interact with the model describing the element to be
+ * shown in the TabItem.
+ * @author dumoulin
+ *
+ */
+public abstract interface IPageModel {
+
+ /**
+ * Get the title to be shown in the tab
+ * @return
+ */
+ public String getTabTitle();
+
+ /**
+ * Get the icon to be shown in the tab
+ * @return
+ */
+ public Image getTabIcon();
+
+ /**
+ * Get the raw model corresponding to this node.
+ * This is the object provided to {@link ITabFolderModel.getChildren()}
+ * @return
+ */
+ public Object getRawModel();
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ISashPanelModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ISashPanelModel.java
new file mode 100644
index 00000000000..166e73bfc77
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ISashPanelModel.java
@@ -0,0 +1,34 @@
+package org.eclipse.papyrus.sasheditor.contentprovider;
+
+import java.util.List;
+
+/**
+ * A sash node contains two children separated by a sash. The sash can be moved, resizing the children.
+ * This interface is used to specify that a sash with two children should be drawn.
+ * @author dumoulin
+ *
+ */
+public interface ISashPanelModel extends IAbstractPanelModel {
+
+ /**
+ * Get the list of children that should be displayed in the folder.
+ * @return
+ */
+ public List<?> getChildren();
+
+ /**
+ * Create the Interface used to access the real model.
+ * This method is called by the sashes window to get the interface.
+ * The method is called only once for a given object.
+ *
+ * @param child A child returned by getChildren().
+ * @return
+ */
+ public IAbstractPanelModel createChildSashModel( Object child);
+
+ /**
+ * Get the sash direction. Can be SWT.VERTICAL or SWT.HORIZONTAL.
+ */
+ public int getSashDirection();
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ISashWindowsContentProvider.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ISashWindowsContentProvider.java
new file mode 100644
index 00000000000..db4bde6901a
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ISashWindowsContentProvider.java
@@ -0,0 +1,109 @@
+package org.eclipse.papyrus.sasheditor.contentprovider;
+
+/**
+ * This interface is used by the sash windows system to discover its content. It is considered
+ * as the root of the sash windows models.
+ * The sashsystem is able to retrieve all its content from this interface, and associated interfaces
+ * {@link ITabFolderModel}, {@link ISashPanelModel}, {@link IPageModel}.
+ * The interface is also used by the sashsystem to communicate, by sending event, with the
+ * effective implementation or upper level.
+ * @author dumoulin
+ *
+ */
+public interface ISashWindowsContentProvider {
+
+ /**
+ * Get the root object shown in the sashes window.
+ * The type of the returned object is left to the implementation.
+ * The sashes window will ask for an interface used to interact with the object.
+ * In normal implementation, this method should return the model used by the implementation.
+ * @return The object representing the root of the sashes window.
+ */
+ public Object getRootModel();
+
+ /**
+ * create the interface used by the sashes window to access the root model.
+ * This method is called by the sashes window to get the interface.
+ * The method is called only once for a given object.
+ * @param root
+ * @return
+ */
+ public IAbstractPanelModel createChildSashModel( Object root );
+
+ /**
+ * Add a Page to the current TabFolder.
+ * The Page is added at the end of the tab list.
+ * @param tabItem TabItem to add
+ */
+ public void addPage( IPageModel tabItem );
+
+ /**
+ * Move a tab inside the specified folder.
+ * @param model
+ * @param oldIndex
+ * @param newIndex
+ */
+ public void movePage(ITabFolderModel folderModel, int oldIndex, int newIndex);
+
+ /**
+ * Move a tab from folder to folder.
+ * @param model
+ * @param sourceIndex
+ * @param model2
+ * @param targetIndex
+ */
+ public void movePage(ITabFolderModel srcFolderModel, int sourceIndex, ITabFolderModel targetFolderModel, int targetIndex);
+
+ /**
+ * Add a page to the current TabFolder.
+ * The page is added at the end of the page list.
+ * @param index Index to where the tabItem should be added.
+ * @param tabItem TabItem to add
+ */
+ public void addPage( int index, IPageModel tabItem );
+
+ /**
+ * Remove the page at the specified index of the current tabFolder
+ * @param index
+ */
+ public IPageModel removePage(int index);
+
+ /**
+ * Remove the page from the sashes window.
+ * Look for the folder containing the page.
+ *
+ * @param tabItem
+ */
+ public void removePage(IPageModel tabItem);
+
+ /**
+ * Remove the specified page from the parentFolder.
+ *
+ * @param tabItem
+ */
+ public void removePage(ITabFolderModel parentFolder, int tabIndex);
+
+ /**
+ * Ask the model to move the specified tab to the specified side of the specified targetFolder.
+ * This method
+ * is called by the the SashTileContainer when the user
+ * have drag a tab in a correct place. The SashTileContainer has not change is presentation yet. This
+ * will be done when the corresponding event will occur.
+ *
+ * @param tabFolder The folder containing the tab to move
+ * @param tabIndex The index of the tab to move
+ * @param targetFolder The folder to which the side refer to
+ * @param side Side where node should be inserted : SWT.LEFT, SWT.RIGHT, SWT.TOP, SWT.DOWN.
+ */
+ public ITabFolderModel createFolder(ITabFolderModel tabFolder, int tabIndex, ITabFolderModel targetFolder, int side);
+
+ /**
+ * Get the current tabFolder.
+ * TODO Check if this method is really needed from sasheditor. If not, move it away.
+ * It is needed by MultiPageEditor.
+ * @return
+ */
+ public ITabFolderModel getCurrentTabFolder();
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ITabFolderModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ITabFolderModel.java
new file mode 100644
index 00000000000..1e13b04a739
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/ITabFolderModel.java
@@ -0,0 +1,30 @@
+package org.eclipse.papyrus.sasheditor.contentprovider;
+
+import java.util.List;
+
+/**
+ * A folder containing tabItem.
+ * This interface is used to specify that a TabFolder should be drawn.
+ * @author dumoulin
+ *
+ * @param <ChildType> Type of the children of the folder. This is the type returned by
+ * getChildren().
+ */
+public interface ITabFolderModel extends IAbstractPanelModel {
+
+ /**
+ * Get the list of children that should be displayed in the folder.
+ * @return
+ */
+ public List<?> getChildren();
+
+ /**
+ * Create the Interface used to access the real model.
+ * This method is called by the sashes window to get the interface.
+ * The method is called only once for a given object.
+ *
+ * @param child A child returned by getChildren().
+ * @return
+ */
+ public IPageModel createChildSashModel( Object child);
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/AbstractModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/AbstractModel.java
new file mode 100644
index 00000000000..2c7d7488e7a
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/AbstractModel.java
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.simple;
+
+
+/**
+ * @author dumoulin
+ */
+public abstract class AbstractModel {
+
+
+ /**
+ * Return the parent of the model. Can be null in the case of rootModel.
+ * @return the parent
+ */
+ abstract public AbstractModel getParent() ;
+
+
+ /**
+ * @param parent the parent to set
+ */
+ abstract public void setParent(AbstractModel parent);
+
+ /**
+ * Replace the oldChild by the newChild
+ *
+ * @param oldChild
+ * @param newChild
+ */
+ abstract public void replaceChild(AbstractPanelModel oldChild, AbstractPanelModel newChild) ;
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/AbstractPanelModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/AbstractPanelModel.java
new file mode 100644
index 00000000000..90e56019b47
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/AbstractPanelModel.java
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.simple;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IAbstractPanelModel;
+
+
+/**
+ * @author dumoulin
+ */
+public abstract class AbstractPanelModel extends AbstractModel implements IAbstractPanelModel {
+
+ /**
+ * Parent of the model. Can be null in the case of rootModel.
+ */
+ protected AbstractModel parent;
+
+ /**
+ * Constructor.
+ * @param parent2
+ */
+ public AbstractPanelModel(AbstractModel parent) {
+ this.parent = parent;
+ }
+
+
+ /**
+ * Return the parent of the model. Can be null in the case of rootModel.
+ * @return the parent
+ */
+ public AbstractModel getParent() {
+ return parent;
+ }
+
+
+ /**
+ * @param parent the parent to set
+ */
+ public void setParent(AbstractModel parent) {
+ this.parent = parent;
+ }
+
+
+ /**
+ * Lookup the folder containing the specified tabItem.
+ * @param tabItem
+ * @return
+ */
+ abstract protected TabFolderModel lookupTabFolder(IPageModel tabItem);
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/RootModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/RootModel.java
new file mode 100644
index 00000000000..dd4beb962c5
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/RootModel.java
@@ -0,0 +1,82 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.simple;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+
+
+/**
+ * @author dumoulin
+ */
+public class RootModel extends AbstractModel {
+
+ /**
+ * Child of this root model.
+ */
+ private AbstractPanelModel child;
+
+
+ /**
+ * Constructor.
+ * @param child
+ */
+ public RootModel(AbstractPanelModel child) {
+ this.child = child;
+ child.setParent(this);
+ }
+
+
+ /**
+ * Return the parent of the model. Can be null in the case of rootModel.
+ * @return the parent
+ */
+ public AbstractModel getParent() {
+ return null;
+ }
+
+
+ /**
+ * @param parent the parent to set
+ */
+ public void setParent(AbstractModel parent) {
+ }
+
+
+ /**
+ * Replace the actual child by the new child.
+ *
+ */
+ public void replaceChild(AbstractPanelModel oldChild, AbstractPanelModel newChild) {
+
+ assert(child == oldChild);
+ child = newChild;
+
+ }
+
+
+ /**
+ * Lookup the folder containing the specified tabItem.
+ * @param tabItem
+ * @return
+ */
+ protected TabFolderModel lookupTabFolder(IPageModel tabItem) {
+ return child.lookupTabFolder(tabItem);
+ }
+
+
+ protected AbstractPanelModel getChild() {
+ return child;
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/SashPanelModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/SashPanelModel.java
new file mode 100644
index 00000000000..96997dff8b1
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/SashPanelModel.java
@@ -0,0 +1,160 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.simple;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IAbstractPanelModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashPanelModel;
+
+
+/**
+ * Simple implementation of the {@link ISashPanelModel}.
+ * @author dumoulin
+ */
+public class SashPanelModel extends AbstractPanelModel implements ISashPanelModel {
+
+ /** Ordered set of childs (a left and right child, or upper and lower) */
+ protected AbstractPanelModel[] children = new AbstractPanelModel[2];
+ // The children array as a list
+ protected List<AbstractPanelModel> childrenList = Arrays.asList(children);
+
+ protected int sashDirection;
+
+
+
+ /**
+ * @param children
+ * @param sashDirection
+ */
+ public SashPanelModel(AbstractModel parent, AbstractPanelModel leftChild, AbstractPanelModel rightChild, int sashDirection) {
+ super(parent);
+ this.children[0] = leftChild;
+ this.children[1] = rightChild;
+
+ this.sashDirection = sashDirection;
+ }
+
+
+ /**
+ * Set the left child.
+ * @param child
+ */
+ public void setLeftChild(AbstractPanelModel child)
+ {
+ this.children[0] = child;
+ }
+
+ /**
+ * Get the left child
+ * @return
+ */
+ private AbstractPanelModel getLeftChild() {
+ return children[0];
+ }
+
+ /**
+ * Set the left child.
+ * @param child
+ */
+ public void setRightChild(AbstractPanelModel child)
+ {
+ this.children[1] = child;
+ }
+
+ /**
+ * Get the right child
+ * @return
+ */
+ private AbstractPanelModel getRightChild() {
+ return children[1];
+ }
+
+
+
+ /**
+ * Create the SashPanelModel from the raw model.
+ * In this implementation, the rawModel is the SashPanelModel.
+ * This default implementation return directly the child which is already of the appropriate type.
+ */
+ public IAbstractPanelModel createChildSashModel(Object rawModel) {
+ return (IAbstractPanelModel)rawModel;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<?> getChildren() {
+ return childrenList;
+ }
+
+ /**
+ * Return the direction of the sash:
+ *
+ */
+ public int getSashDirection() {
+ return sashDirection;
+ }
+
+ /**
+ * Replace specified child with the new child.
+ * {@inheritDoc}
+ */
+ public void replaceChild(AbstractPanelModel oldChild, AbstractPanelModel newChild) {
+
+
+ if(getLeftChild() == oldChild)
+ setLeftChild(newChild);
+ else if( getRightChild() == oldChild)
+ setRightChild(newChild);
+
+ }
+
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected TabFolderModel lookupTabFolder(IPageModel tabItem) {
+ TabFolderModel parent = getLeftChild().lookupTabFolder(tabItem);
+ if(parent != null)
+ return parent;
+
+ return getRightChild().lookupTabFolder(tabItem);
+ }
+
+
+ /**
+ * Delete the sashModel.
+ * The childToDelete is removed from the tree, bypass the sashnode : the other child parent is set to sashnode parent.
+ * @param tabFolder
+ */
+ protected void delete(AbstractPanelModel childToDelete) {
+
+ // Get the other child
+ AbstractPanelModel otherChild = (childToDelete==getLeftChild()?getRightChild():getLeftChild());
+
+ AbstractModel parent = getParent();
+ // Change parent
+ otherChild.setParent( parent );
+ parent.replaceChild(this, otherChild);
+
+
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/SimpleSashWindowsContentProvider.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/SimpleSashWindowsContentProvider.java
new file mode 100644
index 00000000000..43d98231823
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/SimpleSashWindowsContentProvider.java
@@ -0,0 +1,416 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.simple;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IContentChangedListener;
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.sasheditor.contentprovider.IAbstractPanelModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IContentChangedListener.ContentEvent;
+import org.eclipse.swt.SWT;
+
+/**
+ * A simple implementation of providers allowing sashes and folders.
+ * The tabs can be added and removed.
+ *
+ * @author dumoulin
+ *
+ */
+public class SimpleSashWindowsContentProvider implements ISashWindowsContentProvider {
+
+ /** The currently selected tab folder */
+ private TabFolderModel currentTabFolder;
+
+ /** The root model. */
+ private RootModel rootModel;
+
+ /** */
+ private ContentChangeListenerManager contentChangedListenerManager = new ContentChangeListenerManager();
+
+ /**
+ * Constructor.
+ */
+ public SimpleSashWindowsContentProvider() {
+
+ // Create a tree with one single folder
+ currentTabFolder = new TabFolderModel(this);
+ rootModel = new RootModel(currentTabFolder);
+ }
+
+
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ public void addContentChangedListener( IContentChangedListener listener)
+ {
+ contentChangedListenerManager.addContentChangedListener(listener);
+ }
+
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ public void removeContentChangedListener( IContentChangedListener listener)
+ {
+ contentChangedListenerManager.removeContentChangedListener(listener);
+ }
+
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ protected void firePropertyChanged( ContentEvent event)
+ {
+ contentChangedListenerManager.fireContentChanged(event);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public void addPage(IPageModel newModel) {
+ currentTabFolder.doAddItem(newModel);
+ firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, newModel) );
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public void addPage(int index, IPageModel newModel) {
+ currentTabFolder.doAddItem(index, newModel);
+ firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, newModel) );
+ }
+
+ /**
+ * Move a Page inside the folder.
+ * {@inheritDoc}
+ */
+ public void movePage(ITabFolderModel folderModel, int oldIndex, int newIndex) {
+ System.out.println("movePage()");
+ ((TabFolderModel)folderModel).moveTab(oldIndex, newIndex);
+
+ }
+
+ /**
+ * Move a tab from folder to folder.
+ * The change event is sent only once after the complete operation is performed.
+ * {@inheritDoc}
+ */
+ public void movePage(ITabFolderModel srcFolderModel, int sourceIndex, ITabFolderModel targetFolderModel, int targetIndex) {
+ // This implementation use (TabFolderModel), so we can cast safely
+ System.out.println("movePage()");
+ if(sourceIndex == -1)
+ {
+ moveAllPages(srcFolderModel, targetFolderModel);
+ return;
+ }
+ IPageModel movedTab = doMoveTab((TabFolderModel)srcFolderModel, sourceIndex, (TabFolderModel)targetFolderModel, targetIndex);
+ removeEmptyFolder((TabFolderModel)srcFolderModel);
+ doSetCurrentFolder(targetFolderModel);
+ contentChangedListenerManager.fireContentChanged(new ContentEvent(ContentEvent.MOVED, this, movedTab) );
+ }
+
+ /**
+ * Move all tabs from source to target
+ * @param srcFolderModel
+ * @param targetFolderModel
+ */
+ public void moveAllPages(ITabFolderModel srcFolderModel, ITabFolderModel targetFolderModel)
+ {
+ TabFolderModel srcFolder = (TabFolderModel)srcFolderModel;
+ TabFolderModel targetFolder = (TabFolderModel)targetFolderModel;
+ List<IPageModel> toMove = srcFolder.doRemoveAll();
+ targetFolder.doAddAllTab(toMove);
+ removeEmptyFolder((TabFolderModel)srcFolderModel);
+ doSetCurrentFolder(targetFolderModel);
+ contentChangedListenerManager.fireContentChanged(new ContentEvent(ContentEvent.MOVED, this, srcFolderModel) );
+ }
+
+ /**
+ * Set the Current Folder to the newCurrentFolder.
+ * @param targetFolderModel
+ */
+ private void doSetCurrentFolder(ITabFolderModel newCurrentFolder) {
+ currentTabFolder = (TabFolderModel)newCurrentFolder;
+ }
+
+ /**
+ * Create a new folder and insert it at the specified side.
+ * The change event is sent only once after the complete operation is performed.
+ * {@inheritDoc}
+ */
+ public ITabFolderModel createFolder(ITabFolderModel tabFolder, int tabIndex, ITabFolderModel targetFolder, int side) {
+ System.out.println("createFolder()");
+
+ ITabFolderModel newFolder = doCreateFolder((TabFolderModel)tabFolder, tabIndex, (TabFolderModel)targetFolder, side);
+ contentChangedListenerManager.fireContentChanged(new ContentEvent(ContentEvent.CHANGED, this, tabFolder) );
+ return newFolder;
+ }
+
+ /**
+ * Move a tab from folder to folder.
+ * The change event is sent only once after the complete operation is performed.
+ * @return The moved tab.
+ */
+ private IPageModel doMoveTab(TabFolderModel srcFolderModel, int sourceIndex, TabFolderModel targetFolderModel, int targetIndex) {
+
+ IPageModel tab = srcFolderModel.doRemoveTab(sourceIndex);
+ targetFolderModel.doAddItem(targetIndex, tab);
+ return tab;
+ }
+
+ /**
+ * Move a tab from folder to folder.
+ * The tab is added at the end of the target folder.
+ * The change event is sent only once after the complete operation is performed.
+ * {@inheritDoc}
+ */
+ private void doMoveTab(TabFolderModel srcFolderModel, int sourceIndex, TabFolderModel targetFolderModel) {
+
+ IPageModel tab = srcFolderModel.doRemoveTab(sourceIndex);
+ targetFolderModel.doAddItem(tab);
+ }
+
+ /**
+ * Create a new folder and insert it at the specified side.
+ *
+ */
+ private TabFolderModel doCreateFolder(TabFolderModel tabFolder, int tabIndex, TabFolderModel targetFolder, int side) {
+
+ // Create new folder. Parent will be set when inserted.
+ TabFolderModel newFolder = new TabFolderModel(this);
+ // Inset folder
+ doInsertFolder(newFolder, targetFolder, side);
+ // Move tab from folder to folder
+ doMoveTab(tabFolder, tabIndex, newFolder);
+ // Remove unused folder if necessary
+ removeEmptyFolder(tabFolder);
+ doSetCurrentFolder(targetFolder);
+
+ return newFolder;
+ }
+
+ /**
+ * Remove the folder if it is empty.
+ * @param tabFolder
+ */
+ private void removeEmptyFolder(TabFolderModel tabFolder) {
+ // Check if empty
+ if(tabFolder.getChildren().size() > 0)
+ return;
+
+ AbstractModel parent = tabFolder.getParent();
+ // Forbid removing of the last folder
+ if(parent == rootModel)
+ return;
+
+ // Parent is a sash. Ask it to remove the child and itself
+ ((SashPanelModel)parent).delete(tabFolder);
+ }
+
+ /**
+ * Insert the folderToInsert on the specified side of the refFolder. Create and insert the
+ * requested SashModel.
+ *
+ * @param folderToInsert
+ * @param refFolder
+ * @param side
+ */
+ private void doInsertFolder(TabFolderModel folderToInsert, TabFolderModel refFolder, int side)
+ {
+ // Get the parent under which the sash will be inserted
+ AbstractModel refParent = refFolder.getParent();
+ SashPanelModel newSash ;
+
+ int direction;
+ // Compute sash direction
+ if(side == SWT.LEFT || side == SWT.RIGHT)
+ direction = SWT.HORIZONTAL;
+ else
+ direction = SWT.VERTICAL;
+ // Create sash
+ if(side == SWT.LEFT || side == SWT.UP)
+ {
+ newSash = new SashPanelModel(refParent, folderToInsert, refFolder, direction);
+ }
+ else
+ {
+ newSash = new SashPanelModel(refParent, refFolder, folderToInsert, direction);
+ }
+
+ // Change sash childs parent
+ refFolder.setParent(newSash);
+ folderToInsert.setParent(newSash);
+
+ // Change sash parent
+ refParent.replaceChild(refFolder, newSash);
+ }
+
+ /**
+ * Get the root used as root to be shown in the editor.
+ * {@inheritDoc}
+ */
+ public IAbstractPanelModel getRootModel() {
+ return rootModel.getChild();
+ }
+
+ /**
+ * Create the interface used to access the rootModel
+ * {@inheritDoc}
+ */
+ public IAbstractPanelModel createChildSashModel(Object root) {
+ // The root object should be of type IAbstractPanelModel.
+ // This is normally the object returned by getRootPanel
+ return (IAbstractPanelModel)root;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public IPageModel removePage(int index) {
+ return currentTabFolder.removeTab(index);
+ }
+
+ /**
+ * Remove the specified tab from its parent.
+ * {@inheritDoc}
+ */
+ public void removePage(IPageModel tabItem) {
+
+ TabFolderModel folder = lookupPageFolder(tabItem);
+ if(folder != null)
+ folder.removeTab(tabItem);
+ }
+
+ /**
+ * Remove the tab at the specified index.
+ *
+ */
+ public void removePage(ITabFolderModel parentFolder, int tabIndex) {
+ TabFolderModel folder = (TabFolderModel)parentFolder;
+ IPageModel removed = folder.doRemoveTab(tabIndex);
+ removeEmptyFolder(folder);
+ doSetCurrentFolder(lookupPageFolder());
+ contentChangedListenerManager.fireContentChanged(new ContentEvent(ContentEvent.REMOVED, this, removed) );
+ }
+
+ /**
+ * Lookup the folder containing the specified tabItem.
+ * @param tabItem Item for which a folder is looked for. If the item is null, return
+ * the first folder encountered.
+ * @return The folder containing the item, or the first encountered folder if item is null.
+ */
+ private TabFolderModel lookupPageFolder(IPageModel tabItem) {
+ return rootModel.lookupTabFolder(tabItem);
+ }
+
+ /**
+ * Lookup for the first folder in the model.
+ * @return The first encountered folder.
+ */
+ private TabFolderModel lookupPageFolder() {
+ return rootModel.lookupTabFolder(null);
+ }
+
+ /**
+ * Get the parent of the specified tabItem, or null
+ * @param tabItem
+ * @return The parent tabFolder or null if not found.
+ */
+ public ITabFolderModel getParentFolder(IPageModel tabItem) {
+ return lookupPageFolder(tabItem);
+ }
+
+ /**
+ * Return the currently selected TabFolder.
+ * @return
+ */
+ public ITabFolderModel getCurrentTabFolder()
+ {
+ return currentTabFolder;
+ }
+
+ /**
+ * A class managing a list of listeners.
+ * @author dumoulin
+ */
+ protected class ContentChangeListenerManager {
+
+ private List<IContentChangedListener> listeners;
+
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ public void addContentChangedListener( IContentChangedListener listener)
+ {
+ if(listeners == null)
+ createListeners();
+
+ // Check if already exists.
+ if(listeners.contains(listener))
+ return;
+
+ listeners.add(listener);
+ }
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ public void removeContentChangedListener( IContentChangedListener listener)
+ {
+ if(listeners == null)
+ return;
+
+ listeners.remove(listener);
+ }
+
+ /**
+ * Create the list of listeners.
+ */
+ private void createListeners() {
+ if(listeners == null)
+ listeners = new ArrayList<IContentChangedListener>();
+
+ }
+
+ /**
+ * Fire the changed event.
+ * @param event
+ */
+ public void fireContentChanged(ContentEvent event)
+ {
+ if(listeners==null)
+ return;
+
+ for( IContentChangedListener listener : listeners)
+ {
+ listener.contentChanged(event);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/TabFolderModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/TabFolderModel.java
new file mode 100644
index 00000000000..629faf1c76b
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/simple/TabFolderModel.java
@@ -0,0 +1,227 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.simple;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IContentChangedListener.ContentEvent;
+
+/**
+ * Basic implementation allowing to add item to be shown.
+ * @author dumoulin
+ *
+ */
+public class TabFolderModel extends AbstractPanelModel implements ITabFolderModel {
+
+ /**
+ * List of items to be shown
+ */
+ private List<IPageModel> children = new ArrayList<IPageModel>();
+
+ /**
+ * The root of the sash models
+ */
+ private SimpleSashWindowsContentProvider contentProvider;
+ /**
+ * Constructor.
+ */
+ public TabFolderModel( SimpleSashWindowsContentProvider contentProvider) {
+ // Parent should be set later.
+ super(null);
+ this.contentProvider = contentProvider;
+ }
+
+ /**
+ *
+ */
+ public List<?> getChildren() {
+ return children;
+ }
+
+ /**
+ * This default implementation return directly the child which is already of the appropriate type.
+ */
+ public IPageModel createChildSashModel(Object child) {
+ // In this default implementation, the child is already of the appropriate type.
+ return (IPageModel)child;
+ }
+
+ /**
+ * Add a new model.
+ * @param newModel
+ */
+ private void addItem(IPageModel newModel)
+ {
+ doAddItem(newModel);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, newModel) );
+ }
+
+ /**
+ * Add a model at the specified position.
+ * @param index
+ * @param newModel
+ */
+ private void addItem(int index, IPageModel newModel) {
+ doAddItem(index, newModel);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, newModel) );
+ }
+
+ /**
+ * Remove the specified tab.
+ * @param index
+ * @return
+ */
+ public IPageModel removeTab(int index) {
+ IPageModel removed = doRemoveTab(index);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.REMOVED, this, removed) );
+ return removed;
+
+ }
+
+ /**
+ * Remove the specified tab.
+ * @param tabItem
+ */
+ public void removeTab(IPageModel tabItem) {
+ doRemoveTab(tabItem);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, tabItem) );
+ }
+
+ /**
+ * Move a tab inside the folder.
+ * Moves the tab from the old position to the new position.
+ *
+ * @param oldIndex the position of the tab before the move.
+ * @param newIndex the position of the tab after the move.
+ */
+ public void moveTab(int oldIndex, int newIndex) {
+ int listSize = children.size();
+ if (newIndex >= listSize)
+ {
+ newIndex = listSize-1;
+ }
+ if (newIndex < 0)
+ {
+ newIndex = 0;
+ }
+
+ if (oldIndex == newIndex)
+ return;
+
+ if( listSize == 0)
+ return;
+
+
+ // Move
+ IPageModel toMove = children.remove(oldIndex);
+ children.add(newIndex, toMove);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.MOVED, this, toMove) );
+ }
+
+ /**
+ * Add a new model.
+ * Do not fire change Event
+ * @param newModel
+ */
+ protected void doAddItem(IPageModel newModel)
+ {
+ children.add(newModel);
+ }
+
+ /**
+ * Add a model at the specified position.
+ * Do not fire change Event
+ * @param index
+ * @param newModel
+ */
+ protected void doAddItem(int index, IPageModel newModel) {
+ if( index > children.size() || index <0)
+ children.add(newModel);
+ else
+ children.add(index, newModel);
+ }
+
+ /**
+ * Remove the specified tab.
+ * Do not fire change Event
+ * @param index
+ * @return
+ */
+ protected IPageModel doRemoveTab(int index) {
+ IPageModel removed = children.remove(index);
+ return removed;
+
+ }
+
+ /**
+ * Remove all tabs from the folder.
+ * @return A list of removed tabs.
+ */
+ protected List<IPageModel> doRemoveAll()
+ {
+ List<IPageModel> removed = new ArrayList<IPageModel>(children);
+ children.clear();
+ return removed;
+ }
+
+ /**
+ * Add all tabs to the folder.
+ * @param newTabs
+ */
+ protected void doAddAllTab(List<IPageModel> newTabs)
+ {
+ children.addAll(newTabs);
+ }
+
+ /**
+ * Remove the specified tab.
+ * Do not fire change Event
+ * @param tabItem
+ */
+ protected void doRemoveTab(IPageModel tabItem) {
+ children.remove(tabItem);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, tabItem) );
+ }
+
+ /**
+ * Do nothing as this method should never be called on this class.
+ * {@inheritDoc}
+ */
+ @Override
+ public void replaceChild(AbstractPanelModel oldChild, AbstractPanelModel newChild) {
+ throw new UnsupportedOperationException("This method should not be called on this class.");
+ }
+
+ /**
+ * Get a folder by one of its tab.
+ * @param tabItem Item for which a folder is looked for. If the item is null, return
+ * the first folder encountered.
+ * @return The folder if it contains the item, or if item is null.
+ */
+ @Override
+ protected TabFolderModel lookupTabFolder(IPageModel tabItem) {
+
+ if(tabItem == null)
+ return this;
+
+ if(children.contains(tabItem))
+ return this;
+ // not found
+ return null;
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/singlefolder/SingleFolderContentProvider.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/singlefolder/SingleFolderContentProvider.java
new file mode 100644
index 00000000000..8d70728da3e
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/singlefolder/SingleFolderContentProvider.java
@@ -0,0 +1,234 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.singlefolder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IContentChangedListener;
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.sasheditor.contentprovider.IAbstractPanelModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IContentChangedListener.ContentEvent;
+
+/**
+ * A simple implementation of providers allowing only one single folder containing tabs.
+ * The tabs can be added and removed.
+ *
+ * @author dumoulin
+ */
+public class SingleFolderContentProvider implements ISashWindowsContentProvider {
+
+ /** The currently selected tab folder */
+ private SingleFolderModel currentTabFolder;
+
+ /** */
+ private ContentChangeListenerManager contentChangedListenerManager = new ContentChangeListenerManager();
+
+ /**
+ * Constructor.
+ */
+ public SingleFolderContentProvider() {
+ currentTabFolder = new SingleFolderModel(this);
+ }
+
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ public void addContentChangedListener( IContentChangedListener listener)
+ {
+ contentChangedListenerManager.addContentChangedListener(listener);
+ }
+
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ public void removeContentChangedListener( IContentChangedListener listener)
+ {
+ contentChangedListenerManager.removeContentChangedListener(listener);
+ }
+
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ protected void firePropertyChanged( ContentEvent event)
+ {
+ contentChangedListenerManager.fireContentChanged(event);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public void addPage(IPageModel newModel) {
+ currentTabFolder.addItem(newModel);
+
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public void addPage(int index, IPageModel newModel) {
+ currentTabFolder.addItem(index, newModel);
+ }
+
+ /**
+ * Do nothing because this implementation doesn't allows folders.
+ * {@inheritDoc}
+ */
+ public ITabFolderModel createFolder(ITabFolderModel tabFolder, int tabIndex, ITabFolderModel targetFolder, int side) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * Get the root used as root to be shown in the editor.
+ * {@inheritDoc}
+ */
+ public SingleFolderModel getRootModel() {
+ return currentTabFolder;
+ }
+
+ /**
+ * Create the interface used to access the rootModel.
+ * {@inheritDoc}
+ */
+ public IAbstractPanelModel createChildSashModel(Object root) {
+ // The root object should be of type IAbstractPanelModel.
+ // This is normally the object returned by getRootPanel
+ return (IAbstractPanelModel)root;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public IPageModel removePage(int index) {
+ return currentTabFolder.removeTab(index);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public void removePage(IPageModel tabItem) {
+ currentTabFolder.removeTab(tabItem);
+ }
+
+ /**
+ * Remove the specified tab. As we have only one folder, this should be from the currentFolder
+ * {@inheritDoc}
+ */
+ public void removePage(ITabFolderModel parentFolder, int tabIndex) {
+ removePage(tabIndex);
+ }
+
+ /**
+ * Return the currently selected TabFolder.
+ * @return
+ */
+ public ITabFolderModel getCurrentTabFolder()
+ {
+ return currentTabFolder;
+ }
+
+ /**
+ * A class managing a list of listeners.
+ * @author dumoulin
+ */
+ protected class ContentChangeListenerManager {
+
+ private List<IContentChangedListener> listeners;
+
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ public void addContentChangedListener( IContentChangedListener listener)
+ {
+ if(listeners == null)
+ createListeners();
+
+ // Check if already exists.
+ if(listeners.contains(listener))
+ return;
+
+ listeners.add(listener);
+ }
+ /**
+ * Add a listener listening on content changed. This listener will be
+ * notified each time the content change.
+ * @param listener
+ */
+ public void removeContentChangedListener( IContentChangedListener listener)
+ {
+ if(listeners == null)
+ return;
+
+ listeners.remove(listener);
+ }
+
+ /**
+ * Create the list of listeners.
+ */
+ private void createListeners() {
+ if(listeners == null)
+ listeners = new ArrayList<IContentChangedListener>();
+
+ }
+
+ /**
+ * Fire the changed event.
+ * @param event
+ */
+ public void fireContentChanged(ContentEvent event)
+ {
+ if(listeners==null)
+ return;
+
+ for( IContentChangedListener listener : listeners)
+ {
+ listener.contentChanged(event);
+ }
+ }
+ }
+
+ /**
+ * Move a tab inside the folder.
+ * {@inheritDoc}
+ */
+ public void movePage(ITabFolderModel folderModel, int oldIndex, int newIndex) {
+ currentTabFolder.moveTab(oldIndex, newIndex);
+
+ }
+
+ /**
+ * Move a tab from folder to folder.
+ * As this implementation has only one folder, this can't happen. Do nothing.
+ * {@inheritDoc}
+ */
+ public void movePage(ITabFolderModel srcFolderModel, int sourceIndex, ITabFolderModel targetFolderModel, int targetIndex) {
+ return;
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/singlefolder/SingleFolderModel.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/singlefolder/SingleFolderModel.java
new file mode 100644
index 00000000000..d3900643904
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/contentprovider/singlefolder/SingleFolderModel.java
@@ -0,0 +1,133 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.singlefolder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IContentChangedListener.ContentEvent;
+
+/**
+ * Basic implementation allowing to add item to be shown.
+ * @author dumoulin
+ *
+ */
+public class SingleFolderModel implements ITabFolderModel {
+
+ /**
+ * List of items to be shown
+ */
+ private List<IPageModel> itemModels = new ArrayList<IPageModel>();
+
+ /**
+ * The root of the sash models
+ */
+ private SingleFolderContentProvider contentProvider;
+ /**
+ * Constructor.
+ */
+ public SingleFolderModel( SingleFolderContentProvider contentProvider) {
+ this.contentProvider = contentProvider;
+ }
+
+ /**
+ *
+ */
+ public List<?> getChildren() {
+ return itemModels;
+ }
+
+ /**
+ * This default implementation return directly the child which is already of the appropriate type.
+ */
+ public IPageModel createChildSashModel(Object child) {
+ // In this default implementation, the child is already of the appropriate type.
+ return (IPageModel)child;
+ }
+
+ /**
+ * Add a new model.
+ * @param newModel
+ */
+ public void addItem(IPageModel newModel)
+ {
+ itemModels.add(newModel);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, newModel) );
+ }
+
+ /**
+ * Add a model at the specified position.
+ * @param index
+ * @param newModel
+ */
+ public void addItem(int index, IPageModel newModel) {
+ itemModels.add(index, newModel);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, newModel) );
+ }
+
+ /**
+ * Remove the specified tab.
+ * @param index
+ * @return
+ */
+ public IPageModel removeTab(int index) {
+ IPageModel removed = itemModels.remove(index);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, removed) );
+ return removed;
+
+ }
+
+ /**
+ * Remove the specified tab.
+ * @param tabItem
+ */
+ public void removeTab(IPageModel tabItem) {
+ itemModels.remove(tabItem);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.ADDED, this, tabItem) );
+ }
+
+ /**
+ * Move a tab inside the folder.
+ * Moves the tab from the old position to the new position.
+ *
+ * @param oldIndex the position of the tab before the move.
+ * @param newIndex the position of the tab after the move.
+ */
+ public void moveTab(int oldIndex, int newIndex) {
+
+ int listSize = itemModels.size();
+ if (newIndex >= listSize)
+ {
+ newIndex = listSize-1;
+ }
+ if (newIndex < 0)
+ {
+ newIndex = 0;
+ }
+
+ if (oldIndex == newIndex)
+ return;
+
+ if( listSize == 0)
+ return;
+
+
+ // Move
+ IPageModel toMove = itemModels.remove(oldIndex);
+ itemModels.add(newIndex, toMove);
+ contentProvider.firePropertyChanged(new ContentEvent(ContentEvent.MOVED, this, toMove) );
+ }
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/AbstractMultiPageSashEditor.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/AbstractMultiPageSashEditor.java
new file mode 100644
index 00000000000..23343d5f3f9
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/AbstractMultiPageSashEditor.java
@@ -0,0 +1,170 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.editor;
+
+import java.util.logging.Logger;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.sasheditor.eclipsecopy.IMultiPageEditorPart;
+import org.eclipse.papyrus.sasheditor.eclipsecopy.MultiPageSelectionProvider;
+import org.eclipse.papyrus.sasheditor.internal.IMultiEditorManager;
+import org.eclipse.papyrus.sasheditor.internal.SashWindowsContainer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.part.EditorPart;
+
+/**
+ * Base editor that can be subclassed to provide a multi page editor with sash windows.
+ *
+ * @author dumoulin
+ */
+public abstract class AbstractMultiPageSashEditor extends EditorPart implements IMultiPageEditorPart, IMultiEditorManager {
+
+ /** Log object */
+ protected Logger log = Logger.getLogger(getClass().getName());
+
+ /** The pageProvider */
+ private ISashWindowsContentProvider pageProvider;
+
+ /** The sash windows system :-) */
+ private SashWindowsContainer sashContainer;
+
+ /**
+ * get the contentProvider. Create it if necessary.
+ *
+ * @return
+ */
+ protected ISashWindowsContentProvider getContentProvider() {
+ if (pageProvider == null)
+ pageProvider = createPageProvider();
+
+ return pageProvider;
+ }
+
+ /**
+ * Create the provider.
+ * Subclass must implements this method. It should return the provider used by the editor.
+ *
+ */
+ abstract protected ISashWindowsContentProvider createPageProvider();
+
+ /**
+ * Handles a property change notification from a nested editor. The default implementation simply forwards the change to
+ * listeners on this multi-page editor by calling <code>firePropertyChange</code> with the same property id. For example, if
+ * the dirty state of a nested editor changes (property id <code>IEditorPart.PROP_DIRTY</code>), this method handles it
+ * by firing a property change event for <code>IEditorPart.PROP_DIRTY</code> to property listeners on this multi-page
+ * editor.
+ * <p>
+ * Subclasses may extend or reimplement this method.
+ * </p>
+ *
+ * @copiedfrom org.eclipse.ui.part.MultiPageEditorPart.handlePropertyChange(int)
+ *
+ * @param propertyId
+ * the id of the property that changed
+ */
+ protected void handlePropertyChange(int propertyId) {
+ firePropertyChange(propertyId);
+ }
+
+ /**
+ * The <code>MultiPageEditorPart</code> implementation of this <code>IEditorPart</code> method sets its site to the given
+ * site, its input to the given input, and the site's selection provider to a <code>MultiPageSelectionProvider</code>.
+ * Subclasses may extend this method.
+ *
+ * @copiedfrom org.eclipse.ui.part.MultiPageEditorPart
+ * @param site
+ * The site for which this part is being created; must not be <code>null</code>.
+ * @param input
+ * The input on which this editor should be created; must not be <code>null</code>.
+ * @throws PartInitException
+ * If the initialization of the part fails -- currently never.
+ */
+ public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+ setSite(site);
+ setInput(input);
+ site.setSelectionProvider(new MultiPageSelectionProvider(this));
+ }
+
+ /**
+ * Create the part controls. {@inheritDoc}
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+
+ // Create and intialize sash windows
+ sashContainer = new SashWindowsContainer(this);
+ sashContainer.setContentProvider(getContentProvider());
+ sashContainer.createPartControl(parent);
+ }
+
+ /**
+ * Refresh the sash windows system
+ */
+ protected void refreshTabs() {
+ if (sashContainer != null)
+ sashContainer.refreshTabs();
+
+ }
+
+ /**
+ * If there is an adapter registered against the subclass of MultiPageEditorPart return that. Otherwise, delegate to the
+ * internal editor.
+ *
+ * @copiedfrom org.eclipse.ui.part.MultiPageEditorPart
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
+ */
+ public Object getAdapter(Class adapter) {
+
+ // Get the content provider if requested.
+ if (ISashWindowsContentProvider.class == adapter)
+ return getContentProvider();
+
+ // Look in hierarchy
+ Object result = super.getAdapter(adapter);
+ // restrict delegating to the UI thread for bug 144851
+ if (result == null && Display.getCurrent() != null) {
+ IEditorPart innerEditor = getActiveEditor();
+ // see bug 138823 - prevent some subclasses from causing
+ // an infinite loop
+ if (innerEditor != null && innerEditor != this) {
+ result = Util.getAdapter(innerEditor, adapter);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Needed by MultiPageActionBarContributor and MultiPageSelectionProvider.
+ */
+ public IEditorPart getActiveEditor() {
+ return sashContainer.getActiveEditor();
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void setFocus() {
+ sashContainer.setFocus();
+
+ }
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/IMultiPageEditorActionBarContributor.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/IMultiPageEditorActionBarContributor.java
new file mode 100644
index 00000000000..a8472dd3850
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/IMultiPageEditorActionBarContributor.java
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.editor;
+
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * Interface implemented by ActionBarContributor dedicated to MultiEditor.
+ * ActionBarContributor that want to be advised of a page change should implement this interface.
+ * Another way should be to use a Observer/Observee mechanism, allowing to remove the dependancy
+ * from the editor to the ActionBarContributor ?
+ *
+ * @author dumoulin
+ *
+ */
+public interface IMultiPageEditorActionBarContributor {
+
+ /**
+ * Sets the active page of the the multi-page editor to be the given editor. Redirect actions to the given editor if actions are not already being sent to it.
+ * <p>
+ * This method is called whenever the page changes. Subclasses must implement this method to redirect actions to the given editor (if not already directed to it).
+ * </p>
+ *
+ * @param activeEditor
+ * the new active editor, or <code>null</code> if there is no active page, or if the active page does not have a corresponding editor
+ */
+ public abstract void setActivePage(IEditorPart activeEditor);
+
+} \ No newline at end of file
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/IMultiPageEditorPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/IMultiPageEditorPart.java
new file mode 100644
index 00000000000..91d45cacfdb
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/IMultiPageEditorPart.java
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.editor;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbenchPartSite;
+
+/**
+ * Marker to mark a EditorPart as a MultiPartEditor. Provides methods needed by classes
+ * like MultiPageActionBarContributor and MultiPageSelectionProvider.
+ */
+public interface IMultiPageEditorPart {
+
+ /**
+ * Get the currently active editor of the MultiPageEditorPart.
+ * @return
+ */
+ public IEditorPart getActiveEditor();
+
+ /**
+ * Get the main site of the MultiPageEditorPart.
+ * @return
+ */
+ public IWorkbenchPartSite getSite();
+
+ /**
+ * Get the IEditorSite associated to this MultiPageEditorPart.
+ * This return the same object as getSite().
+ * @return
+ */
+ public IEditorSite getEditorSite();
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/MultiPageEditorActionBarContributor.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/MultiPageEditorActionBarContributor.java
new file mode 100644
index 00000000000..f70417fbe44
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/editor/MultiPageEditorActionBarContributor.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.sasheditor.editor;
+
+import java.util.logging.Logger;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * Abstract base class for managing the installation/deinstallation of global actions for multi-page editors.
+ * <p>
+ * Subclasses must implement <code>setActivePage</code>, and may reimplement any of the following methods:
+ * <ul>
+ * <li><code>contributeToMenu</code> - reimplement to contribute to menu</li>
+ * <li><code>contributeToToolBar</code> - reimplement to contribute to tool bar</li>
+ * <li><code>contributeToStatusLine</code> - reimplement to contribute to status line</li>
+ * </ul>
+ * </p>
+ * @see org.eclipse.ui.part.MultiPageEditorActionBarContributor
+ */
+public abstract class MultiPageEditorActionBarContributor extends EditorActionBarContributor implements IMultiPageEditorActionBarContributor {
+
+ /** Log object */
+ Logger log = Logger.getLogger(getClass().getName());
+
+ /**
+ * Creates a multi-page editor action contributor.
+ */
+ protected MultiPageEditorActionBarContributor() {
+ super();
+ }
+
+ /**
+ * Method declared on EditorActionBarContributor.
+ * Registers the contributor with the multi-page
+ * editor for future editor action redirection when the active page is changed, and sets
+ * the active page.
+ */
+ public void setActiveEditor(IEditorPart part) {
+
+ IEditorPart activeNestedEditor = null;
+ if (part instanceof IMultiPageEditorPart) {
+ activeNestedEditor = ((IMultiPageEditorPart) part).getActiveEditor();
+ setActivePage(activeNestedEditor);
+ }
+
+ }
+
+ /**
+ * Called by the MultiEditor whenever the active page change.
+ * @param activeEditor
+ */
+ public abstract void setActivePage(IEditorPart activeEditor);
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/AbstractPanelPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/AbstractPanelPart.java
new file mode 100644
index 00000000000..627e24eab8d
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/AbstractPanelPart.java
@@ -0,0 +1,139 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.internal.dnd.IDropTarget;
+
+
+/**
+ * Common ancestor of Panel Parts.
+ * Panels are sashes and folders.
+ *
+ * @author cedric dumoulin
+ */
+public abstract class AbstractPanelPart extends AbstractPart {
+
+ /**
+ * Parent of this part.
+ */
+ protected IPanelParent parent;
+
+ /**
+ * Constructor.
+ *
+ * @param parent Parent of the Pane.
+ */
+ public AbstractPanelPart(IPanelParent parent) {
+ super(parent.getSashWindowContainer());
+ }
+
+ /**
+ * Create the SWT controls.
+ * This method is called by the SWT parent.
+ * @param container
+ */
+ abstract public void createPartControl(Composite container);
+
+ /**
+ * Dispose all nested SWT controls.
+ */
+ abstract public void dispose();
+
+ /**
+ * Visit the part.
+ * @param visitor
+ */
+ abstract public void visit(IPartVisitor visitor) ;
+
+ /**
+ * Synchronize the part and its children with the models in contentProvider.
+ *
+ * @param existingParts List of already existing part before the synchronization.
+ */
+ abstract public void synchronize2(PartLists existingParts);
+
+ /**
+ * Return true is the part is for the specified raw model.
+ * Return false otherwise.
+ * @param rawModel
+ * @return
+ */
+ abstract public boolean isPartFor(Object rawModel);
+
+ /**
+ * Orphan this node. The parent is set to null, but control is left unchanged.
+ * The node can be reattached with reparent(). Change garbage state to
+ * {@link GarbageState.ORPHANED}.
+ * This method as no effect if the Tile has already been reparented.
+ */
+ abstract public void orphan();
+
+ /**
+ * Change the parent of the Part. The parent is changed, and the control is
+ * attached to the parent control. Change garbage state to {@link GarbageState.REPARENTED}.
+ * @param newParent The new parent to which the part should be attached.
+ */
+ abstract public void reparent(IPanelParent newParent, Composite swtParent );
+
+ /**
+ * Collect all the parts. The method is called recursively in the tree of parts.
+ * @param parts The list into which parts are added.
+ */
+ abstract public void fillPartMap(PartLists parts);
+
+ /**
+ * Traverses the tree to find the part that intersects the given point
+ *
+ * @param toFind
+ * Point in display coordinate
+ * @return the part that intersects the given point
+ * @throws NotFoundException
+ */
+ abstract public AbstractPart findPart(Point toFind) throws NotFoundException;
+
+ /**
+ * Find the part associated to the provided control.
+ * @param control
+ * @return
+ */
+ abstract public AbstractPart findPart(Object control);
+
+ /**
+ * Locates the part that intersects the given point and that have the expected type
+ *
+ * @param toFind Position in Display coordinate.
+ * @return
+ */
+ abstract public AbstractPart findPartAt(Point toFind, Class<?> expectedTileType) ;
+
+ /* ***************************************************** */
+ /* Drag and Drop methods */
+ /* ***************************************************** */
+
+ /**
+ * Return the swt Control associated to this part.
+ */
+ abstract public Composite getControl();
+
+ /**
+ * Get the drop target.
+ * Used by the drag tab mechanism.
+ */
+ abstract public IDropTarget getDropTarget(Object draggedObject, TabFolderPart sourcePart, Point position);
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/AbstractPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/AbstractPart.java
new file mode 100644
index 00000000000..b3f9e5842f3
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/AbstractPart.java
@@ -0,0 +1,85 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashWindowsContentProvider;
+
+
+/**
+ * Base class of the Part hierarchy.
+ * This class provides common methods for sashwindows Parts.
+ *
+ *
+ * @author dumoulin
+ */
+public abstract class AbstractPart {
+
+ /**
+ * Enumeration used when the parts are synchronized.
+ */
+ public enum GarbageState {
+ UNCHANGED, ORPHANED, REPARENTED, CREATED
+ }
+
+ /**
+ * The main container.
+ */
+ protected SashWindowsContainer sashWindowsContainer;
+
+ /** Garbage state used during refresh */
+ protected GarbageState garbageState = GarbageState.CREATED;
+
+
+ /**
+ * @param sashWindowsContainer
+ */
+ public AbstractPart(SashWindowsContainer sashWindowsContainer) {
+ this.sashWindowsContainer = sashWindowsContainer;
+ }
+
+
+ /**
+ * Get the {@link SashWindowsContainer}.
+ * @return
+ */
+ public SashWindowsContainer getSashWindowContainer() {
+ return sashWindowsContainer;
+ }
+
+
+ /**
+ * Get the content provider of the sashwindows.
+ * @return
+ */
+ public ISashWindowsContentProvider getContentProvider() {
+ return sashWindowsContainer.getContentProvider();
+ }
+
+ /**
+ *
+ * @return
+ */
+ public boolean isOrphaned() {
+ return garbageState == GarbageState.ORPHANED;
+ }
+
+ /**
+ * @return
+ */
+ public GarbageState getGarbageState() {
+ return garbageState;
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ActiveEditorAndPageTracker.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ActiveEditorAndPageTracker.java
new file mode 100644
index 00000000000..c00c1593b48
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ActiveEditorAndPageTracker.java
@@ -0,0 +1,238 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import java.util.logging.Level;
+
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.papyrus.sasheditor.eclipsecopy.MultiPageEditorActionBarContributor;
+import org.eclipse.papyrus.sasheditor.eclipsecopy.MultiPageSelectionProvider;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.INestableKeyBindingService;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.services.INestable;
+import org.eclipse.ui.services.IServiceLocator;
+
+
+/**
+ * Instance of this class track the active leaf or editor.
+ * When the active editor change, the tracker receive an event, and perform following tasks:
+ * - send unselect msg to old active editor
+ * - send select msg to new active editor
+ * - record the new active editor
+ * - fire events to all registered listeners.
+ *
+ * This class allows to set externally the active editor.
+ * This class add IEditor switching: when the editor change, it is connected, thanks
+ * to the Site, to the SelectionService, KeyboardService, ...
+ *
+ * @author dumoulin
+ *
+ */
+public class ActiveEditorAndPageTracker extends ActivePageTracker {
+
+ /**
+ * The manager used to access main editor properties like site, actionbars, ...
+ */
+ private IMultiEditorManager multiEditorManager;
+
+ /**
+ * The active service locator. This value may be <code>null</code> if there is no selected page, or if the selected page is a control with no site.
+ */
+ private INestable activeServiceLocator;
+
+ /**
+ * @param editorManager
+ */
+ public ActiveEditorAndPageTracker(IMultiEditorManager editorManager) {
+ this.multiEditorManager = editorManager;
+ }
+
+ /**
+ * Get the currently active IEditorPart, if any.
+ * Return null if there is no active IeditorPart.
+ * Method check if the active leaf encapsulate an IEditorPart. Return it if true.
+ * @return The currentlyactive IEditorPart or null.
+ */
+ private IEditorPart getActiveIEditorPart()
+ {
+ return getIEditorPart(activeEditor);
+ }
+
+ /**
+ * Get IEditorPart of the specified PagePart, if any.
+ * Return null if there is no IeditorPart.
+ * Method check if the leaf encapsulate an IEditorPart. Return it if true.
+ * @return The IEditorPart or null.
+ */
+ private IEditorPart getIEditorPart( PagePart pagePart)
+ {
+ if(pagePart==null)
+ return null;
+
+ if(pagePart instanceof EditorPart)
+ {
+ return ((EditorPart)pagePart).getIEditorPart();
+ }
+ // not found
+ return null;
+ }
+
+ /**
+ * Notifies that the editor has been activated. This method is called when the
+ * user selects a different editor.
+ * @param editor
+ */
+ @Override
+ protected void editorChange(PagePart editor)
+ {
+ System.out.println(getClass().getSimpleName()+ ".editorChange('"+ editor.getPartTitle()+"')");
+ // Set focus
+ IPartService partService = (IPartService) getEditorSite().getService(IPartService.class);
+ if (partService.getActivePart() == getEditorSite().getPart()) {
+ editor.setFocus();
+ }
+
+ // Switch services
+ deactivateServices(false);
+ fireChangeEventToActionBarContributor();
+ propagateSelectionChange(editor);
+ activateServices();
+ }
+
+ /**
+ * Propagate the selection change to the outer SelectionProvider.
+ * @param editor
+ */
+ private void propagateSelectionChange(PagePart editor) {
+
+ // Get the IEditor
+ IEditorPart editorPart = getIEditorPart(editor);
+
+ // Propagate the selection change event.
+ if (editorPart != null) {
+ ISelectionProvider selectionProvider = editorPart.getSite().getSelectionProvider();
+ if (selectionProvider != null) {
+ ISelectionProvider outerProvider = getEditorSite().getSelectionProvider();
+ if (outerProvider instanceof MultiPageSelectionProvider) {
+ SelectionChangedEvent event = new SelectionChangedEvent(selectionProvider, selectionProvider.getSelection());
+
+ MultiPageSelectionProvider provider = (MultiPageSelectionProvider) outerProvider;
+ provider.fireSelectionChanged(event);
+ provider.firePostSelectionChanged(event);
+ } else {
+ if(log.isLoggable(Level.WARNING))
+ {
+ log.warning( this.getClass().getSimpleName()
+ + " did not propogate selection for " //$NON-NLS-1$
+ + editorPart.getTitle());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Activates services of the active editor: site, keybinding
+ * deactivate old active site.
+ */
+ @SuppressWarnings({ "restriction", "deprecation" })
+ private void activateServices()
+ {
+ // Deactivate old active site
+ if (activeServiceLocator != null) {
+ activeServiceLocator.deactivate();
+ activeServiceLocator = null;
+ }
+
+
+ // Get the service
+ final IKeyBindingService service = getEditorSite().getKeyBindingService();
+
+
+ final IEditorPart editor = getActiveIEditorPart();
+
+ if (editor != null) {
+ // active the service for this inner editor
+ if (service instanceof INestableKeyBindingService) {
+ final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+ nestableService.activateKeyBindingService(editor.getEditorSite());
+
+ } else {
+ WorkbenchPlugin
+ .log("MultiPageEditorPart.activateSite() Parent key binding service was not an instance of INestableKeyBindingService. It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ // Activate the services for the new service locator.
+ final IServiceLocator serviceLocator = editor.getEditorSite();
+ if (serviceLocator instanceof INestable) {
+ activeServiceLocator = (INestable) serviceLocator;
+ activeServiceLocator.activate();
+ }
+
+ }
+ }
+
+ /**
+ * Deactivate services: old nested site if any and keybinding service if there is no active editor.
+ * Deactivate the key binding service.
+ * Deactivate it only if there is no editor selected.
+ */
+ @SuppressWarnings({ "restriction", "deprecation" })
+ private void deactivateServices(boolean immediate) {
+ // Deactivate the nested services from the last active service locator.
+ if (activeServiceLocator != null) {
+ activeServiceLocator.deactivate();
+ activeServiceLocator = null;
+ }
+
+ final IEditorPart editor = getActiveIEditorPart();
+ final IKeyBindingService service = getEditorSite().getKeyBindingService();
+ if (editor!=null || immediate) {
+ // There is no selected page, so deactivate the active service.
+ if (service instanceof INestableKeyBindingService) {
+ final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+ nestableService.activateKeyBindingService(null);
+ } else {
+ WorkbenchPlugin
+ .log("MultiPageEditorPart.deactivateSite() Parent key binding service was not an instance of INestableKeyBindingService. It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+
+ /**
+ * Send message to the ActionBarContributor, like this it can switch the active editor.
+ */
+ private void fireChangeEventToActionBarContributor() {
+ IEditorActionBarContributor contributor = getEditorSite().getActionBarContributor();
+ if (contributor != null && contributor instanceof MultiPageEditorActionBarContributor) {
+ ((MultiPageEditorActionBarContributor) contributor).setActivePage(getActiveIEditorPart());
+ }
+
+ }
+
+ /**
+ * Return the MultipageEditorSite
+ * @return
+ */
+ private IEditorSite getEditorSite() {
+ return multiEditorManager.getEditorSite();
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ActivePageTracker.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ActivePageTracker.java
new file mode 100644
index 00000000000..c1ea98859af
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ActivePageTracker.java
@@ -0,0 +1,138 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.eclipse.ui.IPartService;
+
+
+/**
+ * Instance of this class track the active Page.
+ * When the active Page change, the tracker receive an event, and perform following tasks:
+ * - call editorChange()
+ * - fire events to all registered listeners.
+ *
+ * This class allows to set externally the active editor.
+ * @author dumoulin
+ *
+ */
+@SuppressWarnings("unchecked")
+public class ActivePageTracker {
+
+ /** Log object */
+ Logger log = Logger.getLogger(getClass().getName());
+
+ /** List of listeners */
+ private List<IActiveEditorChangeListener> activeEditorChangeListeners = new ArrayList<IActiveEditorChangeListener>();
+
+ /** The currently active editor */
+ protected PagePart activeEditor;
+
+ /**
+ * Interface that must be implemented by listeners on activeEditorChange event.
+ * @author dumoulin
+ *
+ */
+ public interface IActiveEditorChangeListener {
+
+ /**
+ * This method is called whenever the active editor change.
+ * @param oldEditor
+ * @param newEditor
+ */
+ public void activeEditorChange(PagePart oldEditor, PagePart newEditor);
+ }
+
+
+ /**
+ * Constructor.
+ * The activeEditor will be set by the first TabFolder that will call TabFolderPart.setPage().
+ * @param multiPartEditor
+ */
+ public ActivePageTracker() {
+ }
+
+ /**
+ * Get the activeEditor.
+ * @return The active editor or null if there is none.
+ */
+ public PagePart getActiveEditor() {
+ return activeEditor;
+ }
+
+ /**
+ * Set the active editor with the specified editor.
+ * @param editor
+ */
+ public void setActiveEditor(PagePart editor)
+ {
+ // Skip if there is no change
+ if(activeEditor == editor)
+ return;
+
+ PagePart oldEditor = activeEditor;
+ activeEditor = editor;
+ editorChange(editor);
+ fireEditorChangeEvent(oldEditor, editor);
+ }
+
+ /**
+ * Notifies that the editor has been activated. This method is called when the
+ * user selects a different editor.
+ * @param editor
+ */
+ protected void editorChange(PagePart editor)
+ {
+ System.out.println(getClass().getSimpleName()+ ".editorChange('"+ editor.getPartTitle()+"')");
+
+ editor.setFocus();
+ }
+
+ /**
+ * Add a listener on the activeEditorChange event.
+ * @param listener
+ */
+ public void addActiveEditorChangeListener(IActiveEditorChangeListener listener)
+ {
+ // no duplicate
+ if(activeEditorChangeListeners.contains(listener))
+ return;
+ activeEditorChangeListeners.add(listener);
+ }
+
+ /**
+ * Add a listener on the activeEditorChange event.
+ * @param listener
+ */
+ public void removeActiveEditorChangeListener(IActiveEditorChangeListener listener)
+ {
+ activeEditorChangeListeners.remove(listener);
+ }
+
+ private void fireEditorChangeEvent(PagePart oldEditor, PagePart newEditor)
+ {
+ // Fire only if really change
+ if(oldEditor == newEditor)
+ return;
+
+ for(IActiveEditorChangeListener listener : activeEditorChangeListeners)
+ {
+ listener.activeEditorChange(oldEditor, newEditor);
+ }
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ComponentPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ComponentPart.java
new file mode 100644
index 00000000000..2ab04611c5f
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ComponentPart.java
@@ -0,0 +1,396 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.window.Window;
+import org.eclipse.papyrus.sasheditor.Activator;
+import org.eclipse.papyrus.sasheditor.contentprovider.IComponentModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IEditorModel;
+import org.eclipse.papyrus.sasheditor.gef.EditorNotFoundException;
+import org.eclipse.papyrus.sasheditor.gef.InstantiationException;
+import org.eclipse.papyrus.sasheditor.gef.MultiDiagramException;
+import org.eclipse.papyrus.sasheditor.internal.AbstractPart.GarbageState;
+import org.eclipse.papyrus.sasheditor.internal.eclipsecopy.MultiPageEditorSite;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.dnd.IDropTarget;
+import org.eclipse.ui.part.EditorActionBarContributor;
+import org.eclipse.ui.part.IWorkbenchPartOrientation;
+
+
+/**
+ * This is a controler/part for an SWT Control. It is associated to a {@link IComponentModel}.
+ * This Part encapsulate a SWT Control.
+ *
+ * @author dumoulin
+ *
+ */
+@SuppressWarnings("restriction")
+public class ComponentPart extends PagePart {
+
+ /**
+ * The model representing the control.
+ */
+ private IComponentModel partModel;
+
+ /**
+ * The SWT Control.
+ */
+ private Composite editorControl;
+
+ /**
+ * Parent owning this PagePart.
+ * Can be null if the Part is orphaned. Even if it is orphaned, the Item still set.
+ */
+ protected TabFolderPart parent;
+
+ /**
+ * Listen on mouse enter event.
+ * Try to get an event indicating that the mouse enter over the editor.
+ * This can be used to switch the active editor.
+ * TODO This doesn't work yet.
+ */
+ private Listener mouseEnterListener = new Listener() {
+
+ /**
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
+ */
+ public void handleEvent(Event event) {
+ Point globalPos = new Point(event.x, event.y);
+ System.out.println("EditorTile.mouseEnterListener(" + eventName(event.type) + ", " + globalPos + ")");
+ }
+ };
+
+ private String eventName(int eventType)
+ {
+ switch(eventType)
+ {
+ case SWT.MouseEnter : return "MouseEnter";
+ case SWT.MouseDown : return "MouseDown";
+ case SWT.MouseExit : return "MouseExit";
+ case SWT.MouseHover : return "MouseHover";
+ case SWT.FocusIn : return "FocusIn";
+ case SWT.FocusOut : return "FocusOut";
+ case SWT.MouseMove : return "MouseMove";
+ case SWT.MouseUp : return "MouseUp";
+ default : return Integer.toString(eventType);
+ }
+ }
+
+ /**
+ * Constructor.
+ * @param partModel The model of the editor.
+ */
+ public ComponentPart(TabFolderPart parent, IComponentModel partModel, Object rawModel)
+ {
+ super(parent, rawModel);
+ this.partModel = partModel;
+ }
+
+
+
+ /**
+ * Create the control of this Part, and children's controls.
+ * @param parent
+ */
+ public void createPartControl(Composite parent) {
+
+ try {
+ // Initialize it and create its controls.
+ editorControl = createEditorPartControl(parent);
+// attachListeners(editorControl, true);
+
+ } catch (PartInitException e) {
+ Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage()));
+ }
+ }
+
+ /**
+ * Create the controls required by the editor.
+ * Init the editor.
+ * @param viewer
+ * @param editorInput
+ * @param model
+ * @return
+ * @throws PartInitException
+ */
+ private Composite createEditorPartControl(Composite parentControl)
+ throws PartInitException
+ {
+ Composite editorParent = new Composite(parentControl, SWT.NONE);
+ editorParent.setLayout(new FillLayout());
+ partModel.createPartControl(editorParent);
+
+ return editorParent;
+ }
+
+ /**
+ * Attach SWT listeners.
+ */
+ private void attachListeners(Control theControl, boolean recursive) {
+
+ // Both following methods listen to the same event.
+ // So use only one of them
+ theControl.addListener(SWT.MouseEnter, mouseEnterListener);
+
+ theControl.addListener(SWT.FocusIn, mouseEnterListener);
+ theControl.addListener(SWT.MouseMove, mouseEnterListener);
+ theControl.addListener(SWT.MouseHover, mouseEnterListener);
+ theControl.addListener(SWT.MouseUp, mouseEnterListener);
+ theControl.addListener(SWT.MouseDown, mouseEnterListener);
+
+ if (recursive && theControl instanceof Composite) {
+ Composite composite = (Composite) theControl;
+ Control[] children = composite.getChildren();
+
+ for (int i = 0; i < children.length; i++) {
+ Control control = children[i];
+
+ attachListeners(control, true);
+ }
+ }
+ }
+
+ /**
+ * Detach SWT listeners
+ */
+ private void detachListeners(Control theControl, boolean recursive) {
+ theControl.removeListener(SWT.MouseEnter, mouseEnterListener);
+ theControl.removeListener(SWT.FocusIn, mouseEnterListener);
+
+ if (recursive && theControl instanceof Composite) {
+ Composite composite = (Composite) theControl;
+ Control[] children = composite.getChildren();
+
+ for (int i = 0; i < children.length; i++) {
+ Control control = children[i];
+
+ detachListeners(control, false);
+ }
+ }
+ }
+
+ /**
+ * @param isRecursive
+ */
+ public void dispose() {
+
+// detachListeners(editorControl, true);
+ // dispose the SWT root control
+ editorControl.dispose();
+ }
+
+
+ /**
+ * As we are a final Tile, we should be the requested part.
+ * Return this TilePart.
+ * @param toFind
+ * @return
+ */
+ public PagePart findPart(Point toFind) {
+ return this;
+ }
+
+ /**
+ * Locates the part that intersects the given point and that have the expected type
+ *
+ * @param toFind
+ * @return
+ */
+ public PagePart findPartAt(Point toFind, Class<?> expectedTileType) {
+
+ if(expectedTileType == this.getClass())
+ return this;
+
+ // Not found !!
+ // The tile contains the position, but the type is not found.
+ throw new UnsupportedOperationException("Tile match the expected position '"
+ + toFind
+ + "' but there is no Tile of requested type '"
+ + expectedTileType.getClass().getName() + "'" );
+ }
+
+ /**
+ * @param control
+ * @return
+ */
+ public PagePart findPart(Object control) {
+ if (getControl() == control)
+ return this;
+
+ // Not found
+ return null;
+ }
+
+ /**
+ * Get associated SWT Control.
+ *
+ * @return
+ */
+ public Composite getControl() {
+ return editorControl;
+ }
+
+
+ /**
+ * This is a container method. Not necessary in Leaf Tile.
+ * TODO: change the interface.
+ * @param draggedObject
+ * @param sourcePart
+ * @param position
+ * @return
+ */
+ public IDropTarget getDropTarget(Object draggedObject, TabFolderPart sourcePart, Point position) {
+ return null;
+ }
+
+ /**
+ * Orphan this node. The parent is set to null, but control is left unchanged.
+ * The node can be reattached with reparent(). Change garbage state to
+ * {@link GarbageState.ORPHANED}.
+ * This method as no effect if the Tile has already been reparented.
+ *
+ * @see
+ * @return the parent
+ */
+ public void orphan() {
+ // orphan only if we are in UNCHANGED state
+ if (garbageState == GarbageState.UNCHANGED) {
+ garbageState = GarbageState.ORPHANED;
+ parent = null;
+ }
+ }
+
+
+ /**
+ * Change the parent of the Tile. The parent is changed, and the control is
+ * attached to the parent control. Change garbage state to {@link GarbageState.REPARENTED}.
+ * Do not detach the Tile from its old parent.
+ *
+ * @param newParent
+ * The tilePart that should be used as part parent.
+ * @param compositeParent
+ * The composite that should be used as parent.
+ */
+ public void reparent(TabFolderPart newParent) {
+
+ // Change the tile parent
+ this.parent = newParent;
+ // Change the SWT parent.
+ editorControl.setParent(newParent.getControl());
+ garbageState = GarbageState.REPARENTED;
+ }
+
+
+ /**
+ * Asks this part to take focus within the workbench.
+ * Set the focus on the active nested part if the part is a container.
+ */
+ public void setFocus() {
+ editorControl.setFocus();
+ }
+
+
+ /**
+ * Synchronize the Part, and its children. PartMap contains a snapshot of the available part before
+ * the synchronization. After synchronization, unreachable parts should be marked "orphaned" (= no
+ * parent).
+ * Do nothing in this implementation, as we are a final leaf, and there is nothing to synchronize
+ * with the underlying model.
+ * @param partMap
+ */
+ public void synchronize2(PartLists partMap) {
+
+ }
+
+
+ /**
+ * Garbage this part.
+ * The part is already marked as ORPHANED. It is not used anymore. It is already detached
+ * from its parent.
+ *
+ */
+ public void garbage() {
+ dispose();
+ }
+
+
+ /**
+ * Accept the provided visitor.
+ * Call the corresponding accept method in the visitor.
+ * @param visitor
+ * @return
+ */
+ public void visit(IPartVisitor visitor) {
+ visitor.accept(this);
+ }
+
+ /**
+ * Visit the children of this Tile.
+ * There is no child, so do nothing.
+ * @param visitor
+ */
+ public void visitChildren(IPartVisitor visitor) {
+ }
+
+
+ /**
+ * Show item status.
+ */
+ protected void showStatus()
+ {
+// System.out.println( "EditorTile: "
+// + " disposed=" + editorControl.isDisposed()
+// + ", visible=" + editorControl.isVisible()
+// + ", garbState=" + garbageState
+// + ", '" + editorPart.getTitle()
+// + "', " + this);
+
+ System.out.printf("ComponentPart: disposed=%-5b, visible=%-5b, garbState=%-10s, %s, %s\n"
+ , editorControl.isDisposed(), (editorControl.isDisposed()?false:editorControl.isVisible()), garbageState, getPartTitle(), this);
+
+ }
+
+ /**
+ * Get the title for this part.
+ * {@inheritDoc}
+ */
+ @Override
+ public String getPartTitle() {
+ return partModel.getTabTitle();
+ }
+
+ /**
+ * Return an icon for this part.
+ * {@inheritDoc}
+ */
+ @Override
+ public Image getPartIcon() {
+ return partModel.getTabIcon();
+ }
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/Copyright.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/Copyright.java
new file mode 100644
index 00000000000..9605d04c610
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/Copyright.java
@@ -0,0 +1,23 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.sasheditor.internal;
+
+
+/**
+ * @author dumoulin
+ */
+public class Copyright {
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/EditorPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/EditorPart.java
new file mode 100644
index 00000000000..7b62694e515
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/EditorPart.java
@@ -0,0 +1,547 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.window.Window;
+import org.eclipse.papyrus.sasheditor.Activator;
+import org.eclipse.papyrus.sasheditor.contentprovider.IEditorModel;
+import org.eclipse.papyrus.sasheditor.gef.EditorNotFoundException;
+import org.eclipse.papyrus.sasheditor.gef.InstantiationException;
+import org.eclipse.papyrus.sasheditor.gef.MultiDiagramException;
+import org.eclipse.papyrus.sasheditor.internal.AbstractPart.GarbageState;
+import org.eclipse.papyrus.sasheditor.internal.eclipsecopy.MultiPageEditorSite;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.dnd.IDropTarget;
+import org.eclipse.ui.part.EditorActionBarContributor;
+import org.eclipse.ui.part.IWorkbenchPartOrientation;
+
+
+/**
+ * This is a controler/part for an Editor. It is associated to a {@link IEditorModel}.
+ * This Part encapsulate an Eclipse Editor implementing {@link IEditorPart}.
+ *
+ * @author dumoulin
+ *
+ */
+@SuppressWarnings("restriction")
+public class EditorPart extends PagePart {
+
+ /**
+ * The model representing the editor.
+ */
+ private IEditorModel editorModel;
+
+ /**
+ * The created Eclipse editor.
+ */
+ private IEditorPart editorPart;
+
+ /**
+ * The SWT Control containning the editor's controls.
+ */
+ private Composite editorControl;
+
+ /**
+ * The MultiPageContainer system. This is the manager of all tiles.
+ */
+ private SashWindowsContainer tilesContainer;
+
+ /**
+ * The manager used to access main editor properties like site, actionbars, ...
+ */
+ private IMultiEditorManager multiEditorManager;
+
+ /**
+ * Parent owning this PagePart.
+ * Can be null if the Part is orphaned. Even if it is orphaned, the Item still set.
+ */
+ protected TabFolderPart parent;
+
+ /**
+ * Listen on mouse enter event.
+ * Try to get an event indicating that the mouse enter over the editor.
+ * This can be used to switch the active editor.
+ * TODO This doesn't work yet.
+ */
+ private Listener mouseEnterListener = new Listener() {
+
+ /**
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
+ */
+ public void handleEvent(Event event) {
+ Point globalPos = new Point(event.x, event.y);
+ System.out.println("EditorTile.mouseEnterListener(" + eventName(event.type) + ", " + globalPos + ")");
+ }
+ };
+
+ private String eventName(int eventType)
+ {
+ switch(eventType)
+ {
+ case SWT.MouseEnter : return "MouseEnter";
+ case SWT.MouseDown : return "MouseDown";
+ case SWT.MouseExit : return "MouseExit";
+ case SWT.MouseHover : return "MouseHover";
+ case SWT.FocusIn : return "FocusIn";
+ case SWT.FocusOut : return "FocusOut";
+ case SWT.MouseMove : return "MouseMove";
+ case SWT.MouseUp : return "MouseUp";
+ default : return Integer.toString(eventType);
+ }
+ }
+
+ /**
+ * Constructor.
+ * @param editorModel The model of the editor.
+ */
+ public EditorPart(TabFolderPart parent, IEditorModel editorModel, Object rawModel, IMultiEditorManager multiEditorManager)
+ {
+ super(parent, rawModel);
+ this.editorModel = editorModel;
+ this.multiEditorManager = multiEditorManager;
+ }
+
+
+ /**
+ * Create the control of this part.
+ * For a this implementations, also create the children's controls.
+ * This method forward to {@link createPartControl(Composite)}.
+ * @param parent
+ */
+ public void createControl(Composite parent) {
+ createPartControl(parent);
+ }
+
+
+ /**
+ * Create the control of this Part, and children's controls.
+ * @param parent
+ */
+ public void createPartControl(Composite parent) {
+
+ try {
+ // Create the editor.
+ editorPart = createIEditorPart();
+ // Initialize it and create its controls.
+ editorControl = createEditorPartControl(parent, editorPart);
+// attachListeners(editorControl, true);
+
+ } catch (PartInitException e) {
+ Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage()));
+ }
+ }
+
+ /**
+ * Create the editor associated to this TabPart.
+ * @return
+ * @throws PartInitException
+ */
+ private IEditorPart createIEditorPart() throws PartInitException {
+
+ return editorModel.createIEditorPart();
+ }
+
+ /**
+ * Create the controls required by the editor.
+ * Init the editor.
+ * @param viewer
+ * @param editorInput
+ * @param model
+ * @return
+ * @throws PartInitException
+ */
+ private Composite createEditorPartControl(Composite parentControl, IEditorPart editor)
+ throws PartInitException
+ {
+ IEditorSite site = createSite(editor);
+ // call init first so that if an exception is thrown, we have created no
+ // new widgets
+ editor.init(site, getIMultiEditorManager().getEditorInput() );
+ Composite editorParent = new Composite(parentControl, getOrientation(editor));
+ editorParent.setLayout(new FillLayout());
+ editor.createPartControl(editorParent);
+ editor.addPropertyListener(new IPropertyListener() {
+
+ public void propertyChanged(Object source, int propertyId) {
+ EditorPart.this.handlePropertyChange(propertyId);
+ }
+ });
+
+ return editorParent;
+ }
+
+ /**
+ * Attach SWT listeners.
+ */
+ private void attachListeners(Control theControl, boolean recursive) {
+
+ // All following methods listen to the same event.
+ // So use only one of them
+ theControl.addListener(SWT.MouseEnter, mouseEnterListener);
+
+ theControl.addListener(SWT.FocusIn, mouseEnterListener);
+ theControl.addListener(SWT.MouseMove, mouseEnterListener);
+ theControl.addListener(SWT.MouseHover, mouseEnterListener);
+ theControl.addListener(SWT.MouseUp, mouseEnterListener);
+ theControl.addListener(SWT.MouseDown, mouseEnterListener);
+
+ if (recursive && theControl instanceof Composite) {
+ Composite composite = (Composite) theControl;
+ Control[] children = composite.getChildren();
+
+ for (int i = 0; i < children.length; i++) {
+ Control control = children[i];
+
+ attachListeners(control, true);
+ }
+ }
+ }
+
+ /**
+ * Detach SWT listeners
+ */
+ private void detachListeners(Control theControl, boolean recursive) {
+ theControl.removeListener(SWT.MouseEnter, mouseEnterListener);
+ theControl.removeListener(SWT.FocusIn, mouseEnterListener);
+
+ if (recursive && theControl instanceof Composite) {
+ Composite composite = (Composite) theControl;
+ Control[] children = composite.getChildren();
+
+ for (int i = 0; i < children.length; i++) {
+ Control control = children[i];
+
+ detachListeners(control, false);
+ }
+ }
+ }
+
+
+ /**
+ * Handles a property change notification from a nested editor. The default implementation simply forwards
+ * the change to listeners on this multi-page editor by calling
+ * <code>firePropertyChange</code> with the same property id. For example, if the dirty state of a nested
+ * editor changes (property id <code>IEditorPart.PROP_DIRTY</code>), this method handles it
+ * by firing a property change event for <code>IEditorPart.PROP_DIRTY</code> to property listeners on this
+ * multi-page editor.
+ * <p>
+ * Subclasses may extend or reimplement this method.
+ * </p>
+ *
+ * @param propertyId
+ * the id of the property that changed
+ */
+ private void handlePropertyChange(int propertyId) {
+ getSashWindowContainer().firePropertyChange(propertyId);
+ }
+
+ /**
+ * Creates the site for the given nested editor. The <code>MultiPageEditorPart</code> implementation
+ * of this method creates an instance of <code>MultiPageEditorSite</code>. Subclasses may
+ * reimplement to create more specialized sites.
+ *
+ * @param editor
+ * the nested editor
+ * @return the editor site
+ */
+ protected IEditorSite createSite(IEditorPart editor) {
+ EditorActionBarContributor contributor = createEditorActionBarContributor();
+ return new MultiPageEditorSite(multiEditorManager.getEditorSite(), editor, contributor);
+ }
+
+ /**
+ * Create the EditorActionBarContributor requested by the editor.
+ * Creation is done by delegating to the IMultiEditorNestedPartManager.
+ * @return
+ */
+ private EditorActionBarContributor createEditorActionBarContributor() {
+ EditorActionBarContributor contributor = editorModel.getActionBarContributor();
+ return contributor;
+ }
+
+ /**
+ * Get the orientation of the editor.
+ *
+ * @param editor
+ * @return int the orientation flag
+ * @see SWT#RIGHT_TO_LEFT
+ * @see SWT#LEFT_TO_RIGHT
+ * @see SWT#NONE
+ */
+ private int getOrientation(IEditorPart editor) {
+ if (editor instanceof IWorkbenchPartOrientation) {
+ return ((IWorkbenchPartOrientation) editor).getOrientation();
+ }
+ return Window.getDefaultOrientation();
+ }
+
+ /**
+ * Get the nested part manager.
+ * @return
+ */
+ private IMultiEditorManager getIMultiEditorManager() {
+ return multiEditorManager;
+ }
+
+
+ /**
+ * @param isRecursive
+ */
+ public void dispose() {
+
+// detachListeners(editorControl, true);
+ // dispose the SWT root control
+ editorControl.dispose();
+ // Dispose the editor.
+ editorPart.dispose();
+ }
+
+
+ /**
+ * As we are a final Tile, we should be the requested part.
+ * Return this TilePart.
+ * @param toFind
+ * @return
+ */
+ public PagePart findPart(Point toFind) {
+ return this;
+ }
+
+ /**
+ * Locates the part that intersects the given point and that have the expected type
+ *
+ * @param toFind
+ * @return
+ */
+ public PagePart findPartAt(Point toFind, Class<?> expectedTileType) {
+
+ if(expectedTileType == this.getClass())
+ return this;
+
+ // Not found !!
+ // The tile contains the position, but the type is not found.
+ throw new UnsupportedOperationException("Tile match the expected position '"
+ + toFind
+ + "' but there is no Tile of requested type '"
+ + expectedTileType.getClass().getName() + "'" );
+ }
+
+ /**
+ * @param control
+ * @return
+ */
+ public PagePart findPart(Object control) {
+ if (getControl() == control)
+ return this;
+
+ // Not found
+ return null;
+ }
+
+ /**
+ * Returns the active nested editor if there is one.
+ * <p>
+ * Subclasses should not override this method
+ * </p>
+ *
+ * @return the active nested editor, or <code>null</code> if none
+ */
+ public IEditorPart getIEditorPart() {
+ return editorPart;
+ }
+
+ /**
+ * Get associated SWT Control.
+ *
+ * @return
+ */
+ public Composite getControl() {
+ return editorControl;
+ }
+
+
+ /**
+ * This is a container method. Not necessary in Leaf Tile.
+ * TODO: change the interface.
+ * @param draggedObject
+ * @param sourcePart
+ * @param position
+ * @return
+ */
+ public IDropTarget getDropTarget(Object draggedObject, TabFolderPart sourcePart, Point position) {
+ return null;
+ }
+
+
+ /**
+ * @return
+ */
+ public GarbageState getGarbageState() {
+ return garbageState;
+ }
+
+
+ /**
+ * Is the associated editor dirty ?
+ * Delegate to {@link IEditorPart.isDirty()}
+ * @return true if the associated editor is dirty.
+ */
+ public boolean isDirty() {
+ return editorPart.isDirty();
+ }
+
+
+
+ /**
+ * Orphan this node. The parent is set to null, but control is left unchanged.
+ * The node can be reattached with reparent(). Change garbage state to
+ * {@link GarbageState.ORPHANED}.
+ * This method as no effect if the Tile has already been reparented.
+ *
+ * @see
+ * @return the parent
+ */
+ public void orphan() {
+ // orphan only if we are in UNCHANGED state
+ if (garbageState == GarbageState.UNCHANGED) {
+ garbageState = GarbageState.ORPHANED;
+ parent = null;
+ }
+ }
+
+
+ /**
+ * Change the parent of the Tile. The parent is changed, and the control is
+ * attached to the parent control. Change garbage state to {@link GarbageState.REPARENTED}.
+ * Do not detach the Tile from its old parent.
+ *
+ * @param newParent
+ * The tilePart that should be used as part parent.
+ * @param compositeParent
+ * The composite that should be used as parent.
+ */
+ public void reparent(TabFolderPart newParent) {
+
+ // Change the tile parent
+ this.parent = newParent;
+ // Change the SWT parent.
+ editorControl.setParent(newParent.getControl());
+ garbageState = GarbageState.REPARENTED;
+ }
+
+
+ /**
+ * Asks this part to take focus within the workbench.
+ * Set the focus on the active nested part if the part is a container.
+ */
+ public void setFocus() {
+ editorPart.setFocus();
+ }
+
+
+ /**
+ * Synchronize the Part, and its children. PartMap contains a snapshot of the available part before
+ * the synchronization. After synchronization, unreachable parts should be marked "orphaned" (= no
+ * parent).
+ * Do nothing in this implementation, as we are a final leaf, and there is nothing to synchronize
+ * with the underlying model.
+ * @param partMap
+ */
+ public void synchronize2(PartLists partMap) {
+
+ }
+
+
+ /**
+ * Garbage this part.
+ * The part is already marked as ORPHANED. It is not used anymore. It is already detached
+ * from its parent.
+ *
+ */
+ public void garbage() {
+ dispose();
+ }
+
+
+ /**
+ * Accept the provided visitor.
+ * Call the corresponding accept method in the visitor.
+ * @param visitor
+ * @return
+ */
+ public void visit(IPartVisitor visitor) {
+ visitor.accept(this);
+ }
+
+ /**
+ * Visit the children of this Tile.
+ * There is no child, so do nothing.
+ * @param visitor
+ */
+ public void visitChildren(IPartVisitor visitor) {
+ }
+
+
+ /**
+ * Show item status.
+ */
+ protected void showStatus()
+ {
+// System.out.println( "EditorTile: "
+// + " disposed=" + editorControl.isDisposed()
+// + ", visible=" + editorControl.isVisible()
+// + ", garbState=" + garbageState
+// + ", '" + editorPart.getTitle()
+// + "', " + this);
+
+ System.out.printf("EditorTile: disposed=%-5b, visible=%-5b, garbState=%-10s, %s, %s\n"
+ , editorControl.isDisposed(), (editorControl.isDisposed()?false:editorControl.isVisible()), garbageState, editorPart.getTitle(), this);
+
+ }
+
+ /**
+ * Get the title for this part.
+ * {@inheritDoc}
+ */
+ @Override
+ public String getPartTitle() {
+ return editorModel.getTabTitle();
+ }
+
+ /**
+ * Return an icon for this part.
+ * {@inheritDoc}
+ */
+ @Override
+ public Image getPartIcon() {
+ return editorModel.getTabIcon();
+ }
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IMultiEditorManager.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IMultiEditorManager.java
new file mode 100644
index 00000000000..5da6af58f20
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IMultiEditorManager.java
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.papyrus.sasheditor.eclipsecopy.IMultiPageEditorPart;
+import org.eclipse.papyrus.sasheditor.gef.MultiDiagramException;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+
+/**
+ * This interface allows EditorPart to access objects provided by the real editor.
+ * Implementation of this interface is provided to the {@link SashWindowsContainer} and used by
+ * {@link EditorPart}.
+ *
+ * @author dumoulin
+ */
+public interface IMultiEditorManager {
+
+ /**
+ * Get the EditorActionBarContributor for the editor associated to the specified model.
+ * @param editorModel
+ * @return
+ * @throws MultiDiagramException
+ */
+// public EditorActionBarContributor getActionBarContributor(Object editorModel);
+
+ /**
+ * Fires a property changed event.
+ *
+ * @param propertyId the id of the property that changed
+ */
+// public void firePropertyChange(int propertyId);
+
+ /**
+ * Get the editor input associated to the main IMultiPageEditorPart.
+ * @return
+ */
+ public IEditorInput getEditorInput();
+
+ /**
+ * Get the main site of the MultiPageEditorPart.
+ * @return
+ */
+ public IWorkbenchPartSite getSite();
+
+ /**
+ * Get the IEditorSite associated to this MultiPageEditorPart.
+ * This return the same object as getSite().
+ * @return
+ */
+ public IEditorSite getEditorSite();
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IPanelParent.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IPanelParent.java
new file mode 100644
index 00000000000..7b18edcf5b4
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IPanelParent.java
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Interface implemented by Part that can be parent of a Panel (Sashes or Folders). The interface allows to restrict the classes that can be parent of a Panel. For now, only {@link RootPart} and
+ * {@link SashPanelPart} can be parent of a Panel.
+ *
+ * @author dumoulin
+ */
+public interface IPanelParent {
+
+ /**
+ * Get the {@link SashWindowsContainer}.
+ *
+ * @return
+ */
+ public SashWindowsContainer getSashWindowContainer();
+
+ /**
+ * Get the parent SWT control.
+ *
+ * @return
+ */
+ public Composite getControl();
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IPartVisitor.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IPartVisitor.java
new file mode 100644
index 00000000000..b8bfeda5af0
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/IPartVisitor.java
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+
+/**
+ * Visitor used to visit the hierarchy of Parts.
+ * @author dumoulin
+ *
+ */
+public interface IPartVisitor {
+
+ /**
+ * Accept the node of specified type.
+ * @param folder
+ */
+
+ public void accept(RootPart tile);
+
+ /**
+ * Accept the node of specified type.
+ * @param folder
+ */
+ public void accept(SashPanelPart tile);
+
+ /**
+ * Accept the node of specified type.
+ * @param folder
+ */
+ public void accept(TabFolderPart folder);
+
+ /**
+ * Accept the node of specified type.
+ * @param folder
+ */
+ public void accept(TabItemPart tile);
+
+ /**
+ * Accept the node of specified type.
+ * @param folder
+ */
+ public void accept(EditorPart tile);
+
+ /**
+ * Accept the node of specified type.
+ * @param componentPart
+ */
+ public void accept(ComponentPart componentPart);
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ImageToolTipManager.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ImageToolTipManager.java
new file mode 100644
index 00000000000..159c7267cbf
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ImageToolTipManager.java
@@ -0,0 +1,281 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import java.util.logging.Logger;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Transform;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+
+/**
+ * @author dumoulin
+ */
+/**
+ * A class managing tooltips as Part.
+ * @author dumoulin
+ */
+public class ImageToolTipManager {
+
+ /** Log object */
+ Logger log = Logger.getLogger(getClass().getName());
+
+ /** */
+ private Control toolTipedControl;
+ /**
+ * Size of the image to show.
+ */
+ private Rectangle toolTipExpectedSize = new Rectangle(0, 0, 100, 80);
+
+ private int offsetX = 20;
+ private int offsetY = 20;
+
+ /**
+ * Position of the tooltip relative to the tooltiped swt.Control.
+ */
+ private int toolTipAlignement = SWT.TOP;
+ /**
+ *
+ */
+ private Shell tip = null;
+
+ /**
+ * Constructor.
+ */
+ public ImageToolTipManager() {
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * Close the toltip and dispose it.
+ */
+ public void closeToolTip() {
+ if(tip==null)
+ return;
+
+ tip.dispose();
+ tip = null;
+ toolTipedControl = null;
+
+ }
+
+ /**
+ * Show the tooltip for the part. Check if the tooltip should be reopen, or use the
+ * previously open one.
+ * @param relatedControlBounds Bounds of the control for which the tooltip should be shown.
+ * @param part The part for which a tooltip should be shown.
+ * @param mousePos Position of the mouse.
+ */
+ public void showToolTip(Rectangle relatedControlBounds, Control control, Point mousePos)
+ {
+ if(toolTipedControl == control)
+ {
+ // resetTimer()
+ return;
+ }
+
+ openToolTip(relatedControlBounds, control, mousePos);
+
+ }
+
+ /**
+ * Show the tooltip for the part. Check if the tooltip should be reopen, or use the
+ * previously open one.
+ * @param relatedControlBounds Bounds of the control for which the tooltip should be shown.
+ * @param toolTipImage The image used as tooltip.
+ * @param mousePos Position of the mouse.
+ */
+ public void showToolTip(Rectangle relatedControlBounds, Image toolTipImage, Point mousePos)
+ {
+ throw new UnsupportedOperationException("Not yet implemented");
+// if(toolTipedControl == control)
+// {
+// // resetTimer()
+// return;
+// }
+//
+// openToolTip(relatedControlBounds, control, mousePos);
+
+ }
+
+ /**
+ * Open the toolTip at the specified position.
+ * @param part
+ * @param atPoint
+ */
+ private void openToolTip(Rectangle relatedControlBounds, Control control, Point atPoint) {
+ toolTipedControl = control;
+ float scaleFactor = .5f;
+
+ Image image = createControlImage(control);
+ if(image == null)
+ return;
+
+ Image scaledImage = scaledImage(control.getDisplay(), image, scaleFactor);
+ image.dispose();
+
+ Point pos = computeToolTipPosition(relatedControlBounds, atPoint, scaledImage.getBounds());
+ openToolTip(control, scaledImage, pos);
+ }
+
+ /**
+ * Compute the tooltip position.
+ *
+ * @param relatedControlBounds Bounds of the item to which the tooltip apply
+ * @param mousePos Position of the mouse inside the relatedControlBounds.
+ * @param toolTipSize Size of the ToolTip.
+ *
+ * @return Position of the tooltip
+ */
+ private Point computeToolTipPosition(Rectangle relatedControlBounds, Point mousePos, Rectangle toolTipSize) {
+
+ int x, y;
+ if(toolTipAlignement == SWT.TOP)
+ {
+ // Position.x = mousePoint.x
+ // Position.y = itemBounds - (toolTipSize.y + offsetY)
+ x = mousePos.x;
+ y = relatedControlBounds.y - (toolTipSize.height + offsetY);
+ }
+ else if(toolTipAlignement == SWT.BOTTOM)
+ {
+ x = mousePos.x;
+ y = relatedControlBounds.y + (relatedControlBounds.height + offsetY);
+ }
+ else
+ {
+ throw new UnsupportedOperationException("Not yet implemented for this alignement.");
+ }
+ return new Point(x, y);
+ }
+
+ /**
+ * Open a tooltip like window containing the image.
+ *
+ * @param device The control from which atPoint is specified.
+ * @param scaledImage
+ * @param atPoint
+ */
+ private void openToolTip(Control device, Image scaledImage, Point atPoint) {
+ if (tip != null && !tip.isDisposed ()) tip.dispose ();
+ tip = new Shell (device.getShell(), SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
+ FillLayout layout = new FillLayout ();
+ layout.marginWidth = 2;
+ tip.setLayout (layout);
+ Label label = new Label (tip, SWT.NONE);
+ label.setImage(scaledImage);
+ Point size = tip.computeSize (SWT.DEFAULT, SWT.DEFAULT);
+ Point pt = device.toDisplay (atPoint.x+20, atPoint.y);
+ tip.setBounds (pt.x, pt.y, size.x, size.y);
+ tip.setVisible (true);
+ }
+
+ /**
+ * Create an image corresponding to the control.
+ * @param control The control for which an image is to be built.
+ * @return
+ */
+ private Image createControlImage(Control control)
+ {
+ // Create an image of the part.
+
+ Rectangle size;
+
+ size = control.getBounds();
+ if( size.width == 0 && size.height == 0){
+ Point pt = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ size = new Rectangle(0,0, pt.x, pt.y);
+ }
+
+ Image image = new Image(control.getDisplay(), size );
+ GC gc = new GC (image);
+
+ boolean success = control.print (gc);
+ gc.dispose ();
+ if (!success) {
+ image.dispose();
+// log.warning("Can't create Snapshot for the control of '" + part + "'.");
+ return null;
+ }
+
+ return image;
+ }
+
+ /**
+ * Create an image corresponding to the control.
+ * @param control The control for which an image is to be built.
+ * @return
+ */
+ private Image scaledImage2(Device device, Image image, float factor)
+ {
+ Rectangle imageBounds = image.getBounds();
+ Rectangle size = computeToolTipSize(image, factor);
+ Image scaledImage = new Image(device, size );
+ GC gc = new GC (scaledImage);
+
+ gc.drawImage(image, 0, 0, imageBounds.width, imageBounds.height, 0, 0, size.width, size.height);
+
+ return scaledImage;
+ }
+
+ /**
+ * Compute the expected size of the tooltip.
+ * For now, simply return the expected size.
+ * @param image
+ * @param factor
+ * @return
+ */
+ private Rectangle computeToolTipSize(Image image, float factor) {
+
+// Rectangle imageBounds = image.getBounds();
+// Rectangle size;
+
+ return toolTipExpectedSize;
+ }
+
+ /**
+ * Create a new image which is the input image scaled.
+ * @param image
+ * @param factor
+ * @return
+ */
+ private Image scaledImage(Device device, Image image, float factor) {
+
+ Rectangle bounds = image.getBounds();
+// Float factor = 0.5f;
+
+ Rectangle newBounds = new Rectangle(0, 0, Math.round(bounds.width*factor), Math.round(bounds.height*factor));
+ Image scaledImage = new Image (device, newBounds);
+ GC gc = new GC (scaledImage);
+
+ gc.setAdvanced(true);
+ gc.setAntialias(SWT.ON);
+ Transform tr = new Transform( device );
+ tr.scale(factor, factor);
+ gc.setTransform( tr );
+ gc.drawImage(image, 0, 0);
+ tr.dispose();
+ return scaledImage;
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/NotFoundException.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/NotFoundException.java
new file mode 100644
index 00000000000..7cdf4e97179
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/NotFoundException.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+
+/**
+ * Exception thrown when a search or lookup fails.
+ * @author dumoulin
+ */
+public class NotFoundException extends SashWindowsException {
+
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public NotFoundException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ */
+ public NotFoundException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param cause
+ */
+ public NotFoundException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public NotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PTabFolder.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PTabFolder.java
new file mode 100644
index 00000000000..7327f4f5111
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PTabFolder.java
@@ -0,0 +1,572 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabFolder2Adapter;
+import org.eclipse.swt.custom.CTabFolderEvent;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.DragDetectEvent;
+import org.eclipse.swt.events.MenuDetectEvent;
+import org.eclipse.swt.events.MenuDetectListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ToolTip;
+import org.eclipse.ui.internal.dnd.DragUtil;
+import org.eclipse.ui.presentations.PresentationUtil;
+
+/**
+ * Papyrus wrapper for CTabFolder.
+ * Provides miscelaneous methods for dragging.
+ * Provides different fireEvents for: menu detected, pageChange, itemClosed.
+ * TODO : add listeners mechanism to listen on events ?
+ */
+@SuppressWarnings("restriction")
+public class PTabFolder {
+
+ /**
+ * The underlying tabfolder.
+ */
+ protected CTabFolder tabFolder;
+
+ /**
+ * This object allows to register listeners on event from this class.
+ */
+ private EventsManager listenersManager = new EventsManager();
+
+ /**
+ * Listen on menu event.
+ */
+ private Listener menuListener = new Listener() {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
+ */
+ public void handleEvent(Event event) {
+ Point globalPos = new Point(event.x, event.y);
+ System.out.println("menuListener(" + globalPos + ")");
+ handleContextMenu(globalPos, event);
+ }
+ };
+
+ private Listener dragListener = new Listener() {
+
+ public void handleEvent(Event e) {
+ Point globalPos = ((Control) e.widget).toDisplay(e.x, e.y);
+ handleDragStarted(globalPos, e);
+ }
+ };
+
+ private Listener mouseUpListener = new Listener() {
+
+ public void handleEvent(Event e) {
+ Point globalPos = ((Control) e.widget).toDisplay(e.x, e.y);
+ System.out.println("mouseUpListener(" + globalPos + ", event=" + e + ")");
+ }
+ };
+
+ private SelectionListener selectionListener = new SelectionListener() {
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ System.out.println("selectionListener(event=" + e + ")");
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ System.out.println("selectionListener(event=" + e + ")");
+ }
+
+ };
+
+ private TraverseListener traverseListener = new TraverseListener() {
+
+ public void keyTraversed(TraverseEvent e) {
+ System.out.println("traverseListener(event=" + e + ")");
+ }
+
+ };
+
+
+// private DragDetectListener dragDetectListener = new DragDetectListener() {
+//
+// public void dragDetected(DragDetectEvent e) {
+// Point globalPos = ((Control) e.widget).toDisplay(e.x, e.y);
+// handleDragDetectStarted(globalPos, e);
+// }
+//
+// };
+
+ private MenuDetectListener menuDetectListener = new MenuDetectListener() {
+
+ public void menuDetected(MenuDetectEvent e) {
+// Point globalPos = ((Control) e.widget).toDisplay(e.x, e.y);
+ Point globalPos = new Point(e.x, e.y);
+ System.out.println("menuDetected(" + globalPos + ")");
+ handleMenuDetect(globalPos, e);
+ }
+
+ };
+
+ /**
+ * Get the underlying control.
+ */
+ public Composite getControl() {
+ return tabFolder;
+ }
+
+ /**
+ * Create the corresponding SWT Control
+ */
+ public void createPartControl(Composite parent) {
+ tabFolder = createContainer(parent);
+
+ // Attach listeners
+ attachListeners(tabFolder, false);
+ }
+
+ /**
+ * Creates an empty container. Creates a CTabFolder with no style bits set, and hooks a selection listener which calls <code>pageChange()</code> whenever the selected tab changes.
+ *
+ * @param parent
+ * The composite in which the container tab folder should be created; must not be <code>null</code>.
+ * @return a new container
+ */
+ private CTabFolder createContainer(Composite parent) {
+ // use SWT.FLAT style so that an extra 1 pixel border is not reserved
+ // inside the folder
+ parent.setLayout(new FillLayout());
+ final CTabFolder newContainer = new CTabFolder(parent, SWT.BOTTOM | SWT.FLAT | SWT.CLOSE);
+
+ // TODO Move listener init in appropriate method.
+ newContainer.addSelectionListener(new SelectionAdapter() {
+
+ public void widgetSelected(SelectionEvent e) {
+ int newPageIndex = newContainer.indexOf((CTabItem) e.item);
+ firePageChange(newPageIndex);
+ }
+ });
+
+ // Test for the close icon. Need style=SWT.CLOSE
+ // addCTabFolderListener is required :-(
+ newContainer.setUnselectedCloseVisible(false);
+ newContainer.addCTabFolder2Listener(new CTabFolder2Adapter() {
+
+ @Override
+ public void close(CTabFolderEvent event) {
+ int pageIndex = newContainer.indexOf((CTabItem) event.item);
+ event.doit = false;
+ fireItemClosed(event, pageIndex);
+ }
+ });
+ return newContainer;
+ }
+
+ /**
+ * Dispose internal resources.
+ */
+ public void dispose() {
+ if (tabFolder.isDisposed())
+ return;
+
+ detachListeners(tabFolder, false);
+ tabFolder.dispose();
+ }
+
+ /**
+ * Copied from org.eclipse.ui.internal.presentations.util.AbstractTabFolder.attachListeners(Control, boolean)
+ */
+ protected void attachListeners(Control theControl, boolean recursive) {
+
+ ToolTip tip;
+
+ // Both following methods listen to the same event.
+ // So use only one of them
+ theControl.addListener(SWT.MenuDetect, menuListener);
+ theControl.addMenuDetectListener(menuDetectListener);
+ // Both listener works. Choose one
+ PresentationUtil.addDragListener(theControl, dragListener);
+ // theControl.addDragDetectListener(dragDetectListener);
+ // Listen on mouse enter event.
+// theControl.addListener(SWT.MouseEnter, mouseEnterListener);
+ theControl.addListener(SWT.MouseUp, mouseUpListener);
+// tabFolder.addSelectionListener(selectionListener);
+// tabFolder.addTraverseListener(traverseListener);
+
+ if (recursive && theControl instanceof Composite) {
+ Composite composite = (Composite) theControl;
+ Control[] children = composite.getChildren();
+
+ for (int i = 0; i < children.length; i++) {
+ Control control = children[i];
+
+ attachListeners(control, recursive);
+ }
+ }
+ }
+
+ /**
+ * Copied from org.eclipse.ui.internal.presentations.util.AbstractTabFolder.detachListeners(Control, boolean)
+ */
+ protected void detachListeners(Control theControl, boolean recursive) {
+ theControl.removeListener(SWT.MenuDetect, menuListener);
+ theControl.removeMenuDetectListener(menuDetectListener);
+ //
+ PresentationUtil.removeDragListener(theControl, dragListener);
+ // theControl.removeDragDetectListener(dragDetectListener);
+ theControl.removeListener(SWT.MouseUp, mouseUpListener);
+
+ if (recursive && theControl instanceof Composite) {
+ Composite composite = (Composite) theControl;
+ Control[] children = composite.getChildren();
+
+ for (int i = 0; i < children.length; i++) {
+ Control control = children[i];
+
+ detachListeners(control, recursive);
+ }
+ }
+ }
+
+ protected void handleContextMenu(Point displayPos, Event e) {
+ // if (isOnBorder(displayPos)) {
+ // return;
+ // }
+
+ CTabItem tab = getItem(displayPos);
+
+ System.out.println(this.getClass().getName() + ".handleContextMenu() for item=" + tab);
+ // fireEvent(TabFolderEvent.EVENT_SYSTEM_MENU, tab, displayPos);
+ listenersManager.fireContextMenuEvent(tab, e);
+ }
+
+ /**
+ * Called when drag start. From here, DragUtil.performDrag() is called, which start the
+ * dragging process. DragUtil.performDrag() will contains the tabFolder or the dragged tab.
+ */
+ protected void handleDragStarted(Point displayPos, Event e) {
+
+ // if (isOnBorder(displayPos)) {
+ // return;
+ // }
+
+ CTabItem tab = getItem(displayPos);
+ System.out.println(this.getClass().getName() + ".handleDragStarted() for item=" + tab);
+ // fireEvent(TabFolderEvent.EVENT_DRAG_START, tab, displayPos);
+
+ boolean allowSnapping = true;
+ Rectangle sourceBounds = Geometry.toDisplay(tabFolder.getParent(), tabFolder.getBounds());
+ if (tab == null) { // drag folder
+ DragUtil.performDrag(tabFolder, sourceBounds, displayPos, allowSnapping);
+ } else { // drag item
+ DragUtil.performDrag(tab, sourceBounds, displayPos, allowSnapping);
+ }
+ }
+
+ /**
+ *
+ * @param displayPos
+ * @param e
+ * TODO REmove, it is not used.
+ */
+ private void handleDragDetectStarted(Point displayPos, DragDetectEvent e) {
+
+ // if (isOnBorder(displayPos)) {
+ // return;
+ // }
+
+ CTabItem tab = getItem(displayPos);
+ System.out.println(this.getClass().getName() + ".handleDragDetectStarted() for item=" + tab);
+ // fireEvent(TabFolderEvent.EVENT_DRAG_START, tab, displayPos);
+ }
+
+ /**
+ * Handle menu detect.
+ * TODO Connect menu staff here.
+ * @param displayPos
+ * @param e
+ */
+ private void handleMenuDetect(Point displayPos, MenuDetectEvent e) {
+
+ if (isOnBorder(displayPos)) {
+ return;
+ }
+
+ CTabItem tab = getItem(displayPos);
+ System.out.println(this.getClass().getName() + ".handleMenuDetectStarted() for item=" + tab);
+ // fireEvent(TabFolderEvent.EVENT_DRAG_START, tab, displayPos);
+ listenersManager.fireMenuDetectEvent(tab, e);
+ }
+
+ /**
+ * Returns true iff the given point is on the border of the folder. By default, double-clicking,
+ * context menus, and drag/drop are disabled on the folder's border.
+ *
+ * @param toTest
+ * a point (display coordinates)
+ * @return true iff the point is on the presentation border
+ * @since 3.1
+ */
+ private boolean isOnBorder(Point toTest) {
+ Control content = getControl();
+ if (content != null) {
+ Rectangle displayBounds = DragUtil.getDisplayBounds(content);
+
+ if (tabFolder.getTabPosition() == SWT.TOP) {
+ return toTest.y >= displayBounds.y;
+ }
+
+ if (toTest.y >= displayBounds.y && toTest.y < displayBounds.y + displayBounds.height) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the item under the specified position.
+ */
+ public CTabItem getItem(Point toFind) {
+ CTabItem[] items = tabFolder.getItems();
+
+ for (int i = 0; i < items.length; i++) {
+ CTabItem item = items[i];
+
+ if (getItemBounds(item).contains(toFind)) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ public int getItemIndex(Point pt) {
+ CTabItem item = tabFolder.getItem(pt);
+ if(item == null)
+ return -1;
+ return getItemIndex(item);
+ }
+
+ /**
+ * Get the rectangle bounding the item, in the parent coordinates. Utility method. Can be moved somewhere else.
+ */
+ public Rectangle getItemBounds(CTabItem item) {
+ return Geometry.toDisplay(item.getParent(), item.getBounds());
+ }
+
+ /**
+ * Fire a page closed event. This event is fired when the close item is pressed. The item is not closed yet. By default, the item is closed after the event. The item is not closed if event.doit is
+ * set to false.
+ *
+ */
+ protected void fireItemClosed(CTabFolderEvent event, int pageIndex) {
+ System.out.println("fireItemClosed: page=" + pageIndex);
+ listenersManager.fireItemClosed(event, pageIndex);
+
+ }
+
+ /**
+ * Fire a PageChangeEvent.
+ */
+ protected void firePageChange(int newPageIndex) {
+ System.out.println("firePageChange: page=" + newPageIndex);
+ listenersManager.firePageChange(newPageIndex);
+ }
+
+ /**
+ * @return the tabFolder
+ */
+ public CTabFolder getTabFolder() {
+ return tabFolder;
+ }
+
+ /**
+ * Get bounds of the tabs area in display coordinate.
+ */
+ public Rectangle getTabArea() {
+ Rectangle bounds = DragUtil.getDisplayBounds(tabFolder);
+ // Rectangle bounds = tabFolder.getBounds();
+ //
+ if (tabFolder.getTabPosition() == SWT.TOP) {
+ bounds.height = tabFolder.getTabHeight();
+ } else { // bottom
+ bounds.y = bounds.y + bounds.height - tabFolder.getTabHeight();
+ bounds.height = tabFolder.getTabHeight();
+ }
+
+ return bounds;
+
+ // Rectangle bounds = DragUtil.getDisplayBounds(tabFolder);
+ // Rectangle res = Geometry.getExtrudedEdge(bounds, tabFolder.getTabPosition(), tabFolder.getTabHeight());
+ // return res;
+ }
+
+ /**
+ * Get the index of the draggedObject
+ *
+ * @param draggedObject
+ * draggedObject should be of type CTabFolder or CTabItem (as provided by handleDragStarted())
+ */
+ static public int getDraggedObjectTabIndex(Object draggedObject) {
+ if (draggedObject instanceof CTabItem) {
+ CTabItem item = (CTabItem) draggedObject;
+ int index = getItemIndex(item);
+ return index;
+ } else if (draggedObject instanceof CTabFolder) {
+ return -1;
+ }
+
+ return -2;
+ }
+
+ /**
+ * Get the item index or -1 if not found.
+ */
+ static private int getItemIndex(CTabItem item) {
+ CTabItem[] items = item.getParent().getItems();
+
+ for (int i = 0; i < items.length; i++) {
+ CTabItem cur = items[i];
+
+ if (cur == item) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Get the event manager.
+ * The event manager can be used to listen to events.
+ * @return
+ */
+ public EventsManager getEventManager() {
+ return listenersManager;
+ }
+
+ /**
+ * Interface to ne implemented by listeners on PTabFodler events.
+ *
+ * @author dumoulin
+ *
+ */
+ public interface IPTabFolderListener {
+ /**
+ *
+ * @param tab
+ * @param event
+ */
+ public void menuDetectEvent(CTabItem tab, MenuDetectEvent event);
+ public void contextMenuDetectEvent(CTabItem tab, Event event);
+ public void itemClosedEvent(CTabFolderEvent event, int pageIndex);
+ public void pageChangeEvent(int newPageIndex);
+ }
+
+ /**
+ * Internal implementations.
+ * Implements a list of listeners.
+ * @author dumoulin
+ *
+ */
+ public class EventsManager {
+ /**
+ * List of event listeners.
+ */
+ List<IPTabFolderListener> listeners = new ArrayList<IPTabFolderListener>();
+
+ /**
+ * Add a listener
+ * @param listener
+ */
+ public void addListener( IPTabFolderListener listener)
+ {
+ if(listeners.contains(listener))
+ return;
+
+ listeners.add(listener);
+ }
+
+ /**
+ * Remove a listener
+ * @param listener
+ */
+ public void removeListener( IPTabFolderListener listener)
+ {
+ listeners.remove(listener);
+ }
+
+ /**
+ * @param tab
+ * @param e
+ */
+ public void fireContextMenuEvent(CTabItem tab, Event event) {
+ for(IPTabFolderListener cur : listeners)
+ {
+ cur.contextMenuDetectEvent(tab, event);
+ }
+ }
+
+ /**
+ * @param event
+ * @param pageIndex
+ */
+ private void fireItemClosed(CTabFolderEvent event, int pageIndex) {
+ for(IPTabFolderListener cur : listeners)
+ {
+ cur.itemClosedEvent(event, pageIndex);
+ }
+ }
+
+ /**
+ * @param newPageIndex
+ */
+ private void firePageChange(int newPageIndex) {
+ for(IPTabFolderListener cur : listeners)
+ {
+ cur.pageChangeEvent(newPageIndex);
+ }
+ }
+
+ /**
+ * Fire the event to all listeners
+ * @param e
+ * @param tab
+ */
+ private void fireMenuDetectEvent(CTabItem tab, MenuDetectEvent e)
+ {
+ for(IPTabFolderListener cur : listeners)
+ {
+ cur.menuDetectEvent(tab, e);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PagePart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PagePart.java
new file mode 100644
index 00000000000..dc13237e9d2
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PagePart.java
@@ -0,0 +1,153 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+
+/**
+ * This class represent a leaf part that is a part containing an editor or a component.
+ *
+ * @author dumoulin
+ */
+public abstract class PagePart extends AbstractPart {
+
+ /** Raw model associated to this part. We store it because the PartModel do not provide it */
+ protected Object rawModel;
+
+ /** Parent part of this Part */
+ protected TabFolderPart parent;
+
+
+ /**
+ * Constructor.
+ * @param sashWindowsContainer
+ */
+ public PagePart(TabFolderPart parent, Object rawModel) {
+ super(parent.getSashWindowContainer());
+ this.parent = parent;
+ this.rawModel = rawModel;
+ }
+
+ /**
+ * Orphan this part.
+ */
+ abstract public void orphan() ;
+
+ /**
+ * Visit this part.
+ *
+ * @param visitor
+ */
+ abstract public void visit(IPartVisitor visitor);
+
+ /**
+ * Locates the part that intersects the given point and that have the expected type.
+ * For a leaf, return the leaf if it is of the expected type.
+ *
+ * @param position
+ * @param expectedTileType
+ * @return
+ */
+ public AbstractPart findPartAt(Point position, Class<?> expectedTileType) {
+
+ if(expectedTileType == this.getClass())
+ return this;
+
+ return null;
+ }
+
+ /**
+ * Create the control of this Part, and children's controls.
+ * @param parent
+ */
+ abstract public void createPartControl(Composite parent);
+
+ /**
+ * Get the control associated to this Part.
+ * @return
+ */
+ abstract public Control getControl() ;
+
+ /**
+ * reparent this Part with the specified new parent.
+ * The part is marked as reparented.
+ * @param parent
+ */
+ abstract public void reparent(TabFolderPart parent);
+
+ /**
+ * Add the tree of parts starting from this part.
+ * As we are a leaf, add itself only.
+ * @param partMap
+ */
+ public void fillPartMap(PartLists partMap) {
+ partMap.addLeaf(this);
+ garbageState = GarbageState.UNCHANGED;
+ }
+
+ /**
+ * Get the raw model associated to this Part.
+ * @return
+ */
+ protected Object getRawModel() {
+ return rawModel;
+ }
+
+ /**
+ * Return a title for this part. This title can be used by parent to be shown
+ * in tabs ...
+ * To be implemented by subclasses.
+ * @return The title or null.
+ */
+ public String getPartTitle() {
+ return null;
+ }
+
+ /**
+ * Return a icon for this part. This title can be used by parent to be shown
+ * in tabs ...
+ * To be implemented by subclasses.
+ *
+ * @return The icon or null.
+ */
+ public Image getPartIcon() {
+ return null;
+ }
+
+ /**
+ * Set focus on the SWT control associated to this PagePart.
+ * Used by the ActivePageTracker.
+ */
+ abstract public void setFocus();
+
+ /**
+ * Garbage the part.
+ */
+ abstract public void garbage();
+
+ /**
+ * Return true if the part is associated to the specified rawModel.
+ * Return false otherwise.
+ * @param realModel
+ * @return
+ */
+ public boolean isPartFor(Object realModel) {
+ return this.rawModel == realModel;
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PartLists.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PartLists.java
new file mode 100644
index 00000000000..7bcbfc7329f
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PartLists.java
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.papyrus.sasheditor.sash.EditorTile;
+import org.eclipse.papyrus.sasheditor.sash.ITilePart;
+
+
+/**
+ * This class contains lists of parts, regardless of the part parents.
+ * There is two lists: one for the pane Parts and one for the Leaf Parts.
+ * This class is used when refreshing the SashesContainer: a new instance is created
+ * and filled with existing parts. Then the list is carried with each pane refresh methods.
+ *
+ * @author cedric dumoulin
+ */
+public class PartLists {
+
+ private List<PagePart> pageParts = new ArrayList<PagePart>();
+ private List<AbstractPanelPart> panelParts = new ArrayList<AbstractPanelPart>();
+
+ /**
+ * Search for a Part associated to the specified newModel.
+ * Return the part or null if none is found.
+ * @param rawModel
+ * @return
+ */
+ public PagePart findPagePartFor(Object rawModel) {
+
+ for (PagePart part : pageParts) {
+ if (part.isPartFor(rawModel))
+ return part;
+ }
+ return null;
+ }
+
+ /**
+ * Find the pane part for the specified rawModel.
+ * Return the found part or null
+ *
+ * @param rawModel The raw model for which a part is lookup.
+ * @return
+ */
+ public AbstractPanelPart findPartFor(Object rawModel) {
+
+ for (AbstractPanelPart part : panelParts) {
+ if (part.isPartFor(rawModel))
+ return part;
+ }
+
+ return null;
+ }
+
+ /**
+ * Add a leaf part to the lists.
+ * @param pagePart
+ */
+ public void addLeaf(PagePart pagePart) {
+ pageParts.add(pagePart);
+ }
+
+ /**
+ * Add the partPane to the lists.
+ * @param panelPart
+ */
+ public void addPart(AbstractPanelPart panelPart) {
+ panelParts.add(panelPart);
+
+ }
+
+ /**
+ * Garbage orphaned elements.
+ */
+ public void garbage()
+ {
+ // Remove orphaned part (no more used)
+ for (AbstractPanelPart part : panelParts) {
+ if (part.isOrphaned())
+ part.dispose();
+ }
+
+ // Remove orphaned part (no more used)
+ for (PagePart part : pageParts) {
+ if (part.isOrphaned())
+ part.garbage();
+ }
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PartVisitor.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PartVisitor.java
new file mode 100644
index 00000000000..e0b050e10a8
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/PartVisitor.java
@@ -0,0 +1,130 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+
+/**
+ * Visitor implementation allowing to visit the hierarchy of Parts.
+ * @author dumoulin
+ *
+ */
+public class PartVisitor implements IPartVisitor {
+
+ /**
+ * Visit the specified type, and then visit the childs..
+ * @param folder
+ */
+ public void accept(TabFolderPart part) {
+ acceptTabFolderPart(part);
+ // Visit the children
+ part.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the childs..
+ * @param folder
+ */
+ public void accept(RootPart part) {
+ acceptRootPart(part);
+ // Visit the children
+ part.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the children..
+ * @param folder
+ */
+ public void accept(SashPanelPart part) {
+ acceptSashPanelPart(part);
+ // Visit the children
+ part.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the children..
+ * @param folder
+ */
+ public void accept(TabItemPart part) {
+ acceptTabItemPart(part);
+ // Visit the children
+ part.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the children..
+ * @param part
+ */
+ public void accept(EditorPart part) {
+ acceptEditorTile(part);
+ // Visit the children
+ part.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the children ..
+ * @param part
+ */
+ public void accept(ComponentPart part) {
+ acceptEditorTile(part);
+ // Visit the children
+ part.visitChildren(this);
+ }
+
+
+ // ----------------------------------------------
+
+ /**
+ * Visit the specified type.
+ * @param part
+ */
+ protected void acceptRootPart(RootPart part) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param part
+ */
+ protected void acceptSashPanelPart(SashPanelPart part) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param part
+ */
+ protected void acceptTabFolderPart(TabFolderPart part) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param part
+ */
+ protected void acceptTabItemPart(TabItemPart part) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param part
+ */
+ protected void acceptEditorTile(EditorPart part) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param part
+ */
+ protected void acceptEditorTile(ComponentPart part) {
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ReplaceableSashForm.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ReplaceableSashForm.java
new file mode 100644
index 00000000000..d7f7673cac0
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ReplaceableSashForm.java
@@ -0,0 +1,71 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Allows to replace one of the window
+ */
+public class ReplaceableSashForm extends SashForm {
+
+ private Composite leftComposite;
+
+ private Composite rightComposite;
+
+ public ReplaceableSashForm(Composite parent, int style) {
+ super(parent, style);
+
+ leftComposite = new Composite(this, 0);
+ leftComposite.setLayout(new FillLayout());
+ rightComposite = new Composite(this, 0);
+ rightComposite.setLayout(new FillLayout());
+ }
+
+ public Composite getLeftParent() {
+ return leftComposite;
+ }
+
+ public Composite getRightParent() {
+ return rightComposite;
+ }
+
+ /**
+ * Reparent the provided control to have the leftPart parent.
+ */
+ public void setLeftControl(Control control) {
+ if (leftComposite == null) {
+ leftComposite = new Composite(this, 0);
+ }
+
+ // reparent the control
+ control.setParent(leftComposite);
+ }
+
+ /**
+ * Reparent the provided control to have the leftPart parent.
+ */
+ public void setRightControl(Control control) {
+ if (rightComposite == null) {
+ rightComposite = new Composite(this, 0);
+ }
+
+ // reparent the control
+ control.setParent(rightComposite);
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/RootPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/RootPart.java
new file mode 100644
index 00000000000..b0f98073ca8
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/RootPart.java
@@ -0,0 +1,307 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.sasheditor.contentprovider.IAbstractPanelModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashPanelModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Part used as root. This is the one with no parent and no model. This class is intended for local
+ * use only.
+ *
+ * @author dumoulin
+ *
+ * @param T Common ancestor for the model provided for the sash windows by the application.
+ * This is the type used externally by the application. Sash implementation don't use this type,
+ * it just carry it to ask for the appropriate wrapper. Concrete implementation can specify
+ * a type.
+
+ */
+@SuppressWarnings("restriction")
+public class RootPart extends AbstractPart implements IPanelParent {
+
+ /** The SWT container used as parent of all */
+ private Composite container;
+
+ /**
+ * The first SWT controled part;
+ */
+ private AbstractPanelPart child;
+
+ /** Raw model associated to this part. We store it because the PartModel do not provide it */
+ private Object rawModel;
+
+ /**
+ * Constructor.
+ */
+ public RootPart(SashWindowsContainer sashWindowsContainer) {
+ super(sashWindowsContainer);
+ }
+
+ /**
+ * Create the SWT controls.
+ * This Root as no control. Create the child part and call the same method on the child.
+ */
+ public void createPartControl(Composite parent) {
+ this.container = parent;
+ Object rawModel = getContentProvider().getRootModel();
+
+ // Create child part
+// child = createChildPart(rawModel);
+ }
+
+ /**
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#dispose()
+ */
+ public void dispose() {
+ if(child != null)
+ child.dispose();
+ }
+
+ /**
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#getControl()
+ */
+ public Composite getControl() {
+ return container;
+ }
+
+
+ /**
+ * Create the part for the specified child model.
+ * The controls are also builds.
+ *
+ * TODO: delegate to sashContainer.
+ * @param rootPart
+ * @param partModel
+ * @return
+ */
+ private AbstractPanelPart createChildPart(Object rawModel) {
+
+ // Create the child PartModel. Delegate creation to the root PartModel.
+ IAbstractPanelModel model = getPartModel().createChildSashModel(rawModel);
+
+ AbstractPanelPart createdPart;
+ if(model instanceof ITabFolderModel)
+ {
+ createdPart = new TabFolderPart(this, (ITabFolderModel)model, rawModel);
+ }
+ else if(model instanceof ISashPanelModel)
+ {
+ createdPart = new SashPanelPart(this, (ISashPanelModel)model, rawModel);
+ }
+ else
+ {
+ // error
+ throw new IllegalArgumentException("Can't create child part for model of type '"
+ + model.getClass().getName()
+ + "'");
+ // TODO: Return an error Part showing the exception instead of throwing it ?
+ }
+
+ // Create controls
+ createdPart.createPartControl(getControl());
+ return createdPart;
+
+ }
+
+ /**
+ * Get the PartModel associated to this Part.
+ * @return
+ */
+ private ISashWindowsContentProvider getPartModel() {
+ // The associated model for a root is the ContentProvider.
+ return getSashWindowContainer().getContentProvider();
+ }
+
+ /**
+ * Synchronize the
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#synchronize2(org.eclipse.papyrus.sasheditor.sash.PartMap)
+ */
+ public void synchronize2(PartLists partMap) {
+
+ // Synchronize locally the child
+ synchronizeChild(partMap);
+ // Synchronize recursively subchilds.
+ if(child != null)
+ child.synchronize2(partMap);
+
+ }
+
+ /**
+ * Synchronize locally the child
+ *
+ * @param partMap
+ */
+ private void synchronizeChild(PartLists partMap) {
+
+ // Get the new raw model
+ Object rawModel = getContentProvider().getRootModel();
+
+ // Check if old child exist
+ // If exist, check if the current part is associated to the checked model
+ //
+ if (child != null) {
+ // If the tile is already for the model, there is nothing to do.
+ if (child.isPartFor(rawModel))
+ return;
+ // The current tile is not for the model: mark it as orphan
+ child.orphan();
+ }
+
+ // The child tile need to be updated. Do it.
+ // First check if already exist in the map
+ AbstractPanelPart newPart = partMap.findPartFor(rawModel);
+ if (newPart != null) {
+ // Reparent the tile
+ newPart.reparent(this, getControl());
+ } else {
+ // create the tile and its control
+ newPart = createChildPart(rawModel);
+ }
+
+ // Now, put the tile on the right side
+ setChild(newPart);
+ }
+
+ /**
+ * Set the child. If a child already exist at the specified index, it is lost.
+ *
+ * @param newTile
+ */
+ private void setChild(AbstractPanelPart newTile) {
+ child = newTile;
+ }
+
+ /**
+ * Get the Composite used as parent for childs.
+ *
+ * @return
+ */
+ private Composite getChildParent() {
+ // This is the rootContainer
+ return container;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#fillPartMap(org.eclipse.papyrus.sasheditor.sash.PartMap)
+ */
+ public void fillPartMap(PartLists partMap) {
+ if(child != null)
+ child.fillPartMap(partMap);
+
+ }
+
+ /**
+ * Find The AbstractPart under the specified position.
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#findPart(org.eclipse.swt.graphics.Point)
+ */
+ public AbstractPart findPart(Point toFind) {
+ if(child != null)
+ try {
+ return child.findPart(toFind);
+ } catch (NotFoundException e) {
+ System.err.println(e.getMessage());
+ return null;
+ }
+ else
+ return null;
+ }
+
+// /**
+// * Locates the part that intersects the given point and that have the expected type
+// *
+// * @param toFind
+// * @return
+// */
+// public AbstractPart findPartAt(Point toFind, Class<?> tileType) {
+// return child.findPartAt(toFind, tileType);
+// }
+
+ /**
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#findPart(java.lang.Object)
+ */
+ public AbstractPart findPart(Object control) {
+ if(child!=null)
+ return child.findPart(control);
+ else
+ return null;
+ }
+
+// /**
+// * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#getDropTarget(java.lang.Object, org.eclipse.papyrus.sasheditor.sash.TabFolderPart, org.eclipse.swt.graphics.Point)
+// */
+// public IDropTarget getDropTarget(Object draggedObject, TabFolderPart sourcePart, Point position) {
+// return child.getDropTarget(draggedObject, sourcePart, position);
+// }
+
+ /**
+ * Do nothing. This node can't be orphaned
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#orphan()
+ */
+ public void orphan() {
+ // Do nothing. This node can't be orphaned
+ }
+
+ /**
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#isOrphaned()
+ */
+ public boolean isOrphaned() {
+ return false;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#getGarbageState()
+ */
+ public GarbageState getGarbageState() {
+ return GarbageState.UNCHANGED;
+ }
+
+ /**
+ * Accept the provided visitor.
+ * Call the corresponding accept method in the visitor.
+ * @param visitor
+ * @return
+ */
+ public void visit(IPartVisitor visitor) {
+ visitor.accept(this);
+ }
+
+ /**
+ * Visit the children of this Tile.
+ * @param visitor
+ */
+ public void visitChildren(IPartVisitor visitor) {
+ if(child!=null)
+ child.visit(visitor);
+ }
+
+ /**
+ * Show tile status.
+ */
+ protected void showStatus()
+ {
+ System.out.println( "rootPart (1)"
+ + ", disposed=" + container.isDisposed()
+ + ", visible=" + container.isVisible()
+ + ", " + this);
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashPanelPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashPanelPart.java
new file mode 100644
index 00000000000..5a805201112
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashPanelPart.java
@@ -0,0 +1,481 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import java.util.logging.Logger;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IAbstractPanelModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashPanelModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.internal.dnd.DragUtil;
+import org.eclipse.ui.internal.dnd.IDropTarget;
+
+/**
+ * Controller for a sash panel.
+ * A sash panel contain 2 children. It shows them in two windows separated by a sash.
+ * Implementation use one model, a {@link ISashPanelModel}. This model encapsulate the real model which
+ * is of an unknown type.
+ *
+ *
+ * @author dumoulin
+ *
+ * @param T Type of the external model representing the sash.
+ */
+@SuppressWarnings({ "restriction" })
+public class SashPanelPart extends AbstractPanelPart implements IPanelParent {
+
+ /** Log object */
+ Logger log = Logger.getLogger(getClass().getName());
+
+ /** Interface to the model */
+ protected ISashPanelModel model;
+
+ /** Raw model associated to this part. We store it because the PartModel do not provide it */
+ private Object rawModel;
+
+ /** Ordered set of currently shown diagrams (a left and right child, or upper and lower) TODO rename as children */
+ protected AbstractPanelPart[] currentChildParts = new AbstractPanelPart[2];
+
+ /**
+ * The container widget.
+ */
+ private ReplaceableSashForm container;
+
+ /**
+ * Direction of the sash: SWT.HORIZONTAL or SWT.VERTICAL. Default = SWT.HORIZONTAL
+ */
+ private int sashDirection = SWT.HORIZONTAL;
+
+ /**
+ * Constructor.
+ */
+ public SashPanelPart(IPanelParent parent, ISashPanelModel model, Object rawModel) {
+ super(parent);
+ this.model = model;
+ this.rawModel = rawModel;
+ this.sashDirection = model.getSashDirection();
+ }
+
+ /**
+ * Get the associated model.
+ */
+ public ISashPanelModel getPartModel() {
+ return model;
+ }
+
+ /**
+ * Fill the provided part map with this parts and recursively call children to fillin.
+ *
+ * @param partMap
+ */
+ public void fillPartMap(PartLists partMap) {
+ partMap.addPart(this);
+ for (AbstractPanelPart child : currentChildParts) {
+ child.fillPartMap(partMap);
+ }
+ garbageState = GarbageState.UNCHANGED;
+ }
+
+ /**
+ * Create local control, and the tree of children (TileParts AND controls). Create this TilePart control, and then Tile childs of this TilePart.
+ *
+ * @param parent
+ * @return Control
+ */
+ public void createPartControl(Composite parent) {
+
+ createControl(parent);
+// activate();
+// createChildrenControl();
+ }
+
+ /**
+ * Create local control. Does not create children.
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ protected void createControl(Composite parent) {
+ // container = new SashForm(parent, sashDirection);
+ container = new ReplaceableSashForm(parent, sashDirection);
+ }
+
+ /**
+ * Create the part for the specified child model.
+ * The controls are NOT build.
+ *
+ * TODO: delegate to sashContainer, remove duplication from here and RootPart.
+ * @param rootPart
+ * @param partModel
+ * @return
+ */
+ private AbstractPanelPart createChildPart(Object rawModel) {
+
+ // Create the child PartModel. Delegate creation to this part PartModel.
+ IAbstractPanelModel model = getPartModel().createChildSashModel(rawModel);
+
+ AbstractPanelPart createdPart;
+ if(model instanceof ITabFolderModel)
+ {
+ createdPart = new TabFolderPart(this, (ITabFolderModel)model, rawModel);
+ }
+ else if(model instanceof ISashPanelModel)
+ {
+ createdPart = new SashPanelPart(this, (ISashPanelModel)model, rawModel);
+ }
+ else
+ {
+ // error
+ throw new IllegalArgumentException("Can't create child part for model of type '"
+ + model.getClass().getName()
+ + "'");
+ // TODO: Return an error Part showing the exception instead of throwing it ?
+ }
+
+ return createdPart;
+ }
+
+ /**
+ * Create the part for the specified child model.
+ * The controls are build.
+ *
+ * TODO: delegate to sashContainer, remove duplication from here and RootPart.
+ * @param rootPart
+ * @param partModel
+ * @return
+ */
+ private AbstractPanelPart createChildPart(Object rawModel, int childIndex) {
+ // Create parts
+ AbstractPanelPart createdPart = createChildPart(rawModel);
+ // Create controls
+ createdPart.createPartControl(getChildParent(childIndex));
+ return createdPart;
+ }
+
+
+ /**
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#getControl()
+ */
+ public Composite getControl() {
+ return container;
+ }
+
+ /**
+ * Change the parent of this method. Reparent the Tile and the control. Normally, the control already exists.
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#reparent(org.eclipse.papyrus.sasheditor.sash.ITilePart)
+ */
+ @Override
+ public void reparent(IPanelParent newParent, Composite swtParent) {
+ parent = newParent;
+ // Create control if needed
+ // This can happen if the TilePart is just created after a refresh
+ // if(getControl() == null)
+ // {
+ // container = createContainer(parent.getControl());
+ // }
+ // Reparent the control
+ assert (getControl() != null);
+ // getControl().setParent(newParent.getControl()) ;
+ getControl().setParent(swtParent);
+ garbageState = GarbageState.REPARENTED;
+ }
+
+ /**
+ * Orphan this node, and children. The parent is set to null, but control is left unchanged. The node can be reattached with reparent().
+ *
+ * @see
+ * @return the parent
+ */
+ public void orphan() {
+
+ // orphan only if we are in UNCHANGED state
+ if (garbageState == GarbageState.UNCHANGED) {
+ garbageState = GarbageState.ORPHANED;
+ parent = null;
+ }
+ }
+
+ /**
+ * Dispose the TilePart and its controls.
+ *
+ * @param isRecursive
+ * If true, also dispose children.
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#dispose()
+ */
+ public void dispose(boolean isRecursive) {
+
+ // Dispose children if requested
+ if (isRecursive) {
+ for (AbstractPanelPart childModel : currentChildParts) {
+ if (childModel != null)
+ childModel.dispose();
+ }
+ }
+
+ // dispose local resources
+ if (container != null && !container.isDisposed()) {
+ container.dispose();
+ }
+ container = null;
+ }
+
+ /**
+ * Dispose the TilePart and its controls.
+ */
+ public void dispose() {
+ dispose(false);
+ }
+
+ /**
+ * Traverses the tree to find the part that intersects the given point
+ *
+ * @param toFind
+ * Point in display coordinate
+ * @return the part that intersects the given point
+ * @throws NotFoundException
+ */
+ public AbstractPart findPart(Point toFind) throws NotFoundException {
+
+ Rectangle bounds = DragUtil.getDisplayBounds(container); // container.getBounds();
+
+ // Try the left/up pane
+ bounds = DragUtil.getDisplayBounds(container.getLeftParent());
+ if (bounds.contains(toFind)) {
+ return currentChildParts[0].findPart(toFind);
+ }
+ bounds = DragUtil.getDisplayBounds(container.getRightParent());
+ if(bounds.contains(toFind))
+ {
+ // Return right part
+ return currentChildParts[1].findPart(toFind);
+ }
+
+ throw new NotFoundException("Can't find a part at '" + toFind + "'");
+
+
+ }
+
+ /**
+ * Locates the part that intersects the given point and that have the expected type
+ *
+ * @param toFind Position in Display coordinate.
+ * @return
+ */
+ public AbstractPart findPartAt(Point toFind, Class<?> expectedTileType) {
+
+ if(expectedTileType == this.getClass())
+ return this;
+
+ Rectangle bounds = DragUtil.getDisplayBounds(container); // container.getBounds();
+
+ if (isVertical()) {
+ if (toFind.y < bounds.y + (bounds.height / 2)) {
+ return currentChildParts[0].findPartAt(toFind, expectedTileType);
+ }
+ return currentChildParts[1].findPartAt(toFind, expectedTileType);
+ } else {
+ if (toFind.x < bounds.x + (bounds.width / 2)) {
+ return currentChildParts[0].findPartAt(toFind, expectedTileType);
+ }
+ return currentChildParts[1].findPartAt(toFind, expectedTileType);
+ }
+ }
+
+
+ /**
+ * Return true if this sash is vertical, false otherwise.
+ */
+ private boolean isVertical() {
+ return (container.getOrientation() == SWT.VERTICAL);
+ }
+
+ /**
+ * Find the part associated to the provided control.
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#findPart(org.eclipse.swt.widgets.Control)
+ */
+ public AbstractPart findPart(Object control) {
+ if (this.getControl() == control) {
+ return this;
+ }
+
+ AbstractPart node = currentChildParts[0].findPart(control);
+ if (node != null) {
+ return node;
+ }
+ node = currentChildParts[1].findPart(control);
+ if (node != null) {
+ return node;
+ }
+ return null;
+
+ }
+
+ /**
+ * SashPanelPart can't be a DropTarget. Do nothing.
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#getDropTarget(java.lang.Object, org.eclipse.swt.graphics.Point)
+ */
+ public IDropTarget getDropTarget(Object draggedObject, TabFolderPart sourcePart, Point position) {
+ return null;
+ }
+
+ /**
+ * Return true if the Part is for the specified real model. Return false otherwise.
+ *
+ * @param realModel The raw model to check
+ * @return
+ */
+ public boolean isPartFor(Object realModel) {
+ return getRawModel() == realModel;
+ }
+
+ /**
+ * Get the raw model associated to this part.
+ * @return
+ */
+ protected Object getRawModel() {
+ return rawModel;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#synchronize2(org.eclipse.papyrus.sasheditor.sash.PartMap)
+ */
+ public void synchronize2(PartLists partMap) {
+
+ // Compare currentChildParts and node model
+ assert (model.getChildren().size() == 2);
+
+ // Synchronize each child
+ for (int i = 0; i < 2 /*model.getChildModels().size()*/; i++) {
+ synchronizeChild(i, partMap);
+ }
+
+ // Now recursively call synchronize on childs.
+ for (int i = 0; i < currentChildParts.length; i++) {
+ currentChildParts[i].synchronize2(partMap);
+ // // Set the child controls at the right place
+ // if(i==0)
+ // container.moveAbove(currentChildParts[i].getControl());
+ // else
+ // container.moveBelow(currentChildParts[i].getControl());
+ //
+ }
+
+ }
+
+ /**
+ * Synchronize the specified child.
+ *
+ * @param childIndex
+ * index of the child to be synchronized
+ * @param existingParts
+ */
+ private void synchronizeChild(int childIndex, PartLists existingParts) {
+
+ Object newModel = model.getChildren().get(childIndex);
+
+ // Check if old child exist
+ // If exist, check if the current part is associated to the checked model
+ //
+ AbstractPanelPart currentChildPart = currentChildParts[childIndex];
+ if (currentChildPart != null) {
+ // If the tile is already for the model, there is nothing to do.
+ if (currentChildPart.isPartFor(newModel))
+ return;
+ // The current tile is not for the model: mark it as orphan
+ currentChildPart.orphan();
+ }
+
+ // The child part need to be updated. Do it.
+ // First check if already exist in the map
+ AbstractPanelPart newTile = existingParts.findPartFor(newModel);
+ if (newTile != null) {
+ // Reparent the tile
+ newTile.reparent(this, getChildParent(childIndex));
+ } else {
+ // create the tile and its control
+ newTile = createChildPart(newModel, childIndex);
+ }
+
+ // Now, put the tile on the right side
+ setChildToSide(newTile, childIndex);
+
+ }
+
+ /**
+ * Get the Composite parent that will be provided to the child.
+ *
+ * @param childIndex
+ * @return
+ */
+ private Composite getChildParent(int childIndex) {
+ // return container;
+ if (childIndex == 0)
+ return container.getLeftParent();
+ else
+ return container.getRightParent();
+
+ }
+
+ /**
+ * Set the provided child at the specified index. If a child already exist at the specified index, it is lost. The controls are set accordingly
+ *
+ * @param newTile
+ * @param childIndex
+ */
+ private void setChildToSide(AbstractPanelPart newTile, int childIndex) {
+ currentChildParts[childIndex] = newTile;
+
+ }
+
+ /**
+ * Accept the provided visitor.
+ * Call the corresponding accept method in the visitor.
+ * @param visitor
+ * @return
+ */
+ public void visit(IPartVisitor visitor) {
+ visitor.accept(this);
+ }
+
+ /**
+ * Visit the children of this Tile.
+ * @param visitor
+ */
+ public void visitChildren(IPartVisitor visitor) {
+ for( AbstractPanelPart child : currentChildParts)
+ {
+ child.visit(visitor);
+ }
+ }
+
+ /**
+ * Show tile status.
+ * Used for debug purpose
+ */
+ protected void showStatus()
+ {
+ System.out.println( "sash[" + currentChildParts.length + "]:"
+ + ", disposed=" + container.isDisposed()
+ + ", visible=" + container.isVisible()
+ + ", garbState=" + garbageState
+ + ", " + this);
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashWindowsContainer.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashWindowsContainer.java
new file mode 100644
index 00000000000..5a8f0ea5822
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashWindowsContainer.java
@@ -0,0 +1,554 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.papyrus.sasheditor.contentprovider.IComponentModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IEditorModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.internal.DragCursors;
+import org.eclipse.ui.internal.dnd.DragUtil;
+import org.eclipse.ui.internal.dnd.IDragOverListener;
+import org.eclipse.ui.internal.dnd.IDropTarget;
+
+
+/**
+ * Main entry class of the SashWindows system.
+ * This class allows to have a multitab window with sashes.
+ * The class require a ContentProvider describing the content to be shown.
+ * @author dumoulin
+ */
+public class SashWindowsContainer {
+
+ /**
+ * The content provider describing the sashes, folders and tabs.
+ */
+ private ISashWindowsContentProvider contentProvider;
+
+ /**
+ * The manager used to get Main editor properties like Site, ActionBars, ...
+ */
+ private IMultiEditorManager multiEditorManager;
+
+ /**
+ * Tracker tracking the current active page. The tracker also dosconnect last active page and connect
+ * the new one.
+ */
+ private ActivePageTracker activePageTracker;
+ /**
+ * The part used as root. We use an extra class as root in order to separate the code dedicated to
+ * ITilePart.
+ */
+ private RootPart rootPart;
+
+ /**
+ * The SWT container associated to this part. This is generally the container of the
+ * parent.
+ */
+ private Composite container;
+
+ /**
+ * The drop target.
+ */
+ protected DropTarget dropTarget;
+
+ /**
+ * Constructor.
+ * Build a Container without IEditor management. Trying to add a EditorPart will result in an Exception.
+ * The ContentProvider should not contain IEditorModel.
+ */
+ public SashWindowsContainer() {
+ this.multiEditorManager = null;
+ activePageTracker = new ActivePageTracker();
+ }
+
+ /**
+ * Constructor.
+ * Build a container with EditorPart management. The container will allow to add EditorPart
+ * (and thus IEditorModel to the ContentProvider).
+ */
+ public SashWindowsContainer(IMultiEditorManager multiEditorManager) {
+ this.multiEditorManager = multiEditorManager;
+ activePageTracker = new ActiveEditorAndPageTracker(multiEditorManager);
+ }
+
+ /**
+ * @return the contentProvider
+ */
+ protected ISashWindowsContentProvider getContentProvider() {
+ // Content provider should have been set.
+ assert(contentProvider != null);
+ // Double check for developement
+ if(contentProvider == null)
+ throw new IllegalStateException("ContentProvider should be set before calling any method requiring it.");
+
+ return contentProvider;
+ }
+
+ /**
+ * Set the content provider describing the sashes, folders and tabs.
+ * @param contentProvider the contentProvider to set
+ */
+ public void setContentProvider(ISashWindowsContentProvider contentProvider) {
+ this.contentProvider = contentProvider;
+ }
+
+ /**
+ * Creates control associated to this Container.
+ * This method should be called when the parent is build.
+ *
+ * @param parent
+ * The parent in which the editor should be created; must not be <code>null</code>.
+ */
+ public void createPartControl(Composite parent) {
+ this.container = parent;
+
+ rootPart = createRootPart();
+ // Create the tree of tile part.
+ rootPart.createPartControl(container);
+ // Create children
+ refreshTabs();
+ // postCreatePartControl();
+ // TODO reactivate next
+ initDrag(container);
+// activate();
+ }
+
+ /**
+ * Create the root part for the model.
+ */
+ private RootPart createRootPart() {
+ RootPart part = new RootPart(this);
+ return part;
+ }
+
+ /**
+ * The active leaf part has change.
+ * This method is called by inner parts whenever the active leaf part changes.
+ * Propagate the event.
+ *
+ * @param childPart
+ */
+ public void activeLeafChange(PagePart childPart) {
+ // TODO propagate to the ActivePageTracker
+ System.out.println("activeLeafChange("+childPart+")");
+ activePageTracker.setActiveEditor(childPart);
+ }
+
+ /**
+ * A change has happen in one of the inner parts. Relay the event.
+ * This method is called by inner parts whenever the event happen in one of the part.
+ *
+ * @param propertyId
+ */
+ public void firePropertyChange(int propertyId) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * Create the part for the specified newModel.
+ * @param parent The parent of the created part.
+ * @param partModel The model for which a part should be created.
+ * @return
+ */
+ protected PagePart createPagePart(TabFolderPart parent, IPageModel partModel, Object rawModel) {
+
+
+ if( partModel instanceof IEditorModel)
+ {
+ // Check if we can use IEditorModel
+ if(multiEditorManager == null)
+ throw new IllegalArgumentException("Container can't accept IEditorModel as no IMultiEditorManager is set. Please set a IMultiEditorManager.");
+
+ return new EditorPart(parent, (IEditorModel)partModel, rawModel, multiEditorManager);
+ }
+ else if( partModel instanceof IComponentModel)
+ {
+ return new ComponentPart(parent, (IComponentModel)partModel, rawModel);
+ }
+ else
+ {
+ // Return a default part
+ }
+
+ // TODO return a default part showing an error instead.
+ throw new IllegalArgumentException("No Part found for the model '" + rawModel + "'");
+ }
+
+ /**
+ * Get the active page.
+ * @return
+ */
+ private PagePart getActivePage() {
+ return activePageTracker.getActiveEditor();
+ }
+
+ /**
+ * Get the currently active editor, or null if none is active.
+ * @return
+ */
+ public IEditorPart getActiveEditor() {
+ PagePart pagePart = getActivePage();
+ if(pagePart instanceof EditorPart)
+ return ((EditorPart)pagePart).getIEditorPart();
+ else
+ return null;
+ }
+
+ /**
+ * The <code>AbstractMultiPageSashEditor</code> implementation of this
+ * <code>IWorkbenchPart</code> method sets focus on the active nested
+ * editor, if there is one.
+ * <p>
+ * Subclasses may extend or reimplement.
+ * </p>
+ */
+ public void setFocus() {
+ setFocus(getActivePage());
+ }
+
+ /**
+ * Sets focus to the control for the given page. If the page has an editor,
+ * this calls its <code>setFocus()</code> method. Otherwise, this calls
+ * <code>setFocus</code> on the control for the page.
+ *
+ * @param pageIndex
+ * the index of the page
+ */
+ private void setFocus(PagePart part) {
+ if(part!=null)
+ part.setFocus();
+ }
+
+ public void refreshTabs() {
+ System.out.println("start synchronize2() ------------------------");
+ showTilesStatus();
+
+ container.setRedraw(false);
+ // Create map of parts
+// PartMap<T> partMap = new PartMap<T>();
+ PartLists garbageMaps = new PartLists();
+ rootPart.fillPartMap(garbageMaps);
+
+ // Synchronize parts
+ rootPart.synchronize2(garbageMaps);
+
+
+ // Remove orphaned parts (no more used)
+ garbageMaps.garbage();
+
+ // Reenable SWT and force layout
+ container.setRedraw(true);
+ container.layout(true, true);
+ System.out.println("end synchronize2() ------------------------");
+ showTilesStatus();
+ }
+
+ /**
+ * Show the status of the different Tiles composing the sash system.
+ * Used for debug purpose.
+ */
+ protected void showTilesStatus()
+ {
+ ShowPartStatusVisitor visitor = new ShowPartStatusVisitor();
+ rootPart.visit(visitor);
+ }
+
+ /* ***************************************************** */
+ /* Drag and Drop methods */
+ /* ***************************************************** */
+
+ /**
+ *
+ */
+ private void initDrag(Composite container) {
+ DragUtil.addDragTarget(container, dragOverListener);
+
+ }
+
+ IDragOverListener dragOverListener = new IDragOverListener() {
+
+ /**
+ *
+ * @see org.eclipse.ui.internal.dnd.IDragOverListener#drag(org.eclipse.swt.widgets.Control, java.lang.Object, org.eclipse.swt.graphics.Point, org.eclipse.swt.graphics.Rectangle)
+ */
+ public IDropTarget drag(Control currentControl, Object draggedObject, Point position, Rectangle dragRectangle) {
+ System.out.println(SashWindowsContainer.this.getClass().getSimpleName() + ".drag(position=" + position + ", rectangle=" + dragRectangle + ")");
+ // if (!(draggedObject instanceof ITilePart)) {
+ // System.out.println("drag object is of bad type (" +draggedObject + "!=ITilePart)");
+ // return null;
+ // }
+
+ // @TODO remove the cast by changing the method. Only folder can be source and target
+ final TabFolderPart sourcePart = (TabFolderPart) rootPart.findPart(draggedObject); // (ITilePart) draggedObject;
+ // Compute src tab index
+ // @TODO move that and previous in the sender of drag event. Use a class containing both as draggedObject.
+ final int srcTabIndex = PTabFolder.getDraggedObjectTabIndex(draggedObject);
+
+ // if (!isStackType(sourcePart) && !isPaneType(sourcePart)) {
+ // return null;
+ // }
+
+ // boolean differentWindows = sourcePart.getWorkbenchWindow() != getWorkbenchWindow();
+ // boolean editorDropOK = ((sourcePart instanceof EditorPane) &&
+ // sourcePart.getWorkbenchWindow().getWorkbench() ==
+ // getWorkbenchWindow().getWorkbench());
+ // if (differentWindows && !editorDropOK) {
+ // return null;
+ // }
+
+ // If this container has no visible children
+ // if (getVisibleChildrenCount(this) == 0) {
+ // return createDropTarget(sourcePart, SWT.CENTER, SWT.CENTER, null);
+ // }
+
+ Rectangle containerDisplayBounds = DragUtil.getDisplayBounds(container);
+ AbstractPanelPart targetPart = null;
+ // ILayoutContainer sourceContainer = isStackType(sourcePart) ? (ILayoutContainer) sourcePart
+ // : sourcePart.getContainer();
+
+ // Check if the cursor is inside the container
+ if (containerDisplayBounds.contains(position)) {
+
+ System.out.println("Inside container bounds");
+ if (rootPart != null) {
+ targetPart = (AbstractPanelPart)rootPart.findPart(position);
+ // System.out.println("targetPart=" + targetPart
+ // + ", position=" + position
+ // + "container.toControl(position)=" + container.toControl(position));
+ }
+
+ if (targetPart != null) {
+ final Control targetControl = targetPart.getControl();
+
+ final Rectangle targetBounds = DragUtil.getDisplayBounds(targetControl);
+
+ int side = Geometry.getClosestSide(targetBounds, position);
+ int distance = Geometry.getDistanceFromEdge(targetBounds, position, side);
+ //
+ // // is the source coming from a standalone part
+ // boolean standalone = (isStackType(sourcePart)
+ // && ((PartStack) sourcePart).isStandalone())
+ // || (isPaneType(sourcePart)
+ // && ((PartPane) sourcePart).getStack()!=null
+ // && ((PartPane) sourcePart).getStack().isStandalone());
+ //
+ // // Only allow dropping onto an existing stack from different windows
+ // if (differentWindows && targetPart instanceof EditorStack) {
+ // IDropTarget target = targetPart.getDropTarget(draggedObject, position);
+ // return target;
+ // }
+ //
+ // Reserve the 5 pixels around the edge of the part for the drop-on-edge cursor
+ // Check if the target can handle the drop.
+ if (distance >= 5) {
+ // Otherwise, ask the part if it has any special meaning for this drop location
+ // @TODO remove cast; change return type of findPart()
+ IDropTarget target = targetPart.getDropTarget(draggedObject, (TabFolderPart) sourcePart, position);
+ if (target != null) {
+ return target;
+ }
+ }
+ //
+ if (distance > 30) {
+ // if (targetPart instanceof ILayoutContainer) {
+ // ILayoutContainer targetContainer = (ILayoutContainer)targetPart;
+ // if (targetContainer.allowsAdd(sourcePart)) {
+ side = SWT.CENTER;
+ // }
+ // }
+ }
+ //
+ // // If the part doesn't want to override this drop location then drop on the edge
+ //
+ // // A "pointless drop" would be one that will put the dragged object back where it started.
+ // // Note that it should be perfectly valid to drag an object back to where it came from -- however,
+ // // the drop should be ignored.
+ //
+ @SuppressWarnings("unused")
+ boolean pointlessDrop = false;
+
+ if (sourcePart == targetPart) {
+ pointlessDrop = true;
+ }
+ //
+ // if ((sourceContainer != null)
+ // && (sourceContainer == targetPart)
+ // && getVisibleChildrenCount(sourceContainer) <= 1) {
+ // pointlessDrop = true;
+ // }
+ //
+ // if (side == SWT.CENTER
+ // && sourcePart.getContainer() == targetPart) {
+ // pointlessDrop = true;
+ // }
+ //
+ int cursor = side;
+ //
+ // if (pointlessDrop) {
+ // side = SWT.NONE;
+ // cursor = SWT.CENTER;
+ // }
+ //
+ return createDropTarget(sourcePart, srcTabIndex, side, cursor, targetPart);
+ }
+ } else {
+ // Cursor is outside the container
+ System.out.println("Outside container bounds");
+ // We only allow dropping into a stack, not creating one
+ // if (differentWindows)
+ // return null;
+
+ int side = Geometry.getClosestSide(containerDisplayBounds, position);
+
+ boolean pointlessDrop = false;
+ //
+ // if ((isStackType(sourcePart) && sourcePart.getContainer() == this)
+ // || (sourcePart.getContainer() != null
+ // && isPaneType(sourcePart)
+ // && getVisibleChildrenCount(sourcePart.getContainer()) <= 1)
+ // && ((LayoutPart)sourcePart.getContainer()).getContainer() == this) {
+ // if (root == null || getVisibleChildrenCount(this) <= 1) {
+ // pointlessDrop = true;
+ // }
+ // }
+ //
+ int cursor = Geometry.getOppositeSide(side);
+
+ if (pointlessDrop) {
+ side = SWT.NONE;
+ }
+
+ return createDropTarget(sourcePart, srcTabIndex, side, cursor, null);
+ }
+ //
+ return null;
+ } // end method
+
+ };
+
+ /**
+ * Create the drop target
+ */
+ private DropTarget createDropTarget(final TabFolderPart sourcePart, int srcTabIndex, int side, int cursor, AbstractPart targetPart) {
+ if (dropTarget == null) {
+ dropTarget = new DropTarget(sourcePart, srcTabIndex, side, cursor, targetPart);
+ } else {
+ dropTarget.setTarget(sourcePart, srcTabIndex, side, cursor, targetPart);
+ }
+ return dropTarget;
+ }
+
+ /**
+ * Class implementing methods required by drop targets.
+ */
+ protected class DropTarget implements IDropTarget {
+
+ int count = 0;
+
+ int cursor = SWT.TOP;
+
+ private int side;
+
+ private AbstractPanelPart targetPart;
+
+ private int srcTabIndex;
+
+ private TabFolderPart sourcePart;
+
+ /**
+ * Constructor.
+ */
+ public DropTarget(TabFolderPart sourcePart, int srcTabIndex, int cursor, int side, AbstractPart targetPart) {
+ this.cursor = cursor;
+ this.side = side;
+ this.sourcePart = sourcePart;
+ this.srcTabIndex = srcTabIndex;
+ this.targetPart = (AbstractPanelPart)targetPart;
+ }
+
+ public void setTarget(TabFolderPart sourcePart, int srcTabIndex, int cursor, int side, AbstractPart targetPart) {
+ this.cursor = cursor;
+ this.side = side;
+ this.sourcePart = sourcePart;
+ this.srcTabIndex = srcTabIndex;
+ this.targetPart = (AbstractPanelPart)targetPart;
+ }
+
+ /**
+ * A folder is dropped.
+ *
+ * @see org.eclipse.ui.internal.dnd.IDropTarget#drop()
+ */
+ public void drop() {
+ System.out.println(SashWindowsContainer.this.getClass().getSimpleName() + ".drop(source=" + sourcePart + ", target=" + targetPart + "side=" + side);
+
+ // @TODO remove next cast
+ if (side == SWT.CENTER) { // Add to target folder
+ contentProvider.movePage(sourcePart.getPartModel(), srcTabIndex, ((TabFolderPart) targetPart).getPartModel(), -1);
+ } else { // Create a new folder
+ contentProvider.createFolder(sourcePart.getPartModel(), srcTabIndex, ((TabFolderPart) targetPart).getPartModel(), side);
+ }
+ }
+
+ /**
+ * Return the cursor used during drag.
+ *
+ * @see org.eclipse.ui.internal.dnd.IDropTarget#getCursor()
+ */
+ public Cursor getCursor() {
+ System.out.println(SashWindowsContainer.this.getClass().getSimpleName() + ".getCursor()-" + count++);
+ return DragCursors.getCursor(DragCursors.positionToDragCursor(cursor));
+
+ }
+
+ public Rectangle getSnapRectangle() {
+ System.out.println(SashWindowsContainer.this.getClass().getSimpleName() + ".getSnapRectangle(" + "sourcePart=" + sourcePart + ", targetPart=" + targetPart + ", side=" + side);
+ Rectangle targetDisplayBounds;
+
+ if (targetPart != null) {
+ targetDisplayBounds = DragUtil.getDisplayBounds(targetPart.getControl());
+ } else {
+ // targetBounds = DragUtil.getDisplayBounds(getParent());
+ targetDisplayBounds = DragUtil.getDisplayBounds(container);
+ }
+
+ if (side == SWT.CENTER || side == SWT.NONE) {
+ return targetDisplayBounds;
+ }
+
+ int distance = Geometry.getDimension(targetDisplayBounds, !Geometry.isHorizontal(side));
+
+ return Geometry.getExtrudedEdge(targetDisplayBounds, (int) (distance * getDockingRatio(sourcePart, targetPart)), side);
+ }
+
+ protected float getDockingRatio(AbstractPart dragged, AbstractPart target) {
+ return 0.5f;
+ }
+
+ }
+
+
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashWindowsException.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashWindowsException.java
new file mode 100644
index 00000000000..28a9b6b18d1
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/SashWindowsException.java
@@ -0,0 +1,56 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+
+/**
+ * Main Exception from the SashWindowsSystem.
+ * @author dumoulin
+ */
+public class SashWindowsException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public SashWindowsException() {
+ }
+
+ /**
+ * @param message
+ */
+ public SashWindowsException(String message) {
+ super(message);
+ }
+
+ /**
+ * @param cause
+ */
+ public SashWindowsException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public SashWindowsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ShowPartStatusVisitor.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ShowPartStatusVisitor.java
new file mode 100644
index 00000000000..0998feba7c5
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/ShowPartStatusVisitor.java
@@ -0,0 +1,112 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+
+/**
+ * Visitor used to show the status of the different Tiles composing the sash system.
+ * @author dumoulin
+ *
+ */
+@SuppressWarnings("unchecked")
+public class ShowPartStatusVisitor extends PartVisitor {
+ int level=1;
+
+ /**
+ * @param tile
+ */
+
+ @Override
+ public void accept(RootPart tile) {
+ indent();
+ tile.showStatus();
+ // System.out.println( "root:" + tile );
+ level++;
+ super.accept(tile);
+ level--;
+ }
+
+ /**
+ *
+ */
+ private void indent() {
+ if(level<1)
+ {
+ //error
+ return;
+ }
+
+ for(int i=0; i<level-1; i++)
+ {
+ System.out.print("| ");
+ }
+ // last segment
+ System.out.print("+ ");
+
+ }
+
+ /**
+ * @param tile
+ */
+ @Override
+ public void accept(SashPanelPart tile) {
+ indent();
+ tile.showStatus();
+ // System.out.println( "sash:" + tile );
+ level++;
+ super.accept(tile);
+ level--;
+ }
+
+ /**
+ * @param tile
+ */
+ @Override
+ public void accept(TabFolderPart tile) {
+ indent();
+ tile.showStatus();
+ // System.out.println( "folder:" + tile );
+ level++;
+ super.accept(tile);
+ level--;
+ }
+
+ /**
+ * @param tile
+ */
+ @Override
+ public void accept(EditorPart tile) {
+ indent();
+ tile.showStatus();
+ // System.out.println( "editor:" + tile );
+ level++;
+ super.accept(tile);
+ level--;
+ }
+
+ /**
+ * @param tile
+ */
+ @Override
+ public void accept(ComponentPart tile) {
+ indent();
+ tile.showStatus();
+ // System.out.println( "editor:" + tile );
+ level++;
+ super.accept(tile);
+ level--;
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/TabFolderPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/TabFolderPart.java
new file mode 100644
index 00000000000..22e196dd64d
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/TabFolderPart.java
@@ -0,0 +1,1041 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.papyrus.sasheditor.internal.eclipsecopy.AbstractTabFolderPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabFolderEvent;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.MenuDetectEvent;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.internal.DragCursors;
+import org.eclipse.ui.internal.dnd.DragUtil;
+import org.eclipse.ui.internal.dnd.IDragOverListener;
+import org.eclipse.ui.internal.dnd.IDropTarget;
+
+/**
+ * Controller associated to a tabfolder.
+ *
+ *
+ *
+ * Extends MultiPageEditor to inherit methods implementations.
+ *
+ * @param T Common ancestor for the model provided for the sash windows by the application.
+ * This is the type used externally by the application. Sash implementation don't use this type,
+ * it just carry it to ask for the appropriate wrapper. Concrete implementation can specify
+ * a type.
+ *
+ * TODO : be more precise for the generic type ?
+ * TODO : Listen to the page change event, and call setActivePage().
+ */
+@SuppressWarnings("restriction")
+public class TabFolderPart extends AbstractTabFolderPart {
+
+ /** Log object */
+ Logger log = Logger.getLogger(getClass().getName());
+
+ /** Interface to the model */
+ protected ITabFolderModel partModel;
+
+ /** Raw model associated to this part. We store it because the PartModel do not provide it */
+ private Object rawModel;
+
+ /** The wrapper around the CTabFolder. This represent the SWT control associated to this part.*/
+ protected PTabFolder pTabFolder;
+
+ /** Ordered set of currently shown diagrams (list of their models) TODO remove */
+ protected TabPartList currentTabItems = new TabPartList();
+
+ /** The drop target associated to this folderPart */
+ private DropTarget dropTarget;
+
+ /**
+ * Track the mouse hover and fire appropriate event.
+ */
+ private MouseHoverTracker mouseHoverTracker;
+
+ /**
+ * Tooltip Manager to manage thumbnail images tooltips.
+ */
+ private ImageToolTipManager toolTipManager;
+
+ /**
+ * Listener on DragOver event.
+ */
+ IDragOverListener dragOverListener = new IDragOverListener() {
+
+ /**
+ *
+ * @see org.eclipse.ui.internal.dnd.IDragOverListener#drag(org.eclipse.swt.widgets.Control, java.lang.Object, org.eclipse.swt.graphics.Point, org.eclipse.swt.graphics.Rectangle)
+ */
+ public IDropTarget drag(Control currentControl, Object draggedObject, Point position, Rectangle dragRectangle) {
+ // System.out.println(TabFolderPart.this.getClass().getSimpleName() + ".drag()");
+ System.out.println(this + ".drag()");
+ return null;
+ }
+ };
+
+ /**
+ * Listener on CTabFolder events.
+ */
+ private PTabFolder.IPTabFolderListener cTabFolderEventListener = new PTabFolder.IPTabFolderListener() {
+
+ public void contextMenuDetectEvent(CTabItem tab, Event event) {
+ System.out.println("contextMenuDetect()");
+ }
+
+ /**
+ * The close cross has been pressed. Remove the corresponding tab.
+ * {@inheritDoc}
+ */
+ public void itemClosedEvent(CTabFolderEvent event, int pageIndex) {
+ System.out.println("itemClosedEvent()");
+ // TODO: call appropriate method (to be determine)
+// model.removeTab(pageIndex);
+// getSashWindowContainer().getContentProvider().removeTab(model, pageIndex);
+ getContentProvider().removePage(partModel, pageIndex );
+ }
+
+ public void menuDetectEvent(CTabItem tab, MenuDetectEvent event) {
+ System.out.println("menuDetectEvent()");
+ }
+
+ /**
+ * Listen to pageChange event, and propagate to TabFolderPart.
+ * @param newPageIndex
+ */
+ public void pageChangeEvent(int newPageIndex) {
+ pageChange(newPageIndex);
+ }
+
+ };
+
+ /**
+ * Constructor.
+ *
+ * @param nestedPartManager
+ * @param partModel
+ * @param rawModel
+ *
+ */
+ public TabFolderPart(IPanelParent parent, ITabFolderModel partModel, Object rawModel) {
+ super(parent);
+ this.partModel = partModel;
+ this.rawModel = rawModel;
+ }
+
+ /**
+ * Get the associated model.
+ */
+ protected ITabFolderModel getPartModel() {
+ return partModel;
+ }
+
+ /**
+ * Activate the part. Register as listener to required services.
+ */
+ private void activate()
+ {
+ // Listen to page changes
+ pTabFolder.getEventManager().addListener(cTabFolderEventListener);
+ mouseHoverTracker = new MouseHoverTracker(pTabFolder.getControl());
+ toolTipManager = new ImageToolTipManager();
+ }
+
+ /**
+ * Deactivate this part.
+ * Unregistered from required service. Do not dispose the part.
+ */
+ private void deactivate()
+ {
+ // Listen to page changes
+ pTabFolder.getEventManager().removeListener(cTabFolderEventListener);
+ }
+
+ /**
+ * Fill the provided part map with this parts and recursively call children to fillin.
+ *
+ * @param partMap
+ */
+ public void fillPartMap(PartLists partMap) {
+ partMap.addPart(this);
+ garbageState = GarbageState.UNCHANGED;
+
+ for( TabItemPart child : currentTabItems)
+ {
+ child.fillPartMap(partMap);
+ }
+ }
+
+ /**
+ * Creates the control tree associated to this part.
+ * Create the control for this part, and eventually recursively call the method for the childs, if any.
+ *
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+
+ createControl(parent);
+// createPages();
+ // model.addChangeListener(modelListener);
+ // model.activate();
+ activate();
+ }
+
+ /**
+ * Add a new page at the end of pages. A new tab is created for the page, and
+ * the page control is created.
+ *
+ * @param pageModel
+ * @param index
+ */
+ private void addPage(Object pageModel)
+ {
+ int index = currentTabItems.size();
+ createTabItem(pageModel, index);
+ }
+
+ /**
+ * Create the control for this Part. Does not create children.
+ * This method is called by the parent after this folder is created.
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ public void createControl(Composite parent) {
+ PTabFolder res = new PTabFolder();
+ pTabFolder = res;
+ res.createPartControl(parent);
+ initDrag(res.getControl());
+ }
+
+ /**
+ * The page has change. Propagate the event.
+ * @param newPageIndex
+ */
+ @Override
+ protected void pageChange(int newPageIndex) {
+
+// System.out.println(this.getClass().getSimpleName() + ".pageChange("+ newPageIndex +")");
+ // Do nothing if out of range.
+ if(newPageIndex<0 || newPageIndex> currentTabItems.size() -1)
+ return;
+
+ getSashWindowContainer().activeLeafChange(currentTabItems.get(newPageIndex).childPart);
+ }
+
+ /**
+ * Dispose the TilePart and its controls.
+ *
+ * @see org.eclipse.papyrus.sasheditor.eclipsecopy.MultiPageEditorTile#dispose()
+ */
+ public void dispose() {
+ deactivate();
+ getControl().dispose();
+ }
+
+ /**
+ *
+ */
+ private void initDrag(Composite container) {
+ DragUtil.addDragTarget(container, dragOverListener);
+ }
+
+
+ /**
+ * Get the associated CTabFolder
+ */
+ @Override
+ protected CTabFolder getTabFolder() {
+ return pTabFolder.getTabFolder();
+ }
+
+ /**
+ * Return the swt Control associated to this part.
+ */
+ public Composite getControl() {
+ return getTabFolder();
+ }
+
+ /**
+ * The <code>MultiPageEditor</code> implementation of this <code>IWorkbenchPart</code> method sets focus on
+ * the active nested editor, if there is one.
+ * <p>
+ * Subclasses may extend or reimplement.
+ * </p>
+ */
+ public void setFocus() {
+ setFocus(getActivePage());
+ }
+
+ /**
+ * Sets focus to the control for the given page. If the page has an editor, this calls its <code>setFocus()</code> method. Otherwise, this calls <code>setFocus</code> on the control for the page.
+ *
+ * @param pageIndex
+ * the index of the page
+ */
+ private void setFocus(int pageIndex) {
+ if (pageIndex < 0 || pageIndex >= getPageCount()) {
+ // page index out of bounds, don't set focus.
+ return;
+ }
+ getPagePart(pageIndex).setFocus();
+ }
+
+ /**
+ * Set the active page of this multi-page editor to the page that contains the given editor part. This method has no effect of the given editor part is not contained in this multi-page editor.
+ *
+ * @param editorPart
+ * the editor part
+ * @since 3.3
+ */
+ public final void setActiveEditor(PagePart editorPart) {
+ int count = getPageCount();
+ for (int i = 0; i < count; i++) {
+ PagePart editor = getPagePart(i);
+ if (editor == editorPart) {
+ setActivePage(i);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Return the part containing specified point. Normally return this part, because the caller has
+ * already determine that this contain the part.
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#findPart(org.eclipse.swt.graphics.Point)
+ */
+ @Override
+ public AbstractPart findPart(Point toFind) {
+ return this;
+ }
+
+ /**
+ * Locates the part that intersects the given point and that have the expected type
+ *
+ * @param toFind
+ * @return
+ */
+ @Override
+ public AbstractPart findPartAt(Point toFind, Class<?> expectedTileType) {
+
+ if(expectedTileType == this.getClass())
+ return this;
+
+ // ask current active tab
+ TabItemPart activeTabPart = getActiveTab();
+ if(activeTabPart== null)
+ return null;
+
+ return getActiveTab().findPartAt(toFind, expectedTileType);
+ }
+
+ /**
+ * Get the currently active tab.
+ * @return
+ */
+ private TabItemPart getActiveTab() {
+ int index = getActivePage();
+ if (index != -1) {
+ return currentTabItems.get(index);
+ }
+ return null;
+ }
+
+ /**
+ * Get the specified childPart
+ * @param index Index of the requested childPart.
+ * @return
+ */
+ protected PagePart getPagePart(int index) {
+ return currentTabItems.get(index).getChildPart();
+ }
+
+ /**
+ * Find the part associated to the provided control.
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#findPart(org.eclipse.swt.widgets.Control)
+ */
+ @Override
+ public AbstractPanelPart findPart(Object control) {
+ if (getControl() == control)
+ return this;
+
+ // Check if it is one of the Item
+ if (control instanceof CTabItem && ((CTabItem) control).getParent() == getControl())
+ return this;
+
+ // Ask childs TODO
+ return null;
+ }
+
+ /**
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#getDropTarget(java.lang.Object, org.eclipse.swt.graphics.Point)
+ */
+ public IDropTarget getDropTarget(Object draggedObject, TabFolderPart sourcePart, Point position) {
+ // see org.eclipse.ui.internal.presentations.util.ReplaceDragHandler
+ // Determine which tab we're currently dragging over
+ CTabItem tabUnderPointer = pTabFolder.getItem(position);
+
+ // Compute source tab index. If folder, index==-1
+ int sourceIndex = PTabFolder.getDraggedObjectTabIndex(draggedObject);
+ // This drop target only deals with tabs... if we're not dragging over
+ // a tab, exit.
+ if (tabUnderPointer == null) {
+ Rectangle titleArea = pTabFolder.getTabArea();
+
+ System.out.println("titleArea=" + titleArea + ", position=" + position);
+ // If we're dragging over the title area, treat this as a drop in the last
+ // tab position.
+ if (titleArea.contains(position) && pTabFolder.getTabFolder().getItemCount() > 0) {
+ int dragOverIndex = pTabFolder.getTabFolder().getItemCount();
+ CTabItem lastTab = pTabFolder.getTabFolder().getItem(dragOverIndex - 1);
+
+ // Can't drag to end unless you can see the end
+ if (!lastTab.isShowing()) {
+ return null;
+ }
+
+ // If we are unable to compute the bounds for this tab, then ignore the drop
+ Rectangle lastTabBounds = lastTab.getBounds();
+ if (lastTabBounds.isEmpty()) {
+ return null;
+ }
+
+ // if (dragStart >= 0) {
+ // dragOverIndex--;
+ //
+ // return createDropTarget( sourcePart, lastTabBounds, dragOverIndex);
+ // // return new StackDropResult(lastTabBounds, new Integer(dragOverIndex));
+ // }
+
+ // Make the drag-over rectangle look like a tab at the end of the tab region.
+ // We don't actually know how wide the tab will be when it's dropped, so just
+ // make it 3 times wider than it is tall.
+ // titleArea is in Display coordinate, lastTabBounds in parent coordinate
+ Rectangle dropRectangle = titleArea;
+
+ dropRectangle.x = dropRectangle.x + lastTabBounds.x + lastTabBounds.width;
+ dropRectangle.width = 3 * dropRectangle.height;
+ return createDropTarget(sourcePart, sourceIndex, dropRectangle, dragOverIndex);
+ // return new StackDropResult(dropRectangle, new Integer(dragOverIndex));
+
+ } else {
+ // If the closest side is the side with the tabs, consider this a stack operation.
+ // Otherwise, let the drop fall through to whatever the default behavior is
+ Rectangle displayBounds = DragUtil.getDisplayBounds(pTabFolder.getControl());
+ int closestSide = Geometry.getClosestSide(displayBounds, position);
+ if (closestSide == pTabFolder.getTabFolder().getTabPosition()) {
+ return createDropTarget(sourcePart, sourceIndex, displayBounds, -1);
+ }
+
+ return null;
+ }
+ }
+
+ if (!tabUnderPointer.isShowing()) {
+ return null;
+ }
+
+ // Get thumbnail bounds in display coordinates
+ Rectangle tabBounds = pTabFolder.getItemBounds(tabUnderPointer);
+
+ if (tabBounds.isEmpty()) {
+ return null;
+ }
+
+ return createDropTarget(sourcePart, sourceIndex, tabBounds, pTabFolder.getTabFolder().indexOf(tabUnderPointer));
+ }
+
+ /**
+ * Copied from org.eclipse.ui.internal.PartStack
+ */
+ public IDropTarget createDropTarget(TabFolderPart sourcePart, int sourceIndex, Rectangle snapRectangle, int tabIndex) {
+
+ if (dropTarget == null) {
+ dropTarget = new DropTarget(sourcePart, sourceIndex, snapRectangle, tabIndex);
+ return dropTarget;
+ }
+
+ dropTarget.setTarget(sourcePart, sourceIndex, snapRectangle, tabIndex);
+ return dropTarget;
+ }
+
+ /**
+ * Class implementing methods required by drop targets. Drop target use when the drop occur on one of the thumbnail of the folder.
+ */
+ protected class DropTarget implements IDropTarget {
+
+ int cursor = SWT.CENTER;
+
+ private TabFolderPart sourcePart;
+
+ private Rectangle snapRectangle;
+
+ private int targetIndex;
+
+ private int sourceIndex;
+
+ /**
+ * Constructor. targetPart is the current folder.
+ *
+ * @param sourcePart
+ * The sourcePart of the drag
+ * @param sourceIndex
+ * Index of the tab from where the drop occur
+ * @param snapRectangle
+ * the drop area.
+ * @param targetIndex
+ * Index of the tab where the drop occur
+ */
+ public DropTarget(TabFolderPart sourcePart, int sourceIndex, Rectangle snapRectangle, int targetIndex) {
+ this.sourceIndex = sourceIndex;
+ this.targetIndex = targetIndex;
+ this.sourcePart = sourcePart;
+ this.snapRectangle = snapRectangle;
+ }
+
+ public void setTarget(TabFolderPart sourcePart, int sourceIndex, Rectangle snapRectangle, int targetIndex) {
+ this.sourceIndex = sourceIndex;
+ this.targetIndex = targetIndex;
+ this.sourcePart = sourcePart;
+ this.snapRectangle = snapRectangle;
+ }
+
+ /**
+ *
+ * @see org.eclipse.ui.internal.dnd.IDropTarget#drop()
+ */
+ public void drop() {
+ System.out.println(TabFolderPart.this.getClass().getSimpleName() + ".drop(source=" + sourcePart + "sourceIndex=" + sourceIndex + ", target=" + TabFolderPart.this + ", targetIndex="
+ + targetIndex);
+
+ // move from a folder to another
+ if (sourcePart == TabFolderPart.this) { // move inside the same folder
+ getContentProvider().movePage(sourcePart.getPartModel(), sourceIndex, targetIndex);
+ } else { // move between folder
+ getContentProvider().movePage(sourcePart.getPartModel(), sourceIndex, TabFolderPart.this.getPartModel(), targetIndex);
+ }
+ }
+
+ /**
+ * Return the cursor used during drag.
+ *
+ * @see org.eclipse.ui.internal.dnd.IDropTarget#getCursor()
+ */
+ public Cursor getCursor() {
+ // System.out.println(TabFolderPart.this.getClass().getSimpleName() + ".getCursor()-" + count++);
+ return DragCursors.getCursor(DragCursors.positionToDragCursor(cursor));
+
+ }
+
+ public Rectangle getSnapRectangle() {
+ // System.out.println(TabFolderPart.this.getClass().getSimpleName() + ".getSnapRectangle()-" + count);
+ return snapRectangle;
+ }
+
+ }
+
+ /**
+ * Orphan this node. The parent is set to null, but control is left unchanged. The node can be reattached with reparent().
+ *
+ * @see
+ * @return the parent
+ */
+ public void orphan() {
+ // orphan only if we are in UNCHANGED state
+ if (garbageState == GarbageState.UNCHANGED) {
+ garbageState = GarbageState.ORPHANED;
+ parent = null;
+ }
+ }
+
+ /**
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#getGarbageState()
+ */
+ public GarbageState getGarbageState() {
+ return garbageState;
+ }
+
+ /**
+ * Change the parent of this method.
+ *
+ * @see org.eclipse.papyrus.sasheditor.sash.ITilePart#reparent(org.eclipse.papyrus.sasheditor.sash.ITilePart)
+ */
+ public void reparent(IPanelParent newParent, Composite swtParent ) {
+ parent = newParent;
+ // Create control if needed
+ // This can happen if the TilePart is just created after a refresh
+ // if(getControl() == null)
+ // {
+ // return;
+ // // createContainer(parent.getControl());
+ // }
+ // Reparent the control
+ assert (getControl() != null);
+ // getControl().setParent(newParent.getControl()) ;
+ getControl().setParent(swtParent );
+ garbageState = GarbageState.REPARENTED;
+ }
+
+ /**
+ * Return true if the Part is for the specified real model. Return false otherwise.
+ *
+ * @param realModel The raw model to check
+ * @return
+ */
+ public boolean isPartFor(Object realModel) {
+ return getRawModel() == realModel;
+ }
+
+ /**
+ * Get the raw model associated to this part.
+ * @return
+ */
+ protected Object getRawModel() {
+ return rawModel;
+ }
+
+ /**
+ * Synchronize the TabFolder with the models.
+ * The Tabs order is fixed and can't be moved. So, we move the associated ITilepart if needed.
+ * For each existing Tab, compare its model and the requested model. Synchronize if necessary.
+ * If their is more new model, add new Tab
+ * If their is less newModel, remove unused Tabs.
+ * @param partLists
+ */
+ public void synchronize2(PartLists partLists) {
+
+ // get list of model to be displayed. This is a list of Object.
+ List<Object> newModels = (List<Object>)partModel.getChildren();
+
+ // Disable redraw
+ CTabFolder folder = getTabFolder();
+ folder.setRedraw(false);
+ // Remember active page
+ int activePageIndex = getActivePage();
+
+ // Iterate over the minimum common size
+ // Synchronize each tab with the requested model
+ int minSize = Math.min(newModels.size(), currentTabItems.size());
+ int index;
+ for(index=0; index<minSize; index++)
+ {
+ Object curModel = newModels.get(index);
+ TabItemPart curTab = currentTabItems.get(index);
+ if(! curTab.isTabItemFor(curModel))
+ {
+ resetTabItem(curTab, partLists, curModel);
+ // end
+ activePageIndex = index;
+ }
+ }
+
+ // Check for extra tabs or extra models
+ if( index< newModels.size())
+ {
+ // There is extra models, add new tabs
+ for( int i=index; i<newModels.size(); i++)
+ {
+ Object curModel = newModels.get(i);
+ // Create a new TabItem associated to the curModel.
+ createTabItem(partLists, curModel, i);
+ // end
+ }
+ // Set the last as active
+ activePageIndex = newModels.size()-1;
+ }
+ else if( index< currentTabItems.size())
+ {
+ // There is too much tabs, remove them
+ List<TabItemPart> toRemove = new ArrayList<TabItemPart>();
+ // Collect tab to be removed
+ for( int i=index; i<currentTabItems.size(); i++)
+ {
+ TabItemPart curTab = currentTabItems.get(i);
+ toRemove.add(curTab);
+ }
+ // do remove
+ for( TabItemPart curTab : toRemove)
+ {
+ // removeTab(curTab)
+ removeTabItem(curTab);
+ // end
+ }
+ // Set the active page as the last part if needed
+ if(activePageIndex>=currentTabItems.size())
+ activePageIndex = currentTabItems.size()-1;
+ }
+
+
+ folder.setRedraw(true);
+// folder.setSelection(activePageIndex);
+ folder.redraw();
+
+ if(activePageIndex>=0)
+ {
+// System.err.println("setActivePage(" + activePageIndex + ") : " + this);
+ // Set the activeTab has visible.
+ // Do it here because otherwise the active tab could be not visible.
+ // This come from an undefined bug setting the tab.isVisible(false) in some case.
+ folder.getItem(activePageIndex).getControl().setVisible(true);
+ setActivePage(activePageIndex);
+ }
+ else
+ System.err.println("Active page not set while synchronizing !");
+// folder.update();
+// folder.showSelection();
+
+ }
+
+ /**
+ * Remove the specified tabItem.
+ * Also call appropriate remove() method on the tabItem.
+ *
+ * @param curTab
+ */
+ private void removeTabItem(TabItemPart tabItem) {
+ currentTabItems.remove(tabItem);
+ tabItem.remove();
+ }
+
+ /**
+ * Create a new TabItem associated to the part corresponding to the specified newModel.
+ * The TabItem is created at the specified index.
+ * The associated parts is searched in the existingParts or created if none is found.
+ *
+ * @param existingParts List of existing parts.
+ * @param newModel
+ * @param index
+ * @param i
+ */
+ private void createTabItem(PartLists existingParts, Object newModel, int index) {
+ TabItemPart newTab;
+
+ PagePart modelPart = existingParts.findPagePartFor(newModel);
+ if( modelPart != null )
+ {
+ // A part already exist for the model. Use it.
+ modelPart.reparent(this);
+ newTab = new TabItemPart(this, modelPart, index);
+ }
+ else
+ {
+ // No part found, create one
+ modelPart = createChildPart( newModel );
+ // Attach it to the tabItem
+ newTab = new TabItemPart(this, modelPart, index);
+ }
+
+ // Add to the list of items.
+ currentTabItems.add(index, newTab);
+
+ }
+
+ /**
+ * Create a new TabItem and associated part corresponding to the specified newModel.
+ * The TabItem is created at the specified index.
+ * The associated parts is created.
+ *
+ * @param existingParts List of existing parts.
+ * @param newModel
+ * @param index
+ * @param i
+ */
+ private void createTabItem(Object newModel, int index) {
+ TabItemPart newTab;
+
+ PagePart modelPart = createChildPart( newModel );
+ // Attach it to the tabItem
+ newTab = new TabItemPart(this, modelPart, index);
+
+ // Add to the list of items.
+ currentTabItems.add(index, newTab);
+ }
+
+ /**
+ * Instruct the specified tabItem to use the new model. Check if a part already exist for the model
+ * and use it if any. Otherwise create a new Part.
+ *
+ * @param curTab
+ * @param existingParts
+ * @param newModel
+ */
+ private void resetTabItem(TabItemPart tabItem, PartLists existingParts, Object newModel) {
+
+ PagePart modelPart = existingParts.findPagePartFor(newModel);
+ if( modelPart != null )
+ {
+ // A part already exist for the model. Use it.
+ tabItem.resetChild(modelPart);
+ }
+ else
+ {
+ // No part found, create one
+ modelPart = createChildPart( newModel );
+ // Attach it to the tabItem
+ tabItem.resetChild(modelPart);
+ }
+ }
+
+ /**
+ * Factory method to create a new Part for the specified newModel.
+ * The method should always return a valid Part. In case of error while creating the requested part,
+ * the method should return a default part, maybe showing the encountered error.
+ * The control for the child is created.
+ *
+ * @param newModel
+ * @return The new part
+ */
+ private PagePart createChildPart(Object newModel) {
+
+ // Create the child PartModel. Delegate creation to this part PartModel.
+ IPageModel partModel = getPartModel().createChildSashModel(newModel);
+
+ // Delegate part creation to the container. This allow the container to provide appropriate
+ // objects not available from the part.
+ PagePart newPart = getSashWindowContainer().createPagePart(this, partModel, newModel);
+ // Create control.
+ newPart.createPartControl(getControl());
+
+ return newPart;
+ }
+
+ /**
+ * Show tab status
+ * @debug This is fo debug purpose.
+ * @param msg
+ */
+ private void showTabs(String msg)
+ {
+ System.out.println("------- " + msg);
+ // Show items
+ CTabFolder folder = getTabFolder();
+ CTabItem items[] = folder.getItems();
+ System.out.printf("sel.index %2d :\n", folder.getSelectionIndex() );
+ System.out.printf("items %2d :", folder.getItemCount() );
+ for( CTabItem item : items)
+ {
+ System.out.printf( "%10s |", item.getControl());
+ }
+ System.out.println();
+
+ System.out.printf("it.dispose:" );
+ for( CTabItem item : items)
+ {
+ System.out.printf( "%10b |", item.getControl().isDisposed() );
+ }
+ System.out.println();
+
+ System.out.printf("it.ctrl.vis:" );
+ for( CTabItem item : items)
+ {
+ System.out.printf( "%10s |", item.getControl().isVisible());
+ }
+ System.out.println();
+
+ //
+ System.out.printf("it.ctrl :" );
+ for( CTabItem item : items)
+ {
+ System.out.printf( "%10s |", item.getControl());
+ }
+ System.out.println();
+
+ //
+// System.out.printf("tabs.ctrl :" );
+// for( TabItemPart tab : currentModels)
+// {
+// System.out.printf( "%10s |", tab.childPart.getControl());
+// }
+// System.out.println();
+
+ //
+// System.out.printf("tab.editor:" );
+// for( TabItemPart tab : currentModels)
+// {
+// System.out.printf( "%10s |", tab.childPart.getIEditorPart());
+// }
+// System.out.println();
+
+ //
+ System.out.printf("tabs %2d :", currentTabItems.size() );
+ for( TabItemPart tab : currentTabItems)
+ {
+ System.out.printf( "%10s |", tab);
+ }
+ System.out.println();
+
+ }
+
+ /**
+ * Show tile status.
+ */
+ protected void showStatus()
+ {
+// System.out.println( "tabfolder[" + currentModels.size() + "]:"
+// + ", disposed=" + getCTabFolder().isDisposed()
+// + ", visible=" + getCTabFolder().isVisible()
+// + ", garbState=" + garbageState
+// + ", " + this);
+
+ CTabFolder ctrl = getTabFolder();
+ System.out.printf("tabfolder[%2d]: disposed=%-5b, visible=%-5b, garbState=%-10s, %s\n"
+ , currentTabItems.size(), ctrl.isDisposed(), (ctrl.isDisposed()?false:getTabFolder().isVisible()), garbageState, this);
+ }
+
+ /**
+ * Accept the provided visitor.
+ * Call the corresponding accept method in the visitor.
+ * @param visitor
+ * @return
+ */
+ public void visit(IPartVisitor visitor) {
+ visitor.accept(this);
+ }
+
+ /**
+ * Visit the children of this Tile.
+ * @param visitor
+ */
+ public void visitChildren(IPartVisitor visitor) {
+ for( TabItemPart child : currentTabItems)
+ {
+ child.visit(visitor);
+ }
+ }
+
+
+ /**
+ * Collection of tabpart.
+ * Add miscelenaous methods.
+ * @author dumoulin
+ *
+ */
+ @SuppressWarnings("serial")
+ public class TabPartList extends ArrayList<TabItemPart>
+ {
+
+ /**
+ * Does the list contains a part with the specified model.
+ * @param model
+ * @return
+ */
+ public boolean containsModel(Object model)
+ {
+ return indexOfModel(model) >= 0;
+ }
+
+ /**
+ * Returns the index of the first occurrence of the specified element
+ * in this list, or -1 if this list does not contain the element.
+ * More formally, returns the lowest index <tt>i</tt> such that
+ * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+ * or -1 if there is no such index.
+ */
+ public int indexOfModel(Object o) {
+ if (o == null) {
+ for (int i = 0; i < size(); i++)
+ if (get(i)==null)
+ return i;
+ } else {
+ for (int i = 0; i < size(); i++)
+ if (o.equals(get(i).getChildPart().getRawModel()) )
+ return i;
+ }
+ return -1;
+ }
+
+
+ /**
+ * Get the TabPart by its model.
+ * @param model
+ * @return
+ */
+ public TabItemPart getByModel(Object model)
+ {
+ return get(indexOfModel(model));
+ }
+
+ }
+
+ public class MouseHoverTracker {
+
+
+ private Control control;
+
+ MouseTrackListener mouseTrackListener = new MouseTrackListener(){
+
+ private int count = 0;
+ public void mouseEnter(MouseEvent e) {
+ System.out.println("MouseEnter()" + count++);
+
+ }
+
+ public void mouseExit(MouseEvent e) {
+ System.out.println("MouseExit()" + count++);
+ toolTipManager.closeToolTip();
+ }
+
+ public void mouseHover(MouseEvent e) {
+ CTabFolder folder = getTabFolder();
+// Point pt = folder.toDisplay(e.x, e.y);
+ Point pt = new Point(e.x, e.y);
+ CTabItem item = folder.getItem(pt);
+ int index = pTabFolder.getItemIndex(pt);
+ if(index == -1)
+ {
+ toolTipManager.closeToolTip();
+ return;
+ }
+
+ PagePart part = currentTabItems.get(index).getChildPart();
+ System.out.println("MouseHover(" + e.widget
+ + ", part=" + part.getPartTitle()
+ + ", item=" + item
+ + ") - " + count++);
+ // TODO move it away
+ toolTipManager.showToolTip(item.getBounds(), part.getControl(), pt);
+ }
+
+ };
+
+ public MouseHoverTracker(Control control) {
+ this.control = control;
+ activate();
+ }
+
+ public void activate()
+ {
+ control.addMouseTrackListener(mouseTrackListener);
+ }
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/TabItemPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/TabItemPart.java
new file mode 100644
index 00000000000..61d9cbc4aee
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/TabItemPart.java
@@ -0,0 +1,280 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.internal.AbstractPart.GarbageState;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * A controller associated to a tabitem in a tabfolder. This controller contains a reference to
+ * a PagePart.
+ * This class is used exclusively by the TabFolderPart. It shoulb be not used from elsewhere.
+ *
+ * @author dumoulin
+ *
+ */
+public class TabItemPart {
+
+ /**
+ * The associated model TODO : change the type
+ */
+// protected Object model;
+
+ /**
+ * The child assocciated to this tabitem. The child is rendered by the tabitem.
+ */
+ protected PagePart childPart;
+
+ /**
+ * Parent owning this TabItem. Can be null if the Part is orphaned. Even if
+ * it is orphaned, the SWT Item still set.
+ */
+ protected TabFolderPart parent;
+
+ /**
+ * The SWT item associated to this part. This item contains the control of the
+ * associated editor.
+ */
+ protected CTabItem control;
+
+ /** Garbage state used during refresh */
+ protected GarbageState garbageState;
+
+ /**
+ * Constructor.
+ * Create a TabItem for the provided modelPart.
+ * @param tabFolderPart
+ * @param modelPart
+ * @param index
+ */
+ public TabItemPart(TabFolderPart parent, PagePart modelPart, int index) {
+ this.parent = parent;
+ this.childPart = modelPart;
+
+ createItemControl(index);
+ }
+
+ /**
+ * Create the part control and the control of the child.
+ *
+ * @param tabFolder
+ * @param index
+ */
+ public void createItemControl( int index) {
+ // Create the item
+ CTabItem item = new CTabItem(getTabFolder(), SWT.NONE, index);
+ control = item;
+ if(childPart!=null)
+ {
+ item.setControl(childPart.getControl());
+ refreshTabDecorations();
+ }
+ }
+
+ /**
+ * Set the tab decorations: label, icon.
+ */
+ private void refreshTabDecorations() {
+ setTabText(childPart.getPartTitle());
+ setTabImage(childPart.getPartIcon());
+ }
+
+ /**
+ * Reset this TabItem to use the new part. Reparent the new part and orphan the old part.
+ *
+ * @param modelPart
+ */
+ protected void resetChild(PagePart newChild) {
+ childPart.orphan();
+ newChild.reparent(parent);
+ childPart = newChild;
+ setItemControl(childPart.getControl() );
+
+ refreshTabDecorations();
+ }
+
+ /**
+ * Get the container of the Parent. This container is used as root of the
+ * Controls associated to this editor.
+ *
+ * @return
+ */
+ private CTabFolder getTabFolder() {
+ return (CTabFolder) parent.getControl();
+ }
+
+ /**
+ * Fill the provided part map with the child's parts.
+ *
+ * @param partMap
+ */
+ public void fillPartMap(PartLists partMap) {
+
+ childPart.fillPartMap(partMap);
+ garbageState = GarbageState.UNCHANGED;
+ }
+
+ /**
+ * Remove the TabPart.
+ * Dispose the associated SWT CTabItem.
+ * (TODO Remove from the parent list.)
+ * Orphan the associated ITilePart
+ *
+ * @see
+ * @return the parent
+ */
+ protected void remove() {
+
+ // setControl() change the visibility of the underlying SWT control
+ // (here the editor).
+ // This should not happen if the editor is already attached to another
+ // folder.
+ // check this case and remember the flag to put it back if needed
+ setItemControl(null);
+ parent = null;
+ control.dispose();
+ // Orphan associates Tiles
+ childPart.orphan();
+ }
+
+ /**
+ * Set the item control. Setting the item control with the
+ * control.setControl() method has a side effect: the previous control is
+ * modified with previousControl.setVisible(false). This is annoying when
+ * the previous control has already been attached to another parent. This
+ * method take care to not change the visibility of the previous control if
+ * it is detached from the item's parent.
+ *
+ * @param newControl
+ */
+ private void setItemControl(Control newControl) {
+ // setControl() change the visibility of the underlying SWT control
+ // (here the editor).
+ // This should not happen if the editor is already attached to another
+ // folder.
+ // check this case and remember the flag to put it back if needed
+ boolean editorIsVisible = false;
+ // Get previously attached editor's control
+ Control editorControl = control.getControl();
+ if (editorControl != null && editorControl.getParent() != control.getParent()) {
+ // Editor has already been reattached
+ // Remember its visible flag
+ editorIsVisible = editorControl.getVisible();
+ // Detach the item's control
+ control.setControl(newControl);
+ if (editorIsVisible)
+ editorControl.setVisible(editorIsVisible);
+ } else {
+ // Not reattached, do nothing else
+ control.setControl(newControl);
+ }
+ }
+
+ /**
+ * Dispose the associated control.
+ * Only dispose this tabitem, not the childpart.
+ */
+ public void dispose() {
+ Control itemControl = control.getControl();
+ control.dispose();
+
+ // Dispose the inner control if any.
+ if (!itemControl.isDisposed())
+ itemControl.dispose();
+
+ //
+ parent = null;
+ }
+
+ /**
+ * Set the image of the associated tab.
+ *
+ * @param titleImage
+ */
+ private void setTabImage(Image titleImage) {
+ control.setImage(titleImage);
+ }
+
+ /**
+ * Set the text of the associated tab.
+ *
+ * @param title
+ */
+ private void setTabText(String title) {
+ if(title == null)
+ title = "";
+ control.setText(title);
+ control.setToolTipText(title);
+ }
+
+ /**
+ * Return the associated EditorTile.
+ * @return
+ */
+ public PagePart getChildPart()
+ {
+ return childPart;
+ }
+
+ /**
+ * Locates the part that intersects the given point and that have the expected type
+ *
+ * @param position
+ * @return
+ */
+ public AbstractPart findPartAt(Point position, Class<?> expectedTileType) {
+
+// if(expectedTileType == this.getClass())
+// return this;
+
+ return childPart.findPartAt(position, expectedTileType);
+ }
+
+
+ /**
+ * Accept the provided visitor.
+ * Call the corresponding accept method in the visitor.
+ * @param visitor
+ * @return
+ */
+ public void visit(IPartVisitor visitor) {
+ visitor.accept(this);
+ }
+
+ /**
+ * Visit the children of this Tile.
+ * @param visitor
+ */
+ public void visitChildren(IPartVisitor visitor) {
+ childPart.visit(visitor);
+ }
+
+ /**
+ * Return true if this TabItem is for the specified rawModel.
+ * @param curModel
+ * @return
+ */
+ public boolean isTabItemFor(Object rawModel) {
+ return rawModel.equals( getChildPart().getRawModel());
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/AbstractTabFolderPart.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/AbstractTabFolderPart.java
new file mode 100644
index 00000000000..85d97954e4e
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/AbstractTabFolderPart.java
@@ -0,0 +1,510 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal.eclipsecopy;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.commands.util.Tracing;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.window.Window;
+import org.eclipse.papyrus.sasheditor.editor.MultiPageEditorActionBarContributor;
+import org.eclipse.papyrus.sasheditor.internal.IPanelParent;
+import org.eclipse.papyrus.sasheditor.internal.AbstractPanelPart;
+import org.eclipse.papyrus.sasheditor.sash.PTabFolder;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabFolder2Adapter;
+import org.eclipse.swt.custom.CTabFolderEvent;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.INestableKeyBindingService;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.services.INestable;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.part.IWorkbenchPartOrientation;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Copy of org.eclipse.ui.part.MultiPageEditorPart. Change if to be suitable has a sash leaf. A multi-page editor is an editor with multiple pages, each of which may contain an editor or an arbitrary
+ * SWT control.
+ * <p>
+ * This class is intented to separate folder stuff into 2 classes.
+ * Subclasses must implement the following methods:
+ * <ul>
+ * <li><code>createPages</code> - to create the required pages by calling one of the <code>addPage</code> methods</li>
+ * <li><code>IEditorPart.doSave</code> - to save contents of editor</li>
+ * <li><code>IEditorPart.doSaveAs</code> - to save contents of editor</li>
+ * <li><code>IEditorPart.isSaveAsAllowed</code> - to enable Save As</li>
+ * <li><code>IEditorPart.gotoMarker</code> - to scroll to a marker</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Multi-page editors have a single action bar contributor, which manages contributions for all the pages. The contributor must be a subclass of
+ * <code>AbstractMultiPageEditorActionBarContributor</code>. Note that since any nested editors are created directly in code by callers of <code>addPage(IEditorPart,IEditorInput)</code>, nested
+ * editors do not have their own contributors.
+ * </p>
+ *
+ * @see org.eclipse.ui.part.MultiPageEditorActionBarContributor
+ */
+public abstract class AbstractTabFolderPart extends AbstractPanelPart {
+
+ /**
+ * Subclasses that override {@link #createPageContainer(Composite)} can use this constant to get a site for the container that can be active while the current page is deactivated.
+ *
+ * @since 3.4
+ * @see #activateSite()
+ * @see #deactivateSite(boolean, boolean)
+ * @see #getPageSite(int)
+ */
+ protected static final int PAGE_CONTAINER_SITE = 65535;
+
+// /**
+// * Private tracing output.
+// */
+// private static final String TRACING_COMPONENT = "MPE"; //$NON-NLS-1$
+
+// /**
+// * The active service locator. This value may be <code>null</code> if there is no selected page, or if the selected page is a control with no site.
+// */
+// private INestable activeServiceLocator;
+//
+//
+// private IServiceLocator pageContainerSite;
+
+ /**
+ * Creates an empty multi-page editor with no pages.
+ */
+ protected AbstractTabFolderPart(IPanelParent parent) {
+ super(parent);
+ }
+
+ /**
+ * The <code>MultiPageEditor</code> implementation of this <code>IWorkbenchPart</code> method creates the control for the multi-page editor by calling <code>createContainer</code>, then
+ * <code>createPages</code>. Subclasses should implement <code>createPages</code> rather than overriding this method.
+ *
+ * @param parent
+ * The parent in which the editor should be created; must not be <code>null</code>.
+ */
+ abstract public void createPartControl(Composite parent);
+
+ /**
+ * Returns the active nested editor if there is one.
+ * <p>
+ * Subclasses should not override this method
+ * </p>
+ *
+ * @return the active nested editor, or <code>null</code> if none
+ */
+// public IEditorPart getActiveEditor() {
+// int index = getActivePage();
+// if (index != -1) {
+// return getEditor(index);
+// }
+// return null;
+// }
+
+ /**
+ * Returns the index of the currently active page, or -1 if there is no active page.
+ * <p>
+ * Subclasses should not override this method
+ * </p>
+ *
+ * @return the index of the active page, or -1 if there is no active page
+ */
+ protected int getActivePage() {
+ CTabFolder tabFolder = getTabFolder();
+ if (tabFolder != null && !tabFolder.isDisposed()) {
+ return tabFolder.getSelectionIndex();
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the control for the given page index, or <code>null</code> if no control has been set for the page. The page index must be valid.
+ * <p>
+ * Subclasses should not override this method
+ * </p>
+ *
+ * @param pageIndex
+ * the index of the page
+ * @return the control for the specified page, or <code>null</code> if none has been set
+ */
+ protected Control getControl(int pageIndex) {
+ return getItem(pageIndex).getControl();
+ }
+
+ /**
+ * Returns the editor for the given page index. The page index must be valid.
+ *
+ * @param pageIndex
+ * the index of the page
+ * @return the editor for the specified page, or <code>null</code> if the specified page was not created with <code>addPage(IEditorPart,IEditorInput)</code>
+ */
+// abstract protected IEditorPart getEditor(int pageIndex);
+
+ /**
+ * Returns the service locator for the given page index. This method can be used to create service locators for pages that are just controls. The page index must be valid.
+ * <p>
+ * This will return the editor site service locator for an editor, and create one for a page that is just a control.
+ * </p>
+ *
+ * @param pageIndex
+ * the index of the page
+ * @return the editor for the specified page, or <code>null</code> if the specified page was not created with <code>addPage(IEditorPart,IEditorInput)</code>
+ * @since 3.4
+ */
+// protected final IServiceLocator getPageSite(int pageIndex) {
+// if (pageIndex == PAGE_CONTAINER_SITE) {
+// return getPageContainerSite();
+// }
+//
+// /**
+// * Return the site associated to the editor.
+// */
+// return getEditor(pageIndex).getSite();
+// }
+
+ /**
+ * @return A site that can be used with a header.
+ * @since 3.4
+ * @see #createPageContainer(Composite)
+ * @see #PAGE_CONTAINER_SITE
+ * @see #getPageSite(int)
+ */
+// private IServiceLocator getPageContainerSite() {
+// if (pageContainerSite == null) {
+// IServiceLocatorCreator slc = (IServiceLocatorCreator) getSite().getService(IServiceLocatorCreator.class);
+// pageContainerSite = slc.createServiceLocator(getSite(), null, new IDisposable() {
+//
+// public void dispose() {
+// final Control control = ((PartSite) getSite()).getPane().getControl();
+// if (control != null && !control.isDisposed()) {
+// ((PartSite) getSite()).getPane().doHide();
+// }
+// }
+// });
+// }
+// return pageContainerSite;
+// }
+
+ /**
+ * Returns the tab item for the given page index (page index is 0-based). The page index must be valid.
+ *
+ * @param pageIndex
+ * the index of the page
+ * @return the tab item for the given page index
+ */
+ private CTabItem getItem(int pageIndex) {
+ return getTabFolder().getItem(pageIndex);
+ }
+
+ /**
+ * Returns the number of pages in this multi-page editor.
+ *
+ * @return the number of pages
+ */
+ protected int getPageCount() {
+ CTabFolder folder = getTabFolder();
+ // May not have been created yet, or may have been disposed.
+ if (folder != null && !folder.isDisposed()) {
+ return folder.getItemCount();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the tab folder containing this multi-page editor's pages.
+ *
+ * @return the tab folder, or <code>null</code> if <code>createPartControl</code> has not been called yet
+ */
+ protected abstract CTabFolder getTabFolder();
+
+ /**
+ * Notifies this multi-page editor that the page with the given id has been activated. This method is called when the user selects a different tab.
+ * <p>
+ * The <code>MultiPageEditorPart</code> implementation of this method sets focus to the new page, and notifies the action bar contributor (if there is one). This checks whether the action bar
+ * contributor is an instance of <code>MultiPageEditorActionBarContributor</code>, and, if so, calls <code>setActivePage</code> with the active nested editor. This also fires a selection change
+ * event if required.
+ * </p>
+ * <p>
+ * Subclasses may extend this method.
+ * </p>
+ *
+ * @param newPageIndex
+ * the index of the activated page
+ */
+ protected void pageChange(int newPageIndex) {
+// System.out.println(this.getClass().getSimpleName() + "pageChange()");
+// deactivateSite(false, false);
+//
+// IPartService partService = (IPartService) getSite().getService(IPartService.class);
+// if (partService.getActivePart() == this) {
+// setFocus(newPageIndex);
+// }
+//
+// IEditorPart activeEditor = getEditor(newPageIndex);
+//
+// IEditorActionBarContributor contributor = getEditorSite().getActionBarContributor();
+// if (contributor != null && contributor instanceof MultiPageEditorActionBarContributor) {
+// ((MultiPageEditorActionBarContributor) contributor).setActivePage(activeEditor);
+// }
+//
+// if (activeEditor != null) {
+// ISelectionProvider selectionProvider = activeEditor.getSite().getSelectionProvider();
+// if (selectionProvider != null) {
+// ISelectionProvider outerProvider = getSite().getSelectionProvider();
+// if (outerProvider instanceof MultiPageSelectionProvider) {
+// SelectionChangedEvent event = new SelectionChangedEvent(selectionProvider, selectionProvider.getSelection());
+//
+// MultiPageSelectionProvider provider = (MultiPageSelectionProvider) outerProvider;
+// provider.fireSelectionChanged(event);
+// provider.firePostSelectionChanged(event);
+// } else {
+// if (Policy.DEBUG_MPE) {
+// Tracing.printTrace(TRACING_COMPONENT, "MultiPageEditorPart " + getTitle() //$NON-NLS-1$
+// + " did not propogate selection for " //$NON-NLS-1$
+// + activeEditor.getTitle());
+// }
+// }
+// }
+// }
+//
+// activateSite();
+ }
+
+ /**
+ * This method can be used by implementors of {@link AbstractTabFolderPart#createPageContainer(Composite)} to deactivate the active inner editor services while their header has focus. A
+ * deactivateSite() must have a matching call to activateSite() when appropriate.
+ * <p>
+ * An new inner editor will have its site activated on a {@link AbstractTabFolderPart#pageChange(int)}.
+ * </p>
+ * <p>
+ * <b>Note:</b> This API is evolving in 3.4 and this might not be its final form.
+ * </p>
+ *
+ * @param immediate
+ * immediately deactivate the legacy keybinding service
+ * @param containerSiteActive
+ * Leave the page container site active.
+ * @since 3.4
+ * @see #activateSite()
+ * @see #createPageContainer(Composite)
+ * @see #getPageSite(int)
+ * @see #PAGE_CONTAINER_SITE
+ */
+// protected final void deactivateSite(boolean immediate, boolean containerSiteActive) {
+// // Deactivate the nested services from the last active service locator.
+// if (activeServiceLocator != null) {
+// activeServiceLocator.deactivate();
+// activeServiceLocator = null;
+// }
+//
+// final int pageIndex = getActivePage();
+// final IKeyBindingService service = getSite().getKeyBindingService();
+// if (pageIndex < 0 || pageIndex >= getPageCount() || immediate) {
+// // There is no selected page, so deactivate the active service.
+// if (service instanceof INestableKeyBindingService) {
+// final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+// nestableService.activateKeyBindingService(null);
+// } else {
+// WorkbenchPlugin
+// .log("MultiPageEditorPart.deactivateSite() Parent key binding service was not an instance of INestableKeyBindingService. It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+// }
+// }
+//
+// if (containerSiteActive) {
+// IServiceLocator containerSite = getPageContainerSite();
+// if (containerSite instanceof INestable) {
+// activeServiceLocator = (INestable) containerSite;
+// activeServiceLocator.activate();
+// }
+// }
+// }
+
+ /**
+ * This method can be used by implementors of {@link #createPageContainer(Composite)} to activate the active inner editor services when their header loses focus.
+ * <p>
+ * An new inner editor will have its site activated on a {@link #pageChange(int)}.
+ * </p>
+ * <p>
+ * <b>Note:</b> This API is evolving in 3.4 and this might not be its final form.
+ * </p>
+ *
+ * @since 3.4
+ * @see #deactivateSite(boolean,boolean)
+ * @see #createPageContainer(Composite)
+ * @see #getPageSite(int)
+ */
+// protected final void activateSite() {
+// if (activeServiceLocator != null) {
+// activeServiceLocator.deactivate();
+// activeServiceLocator = null;
+// }
+//
+// final IKeyBindingService service = getSite().getKeyBindingService();
+// final int pageIndex = getActivePage();
+// final IEditorPart editor = getEditor(pageIndex);
+//
+// if (editor != null) {
+// // active the service for this inner editor
+// if (service instanceof INestableKeyBindingService) {
+// final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+// nestableService.activateKeyBindingService(editor.getEditorSite());
+//
+// } else {
+// WorkbenchPlugin
+// .log("MultiPageEditorPart.activateSite() Parent key binding service was not an instance of INestableKeyBindingService. It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+// }
+// // Activate the services for the new service locator.
+// final IServiceLocator serviceLocator = editor.getEditorSite();
+// if (serviceLocator instanceof INestable) {
+// activeServiceLocator = (INestable) serviceLocator;
+// activeServiceLocator.activate();
+// }
+//
+// } else {
+// Item item = getItem(pageIndex);
+//
+// // There is no selected editor, so deactivate the active service.
+// if (service instanceof INestableKeyBindingService) {
+// final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+// nestableService.activateKeyBindingService(null);
+// } else {
+// WorkbenchPlugin
+// .log("MultiPageEditorPart.activateSite() Parent key binding service was not an instance of INestableKeyBindingService. It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+// }
+//
+// if (item.getData() instanceof INestable) {
+// activeServiceLocator = (INestable) item.getData();
+// activeServiceLocator.activate();
+// }
+// }
+// }
+
+// /**
+// * Disposes the given part and its site.
+// *
+// * @param part
+// * The part to dispose; must not be <code>null</code>.
+// */
+// private void disposePart(final IWorkbenchPart part) {
+// SafeRunner.run(new ISafeRunnable() {
+//
+// public void run() {
+// IWorkbenchPartSite partSite = part.getSite();
+// part.dispose();
+// if (partSite instanceof MultiPageEditorSite) {
+// ((MultiPageEditorSite) partSite).dispose();
+// }
+// }
+//
+// public void handleException(Throwable e) {
+// // Exception has already being logged by Core. Do nothing.
+// }
+// });
+// }
+
+ /**
+ * Sets the currently active page.
+ *
+ * @param pageIndex
+ * the index of the page to be activated; the index must be valid
+ */
+ public void setActivePage(int pageIndex) {
+// Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
+ if( !isValidPageIndex(pageIndex))
+ return;
+
+ getTabFolder().setSelection(pageIndex);
+ pageChange(pageIndex);
+ }
+
+ /**
+ * Return true if the specified index is valid.
+ * The index should be between 0 and pageCount.
+ * If there is no page, return false.
+ *
+ * @param pageIndex
+ * @return
+ */
+ private boolean isValidPageIndex(int pageIndex) {
+
+ return pageIndex>= 0 && pageIndex < getPageCount();
+ }
+
+ /**
+ * Sets the control for the given page index. The page index must be valid.
+ *
+ * @param pageIndex
+ * the index of the page
+ * @param control
+ * the control for the specified page, or <code>null</code> to clear the control
+ */
+ protected void setControl(int pageIndex, Control control) {
+ getItem(pageIndex).setControl(control);
+ }
+
+
+ /* *************************************** */
+ /* Added method. */
+ /* *************************************** */
+
+// /**
+// * Title of this TilePart ? Needed by a trace message.
+// */
+// protected String getTitle() {
+// return getClass().toString();
+// }
+//
+// /**
+// *
+// */
+// protected IWorkbenchPartSite getSite() {
+// return getEditorSite();
+// }
+//
+// /**
+// *
+// */
+// abstract protected void firePropertyChange(int propertyId);
+//
+// /**
+// *
+// */
+// abstract protected IEditorSite getEditorSite();
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/MultiPageEditorSite.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/MultiPageEditorSite.java
new file mode 100644
index 00000000000..105d56a3a62
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/MultiPageEditorSite.java
@@ -0,0 +1,551 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal.eclipsecopy;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.papyrus.sasheditor.editor.IMultiPageEditorPart;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.INestableKeyBindingService;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.PopupMenuExtender;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.services.INestable;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.internal.services.WorkbenchLocationService;
+import org.eclipse.ui.part.EditorActionBarContributor;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.services.IServiceScopes;
+
+/**
+ * Site for a nested editor within a multi-page editor. Selection is handled by
+ * forwarding the event to the multi-page editor's selection listeners; most
+ * other methods are forwarded to the multi-page editor's site.
+ * <p>
+ * The base implementation of <code>MultiPageEditor.createSite</code> creates an
+ * instance of this class. This class may be instantiated or subclassed.
+ * </p>
+ *
+ * @see org.eclipse.ui.part.MultiPageEditorSite.class
+ */
+public class MultiPageEditorSite implements IEditorSite, INestable {
+
+
+ /**
+ * The actionBarContributor associated to the site. Can be null. In this case,
+ * use the multiEditor ActionBarContributor.
+ */
+ protected EditorActionBarContributor actionBarContributor;
+
+ /**
+ * The nested editor.
+ */
+ private IEditorPart editor;
+
+ /**
+ * The list of popup menu extenders; <code>null</code> if none registered.
+ */
+ private ArrayList menuExtenders;
+
+ /**
+ * The main editor EditorSite.
+ */
+ private IEditorSite mainEditorSite;
+
+ /**
+ * The post selection changed listener.
+ */
+ private ISelectionChangedListener postSelectionChangedListener = null;
+
+ /**
+ * The selection change listener, initialized lazily; <code>null</code> if
+ * not yet created.
+ */
+ private ISelectionChangedListener selectionChangedListener = null;
+
+ /**
+ * The selection provider; <code>null</code> if none.
+ *
+ * @see MultiPageEditorSite#setSelectionProvider(ISelectionProvider)
+ */
+ private ISelectionProvider selectionProvider = null;
+
+ /**
+ * The cached copy of the key binding service specific to this multi-page
+ * editor site. This value is <code>null</code> if it is not yet
+ * initialized.
+ */
+ private IKeyBindingService service = null;
+
+ /**
+ * The local service locator for this multi-page editor site. This value is
+ * never <code>null</code>.
+ */
+ private final ServiceLocator serviceLocator;
+
+ /**
+ * Creates a site for the given editor nested within the given multi-page
+ * editor.
+ *
+ * @param mainEditorSite
+ * the multi-page editor
+ * @param editor
+ * the nested editor
+ */
+ public MultiPageEditorSite(IEditorSite mainEditorSite, IEditorPart editor, EditorActionBarContributor actionBarContributor) {
+ Assert.isNotNull(mainEditorSite);
+ Assert.isNotNull(editor);
+ this.mainEditorSite = mainEditorSite;
+ this.editor = editor;
+ this.actionBarContributor = actionBarContributor;
+
+ final IServiceLocator parentServiceLocator = mainEditorSite;
+ IServiceLocatorCreator slc = (IServiceLocatorCreator) parentServiceLocator.getService(IServiceLocatorCreator.class);
+ this.serviceLocator = (ServiceLocator) slc.createServiceLocator(mainEditorSite, null, new IDisposable() {
+
+ public void dispose() {
+ final Control control = ((PartSite) getMainEditorSite()).getPane().getControl();
+ if (control != null && !control.isDisposed()) {
+ ((PartSite) getMainEditorSite()).getPane().doHide();
+ }
+ }
+ });
+
+ initializeDefaultServices();
+ }
+
+ /**
+ * Return the site of the main editor.
+ * @return
+ */
+ private IWorkbenchPartSite getMainEditorSite() {
+ return mainEditorSite;
+ }
+
+ /**
+ * Return the EditorSite of the main editor.
+ * This is the same object as getMainEditorSite.
+ * TODO: Remove this one.
+ * @return
+ */
+ private IEditorSite getMainEditorEditorSite() {
+ return mainEditorSite;
+ }
+
+ /**
+ * Initialize the slave services for this site.
+ */
+ private void initializeDefaultServices() {
+ serviceLocator.registerService(IWorkbenchLocationService.class, new WorkbenchLocationService(IServiceScopes.MPESITE_SCOPE, getWorkbenchWindow().getWorkbench(), getWorkbenchWindow(),
+ getMainEditorSite(), this, null, 3));
+ }
+
+ /**
+ * Notifies the multi page editor service that the component within which it
+ * exists has become active.
+ *
+ * @since 3.2
+ */
+ public final void activate() {
+ serviceLocator.activate();
+ }
+
+ /**
+ * Notifies the multi page editor service that the component within which it
+ * exists has been deactived.
+ *
+ * @since 3.2
+ */
+ public final void deactivate() {
+ serviceLocator.deactivate();
+ }
+
+ /**
+ * Dispose the contributions.
+ */
+ public void dispose() {
+ if (menuExtenders != null) {
+ for (int i = 0; i < menuExtenders.size(); i++) {
+ ((PopupMenuExtender) menuExtenders.get(i)).dispose();
+ }
+ menuExtenders = null;
+ }
+
+ // Remove myself from the list of nested key binding services.
+ if (service != null) {
+ IKeyBindingService parentService = getEditor().getSite().getKeyBindingService();
+ if (parentService instanceof INestableKeyBindingService) {
+ INestableKeyBindingService nestableParent = (INestableKeyBindingService) parentService;
+ nestableParent.removeKeyBindingService(this);
+ }
+ service = null;
+ }
+
+ if (serviceLocator != null) {
+ serviceLocator.dispose();
+ }
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IEditorSite</code> method returns the EditorActionBarContributor associated to the site if one is defined,
+ * or the EditorActionBarContributor of the multiEditor.
+ *
+ * @return <code>null</code>
+ */
+ public IEditorActionBarContributor getActionBarContributor() {
+
+ // If we use an action bar contributor, look for a registered ActionBarContributor.
+ // TODO : enable next asap
+// ActionBarContributor contributor = multiPageEditor.getEditorSite().getActionBarContributor();
+// if(contributor instanceof ComposedActionBarContributor)
+// {
+// ComposedActionBarContributor composedContributor = (ComposedActionBarContributor)contributor;
+// return composedContributor.getContributorFor(editor);
+// }
+
+ // Return the main ActionBarContributor, usually ComposedActionBarContributor
+
+ if(actionBarContributor != null)
+ return actionBarContributor;
+ else
+ return getMainEditorEditorSite().getActionBarContributor();
+// return null;
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IEditorSite</code> method forwards to the multi-page editor to
+ * return the action bars.
+ *
+ * @return The action bars from the parent multi-page editor.
+ */
+ public IActionBars getActionBars() {
+ return getMainEditorEditorSite().getActionBars();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
+ */
+ public Object getAdapter(Class adapter) {
+ return null;
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
+ * to return the decorator manager.
+ *
+ * @return The decorator from the workbench window.
+ * @deprecated use IWorkbench.getDecoratorManager()
+ */
+ public ILabelDecorator getDecoratorManager() {
+ return getWorkbenchWindow().getWorkbench().getDecoratorManager().getLabelDecorator();
+ }
+
+ /**
+ * Returns the nested editor.
+ *
+ * @return the nested editor
+ */
+ public IEditorPart getEditor() {
+ return editor;
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method returns an empty string since the
+ * nested editor is not created from the registry.
+ *
+ * @return An empty string.
+ */
+ public String getId() {
+ return ""; //$NON-NLS-1$
+ }
+
+ /*
+ * (non-Javadoc) Method declared on IEditorSite.
+ */
+ public IKeyBindingService getKeyBindingService() {
+ if (service == null) {
+ service = getMainEditorEditorSite().getKeyBindingService();
+ if (service instanceof INestableKeyBindingService) {
+ INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+ service = nestableService.getKeyBindingService(this);
+
+ } else {
+ /*
+ * This is an internal reference, and should not be copied by
+ * client code. If you are thinking of copying this, DON'T DO
+ * IT.
+ */
+ WorkbenchPlugin
+ .log("MultiPageEditorSite.getKeyBindingService() Parent key binding service was not an instance of INestableKeyBindingService. It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ return service;
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
+ * to return the workbench page.
+ *
+ * @return The workbench page in which this editor site resides.
+ */
+ public IWorkbenchPage getPage() {
+ return getMainEditorSite().getPage();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.IWorkbenchPartSite#getPart()
+ */
+ public IWorkbenchPart getPart() {
+ return editor;
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method returns an empty string since the
+ * nested editor is not created from the registry.
+ *
+ * @return An empty string.
+ */
+ public String getPluginId() {
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the post selection change listener which listens to the nested
+ * editor's selection changes.
+ *
+ * @return the post selection change listener.
+ */
+ private ISelectionChangedListener getPostSelectionChangedListener() {
+ if (postSelectionChangedListener == null) {
+ postSelectionChangedListener = new ISelectionChangedListener() {
+
+ public void selectionChanged(SelectionChangedEvent event) {
+ MultiPageEditorSite.this.handlePostSelectionChanged(event);
+ }
+ };
+ }
+ return postSelectionChangedListener;
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method returns an empty string since the
+ * nested editor is not created from the registry.
+ *
+ * @return An empty string.
+ */
+ public String getRegisteredName() {
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the selection changed listener which listens to the nested
+ * editor's selection changes, and calls <code>handleSelectionChanged</code>
+ * .
+ *
+ * @return the selection changed listener
+ */
+ private ISelectionChangedListener getSelectionChangedListener() {
+ if (selectionChangedListener == null) {
+ selectionChangedListener = new ISelectionChangedListener() {
+
+ public void selectionChanged(SelectionChangedEvent event) {
+ MultiPageEditorSite.this.handleSelectionChanged(event);
+ }
+ };
+ }
+ return selectionChangedListener;
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method returns the selection provider set
+ * by <code>setSelectionProvider</code>.
+ *
+ * @return The current selection provider.
+ */
+ public ISelectionProvider getSelectionProvider() {
+ return selectionProvider;
+ }
+
+ public final Object getService(final Class key) {
+ return serviceLocator.getService(key);
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
+ * to return the shell.
+ *
+ * @return The shell in which this editor site resides.
+ */
+ public Shell getShell() {
+ return getMainEditorSite().getShell();
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
+ * to return the workbench window.
+ *
+ * @return The workbench window in which this editor site resides.
+ */
+ public IWorkbenchWindow getWorkbenchWindow() {
+ return getMainEditorSite().getWorkbenchWindow();
+ }
+
+ /**
+ * Handles a post selection changed even from the nexted editor.
+ * <p>
+ * Subclasses may extend or reimplement this method
+ *
+ * @param event
+ * the event
+ *
+ * @since 3.2
+ */
+ protected void handlePostSelectionChanged(SelectionChangedEvent event) {
+ ISelectionProvider parentProvider = getMainEditorSite().getSelectionProvider();
+ if (parentProvider instanceof MultiPageSelectionProvider) {
+ SelectionChangedEvent newEvent = new SelectionChangedEvent(parentProvider, event.getSelection());
+ MultiPageSelectionProvider prov = (MultiPageSelectionProvider) parentProvider;
+ prov.firePostSelectionChanged(newEvent);
+ }
+ }
+
+ /**
+ * Handles a selection changed event from the nested editor. The default
+ * implementation gets the selection provider from the multi-page editor's
+ * site, and calls <code>fireSelectionChanged</code> on it (only if it is an
+ * instance of <code>MultiPageSelectionProvider</code>), passing a new event
+ * object.
+ * <p>
+ * Subclasses may extend or reimplement this method.
+ * </p>
+ *
+ * @param event
+ * the event
+ */
+ protected void handleSelectionChanged(SelectionChangedEvent event) {
+ ISelectionProvider parentProvider = getMainEditorSite().getSelectionProvider();
+ if (parentProvider instanceof MultiPageSelectionProvider) {
+ SelectionChangedEvent newEvent = new SelectionChangedEvent(parentProvider, event.getSelection());
+ MultiPageSelectionProvider prov = (MultiPageSelectionProvider) parentProvider;
+ prov.fireSelectionChanged(newEvent);
+ }
+ }
+
+ public final boolean hasService(final Class key) {
+ return serviceLocator.hasService(key);
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
+ * for registration.
+ *
+ * @param menuManager
+ * The menu manager
+ * @param selProvider
+ * The selection provider.
+ */
+ public void registerContextMenu(MenuManager menuManager, ISelectionProvider selProvider) {
+ getMainEditorSite().registerContextMenu(menuManager, selProvider);
+ }
+
+ public final void registerContextMenu(final MenuManager menuManager, final ISelectionProvider selectionProvider, final boolean includeEditorInput) {
+ registerContextMenu(getId(), menuManager, selectionProvider, includeEditorInput);
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
+ * for registration.
+ *
+ * @param menuID
+ * The identifier for the menu.
+ * @param menuMgr
+ * The menu manager
+ * @param selProvider
+ * The selection provider.
+ */
+ public void registerContextMenu(String menuID, MenuManager menuMgr, ISelectionProvider selProvider) {
+ if (menuExtenders == null) {
+ menuExtenders = new ArrayList(1);
+ }
+ PartSite.registerContextMenu(menuID, menuMgr, selProvider, true, editor, menuExtenders);
+ }
+
+ public final void registerContextMenu(final String menuId, final MenuManager menuManager, final ISelectionProvider selectionProvider, final boolean includeEditorInput) {
+ if (menuExtenders == null) {
+ menuExtenders = new ArrayList(1);
+ }
+ PartSite.registerContextMenu(menuId, menuManager, selectionProvider, includeEditorInput, editor, menuExtenders);
+ }
+
+ /**
+ * The <code>MultiPageEditorSite</code> implementation of this
+ * <code>IWorkbenchPartSite</code> method remembers the selection provider,
+ * and also hooks a listener on it, which calls
+ * <code>handleSelectionChanged</code> when a selection changed event
+ * occurs.
+ *
+ * @param provider
+ * The selection provider.
+ * @see MultiPageEditorSite#handleSelectionChanged(SelectionChangedEvent)
+ */
+ public void setSelectionProvider(ISelectionProvider provider) {
+ ISelectionProvider oldSelectionProvider = selectionProvider;
+ selectionProvider = provider;
+ if (oldSelectionProvider != null) {
+ oldSelectionProvider.removeSelectionChangedListener(getSelectionChangedListener());
+ if (oldSelectionProvider instanceof IPostSelectionProvider) {
+ ((IPostSelectionProvider) oldSelectionProvider).removePostSelectionChangedListener(getPostSelectionChangedListener());
+ }
+ }
+ if (selectionProvider != null) {
+ selectionProvider.addSelectionChangedListener(getSelectionChangedListener());
+ if (selectionProvider instanceof IPostSelectionProvider) {
+ ((IPostSelectionProvider) selectionProvider).addPostSelectionChangedListener(getPostSelectionChangedListener());
+ }
+ }
+ }
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/MultiPageSelectionProvider.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/MultiPageSelectionProvider.java
new file mode 100644
index 00000000000..082c7d02ac3
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/internal/eclipsecopy/MultiPageSelectionProvider.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.sasheditor.internal.eclipsecopy;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.papyrus.sasheditor.editor.IMultiPageEditorPart;
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * Manages the current selection in a multi-page editor by tracking the active nested editor within the multi-page editor. When the selection changes, notifications are sent to all registered
+ * listeners.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed. The base implementation of <code>MultiPageEditor.init</code> creates an instance of this class.
+ * </p>
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class MultiPageSelectionProvider implements IPostSelectionProvider {
+
+ /**
+ * Registered selection changed listeners (element type: <code>ISelectionChangedListener</code>).
+ */
+ private ListenerList listeners = new ListenerList();
+
+ /**
+ * Registered post selection changed listeners.
+ */
+ private ListenerList postListeners = new ListenerList();
+
+ /**
+ * The multi-page editor.
+ */
+ private IMultiPageEditorPart multiPageEditor;
+
+ /**
+ * Creates a selection provider for the given multi-page editor.
+ *
+ * @param multiPageEditor
+ * the multi-page editor
+ */
+ public MultiPageSelectionProvider(IMultiPageEditorPart multiPageEditor) {
+ Assert.isNotNull(multiPageEditor);
+ this.multiPageEditor = multiPageEditor;
+ }
+
+ /*
+ * (non-Javadoc) Method declared on <code>ISelectionProvider</code>.
+ */
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Adds a listener for post selection changes in this multi page selection provider.
+ *
+ * @param listener
+ * a selection changed listener
+ * @since 3.2
+ */
+ public void addPostSelectionChangedListener(ISelectionChangedListener listener) {
+ postListeners.add(listener);
+ }
+
+ /**
+ * Notifies all registered selection changed listeners that the editor's selection has changed. Only listeners registered at the time this method is called are notified.
+ *
+ * @param event
+ * the selection changed event
+ */
+ public void fireSelectionChanged(final SelectionChangedEvent event) {
+ Object[] listeners = this.listeners.getListeners();
+ fireEventChange(event, listeners);
+ }
+
+ /**
+ * Notifies all post selection changed listeners that the editor's selection has changed.
+ *
+ * @param event
+ * the event to propogate.
+ * @since 3.2
+ */
+ public void firePostSelectionChanged(final SelectionChangedEvent event) {
+ Object[] listeners = postListeners.getListeners();
+ fireEventChange(event, listeners);
+ }
+
+ private void fireEventChange(final SelectionChangedEvent event, Object[] listeners) {
+ for (int i = 0; i < listeners.length; ++i) {
+ final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i];
+ SafeRunner.run(new SafeRunnable() {
+
+ public void run() {
+ l.selectionChanged(event);
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns the multi-page editor.
+ *
+ * @return the multi-page editor.
+ */
+ public IMultiPageEditorPart getMultiPageEditor() {
+ return multiPageEditor;
+ }
+
+ /*
+ * (non-Javadoc) Method declared on <code>ISelectionProvider</code>.
+ */
+ public ISelection getSelection() {
+ IEditorPart activeEditor = multiPageEditor.getActiveEditor();
+ if (activeEditor != null) {
+ ISelectionProvider selectionProvider = activeEditor.getSite().getSelectionProvider();
+ if (selectionProvider != null) {
+ return selectionProvider.getSelection();
+ }
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ /*
+ * (non-JavaDoc) Method declaed on <code>ISelectionProvider</code>.
+ */
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Removes a listener for post selection changes in this multi page selection provider.
+ *
+ * @param listener
+ * a selection changed listener
+ * @since 3.2
+ */
+ public void removePostSelectionChangedListener(ISelectionChangedListener listener) {
+ postListeners.remove(listener);
+ }
+
+ /*
+ * (non-Javadoc) Method declared on <code>ISelectionProvider</code>.
+ */
+ public void setSelection(ISelection selection) {
+ IEditorPart activeEditor = multiPageEditor.getActiveEditor();
+ if (activeEditor != null) {
+ ISelectionProvider selectionProvider = activeEditor.getSite().getSelectionProvider();
+ if (selectionProvider != null) {
+ selectionProvider.setSelection(selection);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/multipage/editor/MultiPageEditor.java b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/multipage/editor/MultiPageEditor.java
new file mode 100644
index 00000000000..ce6fb06e837
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/src2/org/eclipse/papyrus/sasheditor/multipage/editor/MultiPageEditor.java
@@ -0,0 +1,292 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.multipage.editor;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.papyrus.sasheditor.contentprovider.IComponentModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IEditorModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.part.MultiPageEditorPart;
+
+/**
+ * A MultiPageEditor implementation accepting IMultiSashContentProvider as content provider.
+ * This implementation extends the regular eclipse MultiPageEditorPart.
+ * The refresh() method allows to refresh the tabs.
+ *
+ * The implementation do not listen on model change. This can be done by subclasses.
+ * To add a new tab, one should add it as a model in the ContentProvider. The addPage()
+ * methods should not be used for this purpose.
+ *
+ * This implementation is intended for debug and testing purpose : it can be used in place
+ * of the AbstractMultiPageSashEditor. It takes the same arguments and ContentProvider, but
+ * it only allows one folder and don't deal with multisashes.
+ * Also, the implementation use the regular Eclipse EditorSite management. This allows to check for problemes from this
+ * site management.
+ *
+ * @author dumoulin
+ */
+public abstract class MultiPageEditor extends MultiPageEditorPart {
+
+ /** Log object */
+ protected Logger log = Logger.getLogger(getClass().getName());
+
+ /** The pageProvider */
+ private ISashWindowsContentProvider pageProvider;
+
+ /**
+ * The tabfolder model providing the pages that must be shown.
+ */
+ private ITabFolderModel tabFolderModel;
+
+ /** Ordered set of currently shown diagrams */
+ protected List<IPageModel> currentTabs = new ArrayList<IPageModel>();
+
+ /**
+ * Constructor.
+ */
+ public MultiPageEditor() {
+ super();
+ }
+
+ @Override
+ public Object getAdapter(Class adapter) {
+
+ // Get the content provider if requested.
+ if(ISashWindowsContentProvider.class == adapter)
+ return getContentProvider();
+
+ return super.getAdapter(adapter);
+ }
+
+ /**
+ * get the contentProvider. Create it if necessary.
+ * @return
+ */
+ protected ISashWindowsContentProvider getContentProvider()
+ {
+ if(pageProvider == null)
+ pageProvider = createPageProvider();
+
+ return pageProvider;
+ }
+
+ /**
+ * Add a page containing the Component described by the provided model.
+ * @param tabItem
+ */
+ protected int addPage(IComponentModel tabItem) {
+ Composite composite = tabItem.createPartControl( getContainer() );
+
+ int index = addPage(composite);
+ setPageText(index, tabItem.getTabTitle() );
+ Image image = tabItem.getTabIcon();
+ if(image !=null)
+ setPageImage(index, image);
+ return index;
+ }
+
+ /**
+ * Add the editor corresponding to the model to the folder.
+ * @param editorModel
+ */
+ protected int addPage(IEditorModel editorModel) {
+ try {
+ IEditorPart editor = editorModel.createIEditorPart();
+ int index = addPage(editor, getEditorInput());
+ setPageText(index, editorModel.getTabTitle());
+ Image image = editorModel.getTabIcon();
+ if(image !=null)
+ setPageImage(index, image);
+ return index;
+ } catch (PartInitException e) {
+ ErrorDialog.openError(
+ getSite().getShell(),
+ "Error creating nested text editor",
+ null,
+ e.getStatus());
+ return -1;
+ }
+
+ }
+
+ /**
+ * Creates the pages of the multi-page editor.
+ */
+ protected void createPages() {
+ // get the page descriptions
+ pageProvider = createPageProvider();
+ // Get the current tabFolder
+ tabFolderModel = pageProvider.getCurrentTabFolder();
+
+ refreshTabs();
+
+// // iterate over pages to be show
+// for( Object rawPageModel : tabFolderModel.getChildren() )
+// {
+// // Get the model interface
+// ITabItemModel tabItem = tabFolderModel.createChildSashModel( rawPageModel);
+// if(tabItem instanceof IEditorModel )
+// {
+// addPage((IEditorModel)tabItem );
+// }
+// else if(tabItem instanceof IComponentModel )
+// {
+// addPage((IComponentModel)tabItem );
+// }
+// else
+// {
+// System.err.println("Can't create page for model '" + tabItem + "'. Skipp it.");
+// }
+// }
+ }
+
+ /**
+ * Create the provider.
+ * Subclass must implements this method. It should return the provider used by the editor.
+ *
+ */
+ abstract protected ISashWindowsContentProvider createPageProvider();
+
+ /**
+ * Refresh the tabs order.
+ * This method should be called after the model list is modified.
+ */
+ protected void refreshTabs()
+ {
+ // get list of diagrams to be displayed
+ List<?> newModels = tabFolderModel.getChildren();
+
+ // Check if each model has an open pageEditor. If not, create the editor.
+ Iterator<?> newIter = newModels.iterator();
+ while(newIter.hasNext())
+ {
+ Object model = newIter.next();
+ if( ! tabExistsFor(model) )
+ { // create a new editor for the model
+ addEditor(tabFolderModel.createChildSashModel(model) );
+ }
+ }
+
+ // If open editor count is the same has models count,
+ // all models have an editor. So, end the refresh process.
+ if( newModels.size() == getPageCount() )
+ return;
+
+ // There is some extra editors ! remove them.
+ // remove extra editors : for each open editor, check if its model is in
+ // the list of required models.
+ List<IPageModel> toBeRemoved = new ArrayList<IPageModel>();
+ Iterator<IPageModel> currentIter = currentTabs.iterator();
+ while(currentIter.hasNext())
+ {
+ IPageModel model = currentIter.next();
+ if( ! newModels.contains(model.getRawModel() ) )
+ { // remove editor
+ toBeRemoved.add(model);
+ }
+ }
+
+ // Remove editor from the editors displayed by the multi editor
+ Iterator<IPageModel> removeIter = toBeRemoved.iterator();
+ while(removeIter.hasNext())
+ {
+ IPageModel model = removeIter.next();
+ removeEditor(model);
+ }
+ }
+
+ /**
+ * Check if an editor exists for the specified model.
+ * @param model the diagram (model) that should be displayed
+ * @return <code>true</code> if the editor exists for this model
+ */
+ private boolean tabExistsFor(Object model) {
+ for(IPageModel tabItem : currentTabs)
+ {
+ if(tabItem.getRawModel() == model)
+ return true;
+ }
+ return false;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.MultiPageEditorPart#removePage(int)
+ */
+ @Override
+ public void removePage(int pageIndex) {
+ super.removePage(pageIndex);
+ // synchronize the list of currently shown models.
+ currentTabs.remove(pageIndex);
+ }
+
+ /**
+ * Removes the editor associated to the specified model.
+ * @param model the diagram (model) displayed in the editor
+ */
+ private void removeEditor(IPageModel model) {
+ int index = currentTabs.indexOf(model);
+ removePage(index);
+ }
+
+ /**
+ * Add a new editor at the end of existing editors.
+ * First, create the editor, then add it to the tabs.
+ * @param contentProvider the diagram (model) to be displayed in the editor
+ */
+ private void addEditor(IPageModel tabItem) {
+ // Check if an editor already exists
+ if( tabExistsFor(tabItem) )
+ {
+ if(log.isLoggable(Level.FINE))
+ log.fine("Editor already exists for '" + tabItem + "'");
+ return;
+ }
+
+ int editorIndex=-1;
+ if(tabItem instanceof IEditorModel )
+ {
+ editorIndex = addPage((IEditorModel)tabItem );
+ }
+ else if(tabItem instanceof IComponentModel )
+ {
+ editorIndex = addPage((IComponentModel)tabItem );
+ }
+ else
+ {
+ System.err.println("Can't create page for model '" + tabItem + "'. Skipp it.");
+ return;
+ }
+
+ // Add the model in the list of current tabs.
+ currentTabs.add(tabItem);
+ // set active page
+ setActivePage(editorIndex);
+
+ }
+
+
+} \ No newline at end of file
diff --git a/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/contentprovider/simple/FakePageModel.java b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/contentprovider/simple/FakePageModel.java
new file mode 100644
index 00000000000..a03c17c334a
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/contentprovider/simple/FakePageModel.java
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.simple;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.swt.graphics.Image;
+
+
+/**
+ * A fake page for testing purpose
+ * @author dumoulin
+ */
+public class FakePageModel implements IPageModel {
+
+ String title;
+ static int count=0;
+
+ public FakePageModel() {
+ title="noname"+count++;
+ }
+
+ /**
+ * @param title
+ */
+ public FakePageModel(String title) {
+ this.title = title;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getRawModel() {
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Image getTabIcon() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getTabTitle() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/contentprovider/simple/SimpleSashWindowsContentProviderTest.java b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/contentprovider/simple/SimpleSashWindowsContentProviderTest.java
new file mode 100644
index 00000000000..d0e1a1fbcf6
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/contentprovider/simple/SimpleSashWindowsContentProviderTest.java
@@ -0,0 +1,172 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.contentprovider.simple;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel;
+import org.eclipse.swt.SWT;
+
+import junit.framework.TestCase;
+
+
+/**
+ * @author dumoulin
+ */
+public class SimpleSashWindowsContentProviderTest extends TestCase {
+
+ protected SimpleSashWindowsContentProvider contentProvider;
+
+ /**
+ * Initialize the tree
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ createContentProvider();
+ }
+
+ /**
+ * Create a tree
+ */
+ private void createContentProvider() {
+ contentProvider = new SimpleSashWindowsContentProvider();
+ }
+
+ /**
+ * Test method for {@link org.eclipse.papyrus.sasheditor.contentprovider.simple.SimpleSashWindowsContentProvider#addPage(org.eclipse.papyrus.sasheditor.contentprovider.IPageModel)}.
+ */
+ public void testAddTabIPageModel() {
+ IPageModel newModel = new FakePageModel();
+ contentProvider.addPage(newModel);
+
+ assertTrue("Folder contains added item", contentProvider.getCurrentTabFolder().getChildren().contains(newModel));
+ }
+
+ /**
+ * Test method for {@link org.eclipse.papyrus.sasheditor.contentprovider.simple.SimpleSashWindowsContentProvider#movePage(org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel, int, int)}.
+ */
+ public void testMoveTabITabFolderModelIntInt() {
+ fail("Not yet implemented");
+ }
+
+ /**
+ * Test method for {@link org.eclipse.papyrus.sasheditor.contentprovider.simple.SimpleSashWindowsContentProvider#movePage(org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel, int, org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel, int)}.
+ */
+ public void testMoveTabITabFolderModelIntITabFolderModelInt() {
+ fail("Not yet implemented");
+ }
+
+ /**
+ * Test method for {@link org.eclipse.papyrus.sasheditor.contentprovider.simple.SimpleSashWindowsContentProvider#createFolder(org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel, int, org.eclipse.papyrus.sasheditor.contentprovider.ITabFolderModel, int)}.
+ */
+ public void testCreateFolder() {
+
+ // Create content
+// IPageModel newModel1 = new FakePageModel();
+// contentProvider.addTab(newModel1);
+// IPageModel newModel2 = new FakePageModel();
+// contentProvider.addTab(newModel2);
+// IPageModel newModel3 = new FakePageModel();
+// contentProvider.addTab(newModel2);
+// IPageModel newModel4 = new FakePageModel();
+// contentProvider.addTab(newModel2);
+
+ // Create models
+ List<IPageModel> models = new ArrayList<IPageModel>();
+ for(int i=0; i<8; i++)
+ {
+ IPageModel newModel = new FakePageModel("model"+i);
+ contentProvider.addPage(newModel);
+ models.add(newModel);
+ }
+
+ ITabFolderModel folder = contentProvider.getCurrentTabFolder();
+
+// // Do move tab 0 to right
+// ITabFolderModel newFolder = contentProvider.createFolder(folder, 0, folder, SWT.RIGHT);
+// // Check creation
+// assertNotNull("Folder created", newFolder);
+// // Check if correctly attached and reachable
+// assertEquals("Tab 2 added in correct folder", folder, contentProvider.getParentFolder(newModel2));
+// assertEquals("Tab 1 added in correct folder", newFolder, contentProvider.getParentFolder(newModel1));
+//
+//// assertNotNull("folder attached", contentProvider.getParentFolder(newModel1));
+//// assertNotNull("folder attached", contentProvider.getParentFolder(newModel1));
+//
+// assertTrue("Folder contains added item", newFolder.getChildren().contains(newModel1));
+// assertTrue("Folder contains added item", folder.getChildren().contains(newModel2));
+
+
+ //
+ // Create another folder
+ int index = 0;
+ IPageModel movedTab = models.get(index++);
+ assertEquals("moved tab is the first in tab", movedTab, folder.getChildren().get(0) );
+ ITabFolderModel newFolder2 = contentProvider.createFolder(folder, 0, folder, SWT.UP);
+ assertFolderCreated(folder, newFolder2, movedTab);
+
+ movedTab = models.get(index++);
+ assertEquals("moved tab is the first in tab", movedTab, folder.getChildren().get(0) );
+ ITabFolderModel newFolder3 = contentProvider.createFolder(folder, 0, newFolder2, SWT.UP);
+ assertFolderCreated(folder, newFolder3, movedTab);
+
+ movedTab = models.get(index++);
+ assertEquals("moved tab is the first in tab", movedTab, folder.getChildren().get(0) );
+ ITabFolderModel newFolder4 = contentProvider.createFolder(folder, 0, newFolder2, SWT.DOWN);
+ assertFolderCreated(folder, newFolder4, movedTab);
+
+ movedTab = models.get(index++);
+ assertEquals("moved tab is the first in tab", movedTab, folder.getChildren().get(0) );
+ ITabFolderModel newFolder5 = contentProvider.createFolder(folder, 0, folder, SWT.LEFT);
+ assertFolderCreated(folder, newFolder5, movedTab);
+
+ }
+
+ /**
+ * Assert folder is correctly created
+ * @param srcFolder
+ * @param srcTab
+ * @param createdFolder
+ * @param movedTab
+ */
+ protected void assertFolderCreated(ITabFolderModel srcFolder, ITabFolderModel createdFolder, IPageModel movedTab )
+ {
+ // Check creation
+ assertNotNull("Folder created", createdFolder);
+ // Check if correctly attached and reachable
+ assertEquals("Item added in correct folder", createdFolder, contentProvider.getParentFolder(movedTab));
+ // Check removed from source
+ assertFalse("item removed from source folder", srcFolder.getChildren().contains(movedTab));
+ // Check contained in created folder
+ assertTrue("Folder contains added item", createdFolder.getChildren().contains(movedTab));
+ }
+ /**
+ * Test method for {@link org.eclipse.papyrus.sasheditor.contentprovider.simple.SimpleSashWindowsContentProvider#removePage(int)}.
+ */
+ public void testRemoveTabInt() {
+ fail("Not yet implemented");
+ }
+
+ /**
+ * Test method for {@link org.eclipse.papyrus.sasheditor.contentprovider.simple.SimpleSashWindowsContentProvider#removePage(org.eclipse.papyrus.sasheditor.contentprovider.IPageModel)}.
+ */
+ public void testRemoveTabIPageModel() {
+ fail("Not yet implemented");
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/CompareTreeVisitor.java b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/CompareTreeVisitor.java
new file mode 100644
index 00000000000..689625c5ab0
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/CompareTreeVisitor.java
@@ -0,0 +1,224 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.sasheditor.editor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.papyrus.sasheditor.internal.AbstractPart;
+import org.eclipse.papyrus.sasheditor.internal.ComponentPart;
+import org.eclipse.papyrus.sasheditor.internal.EditorPart;
+import org.eclipse.papyrus.sasheditor.internal.RootPart;
+import org.eclipse.papyrus.sasheditor.internal.SashPanelPart;
+import org.eclipse.papyrus.sasheditor.internal.TabFolderPart;
+import org.eclipse.papyrus.sasheditor.internal.TabItemPart;
+import org.eclipse.papyrus.sasheditor.internal.PartVisitor;
+
+
+/**
+ * This visitor allows to compare all node of the sash system to all node of the model.
+ * For each node, a compare method is called, which can perform any comparison stuff.
+ *
+ * @author dumoulin
+ */
+public class CompareTreeVisitor extends PartVisitor {
+
+ /**
+ * Stack of parents.
+ */
+ protected Stack<Object> modelStack = new Stack<Object>();
+ protected Stack<AbstractPart> partStack = new Stack<AbstractPart>();
+
+ /**
+ * Push the parents in stacks
+ * @param modelParent
+ * @param partParent
+ */
+ private void pushParents( Object modelParent, AbstractPart partParent)
+ {
+ partStack.push(partParent);
+ modelStack.push(modelParent);
+ }
+
+ /**
+ * Pop the parents.
+ */
+ private void popParents()
+ {
+ partStack.pop();
+ modelStack.pop();
+ }
+
+ /**
+ * Get current model parent.
+ * Retrieve it from the stack.
+ * The parent is the upper model node visited
+ * @return
+ */
+ protected Object getModelParent()
+ {
+ return modelStack.top();
+ }
+
+ /**
+ * Get current part parent.
+ * Retrieve it from the stack.
+ * The parent is the upper part node visited
+ * @return
+ */
+ protected Object getPartParent()
+ {
+ return partStack.top();
+ }
+
+ /**
+ * Visit the specified type, and then visit the childs..
+ * @param folder
+ */
+ public void accept(TabFolderPart tile) {
+ acceptTabFolderPart(tile);
+ // Visit the children
+// pushParents(tile., tile);
+ tile.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the childs..
+ * @param folder
+ */
+ public void accept(RootPart tile) {
+ acceptRootPart(tile);
+ // Visit the children
+ tile.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the children..
+ * @param folder
+ */
+ public void accept(SashPanelPart tile) {
+ acceptSashPanelPart(tile);
+ // Visit the children
+ tile.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the children..
+ * @param folder
+ */
+ public void accept(TabItemPart tile) {
+ acceptTabItemPart(tile);
+ // Visit the children
+ tile.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the children..
+ * @param tile
+ */
+ public void accept(EditorPart tile) {
+ acceptEditorTile(tile);
+ // Visit the children
+ tile.visitChildren(this);
+ }
+
+ /**
+ * Visit the specified type, and then visit the children ..
+ * @param tile
+ */
+ public void accept(ComponentPart part) {
+ acceptEditorTile(part);
+ // Visit the children
+ part.visitChildren(this);
+ }
+
+
+ // ----------------------------------------------
+
+
+ /**
+ * Visit the specified type.
+ * @param tile
+ */
+ protected void acceptRootPart(RootPart tile) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param tile
+ */
+ protected void acceptSashPanelPart(SashPanelPart tile) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param tile
+ */
+ protected void acceptTabFolderPart(TabFolderPart tile) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param tile
+ */
+ protected void acceptTabItemPart(TabItemPart tile) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param tile
+ */
+ protected void acceptEditorTile(EditorPart tile) {
+ }
+
+ /**
+ * Visit the specified type.
+ * @param tile
+ */
+ protected void acceptEditorTile(ComponentPart tile) {
+ }
+
+
+ /**
+ * A simple stack implementation
+ * @author dumoulin
+ * @param <T>
+ */
+ protected class Stack<T> {
+ private List<T> list = new ArrayList<T>();
+ /**
+ * Push object in the stack
+ * @param object
+ */
+ public void push( T object)
+ {
+ list.add(object);
+ }
+
+ /**
+ * Get the index of the top of the stack.
+ * @return
+ */
+ private int topIndex() {
+ return list.size()-1;
+ }
+ /**
+ * Get top of stack.
+ * @return
+ */
+ public T top() {
+ return list.get(topIndex());
+ }
+
+ /**
+ * Pop object in statck
+ * @return
+ */
+ public T pop() {
+ return list.remove(topIndex());
+ }
+ }
+
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/MessagePartModel.java b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/MessagePartModel.java
new file mode 100644
index 00000000000..eba1c0e90c4
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/MessagePartModel.java
@@ -0,0 +1,80 @@
+package org.eclipse.papyrus.sasheditor.editor;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IComponentModel;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * Description of the first page
+ *
+ * @author dumoulin
+ */
+
+public class MessagePartModel implements IComponentModel {
+
+ /** The text editor used in page 0. */
+ private Control board;
+
+ private String title;
+ private String msg;
+
+ static private int count = 0;
+
+
+ /**
+ *
+ */
+ public MessagePartModel(String msg) {
+ title = "newMsg " + count++;
+ this.msg = msg;
+ }
+
+ /**
+ * @param title
+ */
+ public MessagePartModel(String title, String msg) {
+ this.title = title;
+ this.msg = msg;
+ }
+
+ /**
+ * Return the control to be shown.
+ * {@inheritDoc}
+ */
+ public Composite createPartControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ FillLayout layout = new FillLayout();
+ composite.setLayout(layout);
+ StyledText text;
+
+ text = new StyledText(composite, SWT.H_SCROLL | SWT.V_SCROLL);
+ text.setEditable(false);
+
+ text.setText(" " + msg + " - " + getTabTitle());
+ return composite;
+ }
+
+ public Image getTabIcon() {
+ return null;
+ }
+
+ public String getTabTitle() {
+ return title;
+ }
+
+ /**
+ * Return this. In this implementation, the rawModel and the IEditorModel are the same.
+ *
+ */
+ public Object getRawModel() {
+ return this;
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/SashMultiPageEditorTest.java b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/SashMultiPageEditorTest.java
new file mode 100644
index 00000000000..9de8fb71e40
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/SashMultiPageEditorTest.java
@@ -0,0 +1,21 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.sasheditor.editor;
+
+import junit.framework.TestCase;
+
+
+/**
+ * @author dumoulin
+ */
+public class SashMultiPageEditorTest extends TestCase {
+
+ /**
+ * Test method for {@link org.eclipse.papyrus.sasheditor.editor.AbstractMultiPageSashEditor#refreshTabs()}.
+ */
+ public void testRefreshTabs() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
diff --git a/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/ShellEditor.java b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/ShellEditor.java
new file mode 100644
index 00000000000..af7c9197ed4
--- /dev/null
+++ b/org.eclipse.papyrus.sasheditor/test/org/eclipse/papyrus/sasheditor/editor/ShellEditor.java
@@ -0,0 +1,116 @@
+/*****************************************************************************
+ * Copyright (c) 2009 CEA LIST & LIFL
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.sasheditor.editor;
+
+import org.eclipse.papyrus.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.sasheditor.contentprovider.simple.SimpleSashWindowsContentProvider;
+import org.eclipse.papyrus.sasheditor.internal.IMultiEditorManager;
+import org.eclipse.papyrus.sasheditor.internal.SashWindowsContainer;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+
+/**
+ * A standalone application testing the Sash system.
+ * @author dumoulin
+ */
+public class ShellEditor {
+
+ protected SashWindowsContainer sashContainer;
+ protected ISashWindowsContentProvider contentProvider;
+
+ /**
+ * Constructor.
+ * @param parent
+ */
+ public ShellEditor(Shell parent) {
+ parent.setText(this.getClass().getSimpleName());
+ init();
+ createPartControl(parent);
+
+ // add tabItem
+ int count = 0;
+ IPageModel tabItem = new MessagePartModel("msg" + count++);
+ contentProvider.addPage(tabItem);
+ tabItem = new MessagePartModel("msg" + count++);
+ contentProvider.addPage(tabItem);
+
+ sashContainer.refreshTabs();
+ }
+
+ /**
+ * init th class
+ */
+ protected void init()
+ {
+ contentProvider = new SimpleSashWindowsContentProvider();
+ sashContainer = new SashWindowsContainer();
+
+ initContentProvider();
+ sashContainer.setContentProvider(contentProvider);
+
+ }
+
+ /**
+ * Create some windows.
+ */
+ protected void initContentProvider()
+ {
+ int count = 0;
+ IPageModel tabItem = new MessagePartModel("msg" + count++);
+ contentProvider.addPage(tabItem);
+
+ tabItem = new MessagePartModel("msg0" + count++);
+ contentProvider.addPage(tabItem);
+ }
+ /**
+ * Create SWT control of this class
+ * @param parent
+ */
+ protected void createPartControl(Composite parent)
+ {
+// Text newText = new Text(parent, SWT.BORDER & SWT.SCROLL_PAGE);
+
+ sashContainer.createPartControl(parent);
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ Display display = new Display();
+
+ Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+ new ShellEditor(shell);
+
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+
+ display.dispose();
+ }
+
+}

Back to the top