From 7bb93e09dc787fe578deb2d7c48f7ae78c644c4b Mon Sep 17 00:00:00 2001
From: Raphael Girardot <raphael.girardot@synchrotron-soleil.fr>
Date: Tue, 8 Oct 2013 14:32:41 +0000
Subject: [PATCH] beta version of DockingCore

---
 dockingcore/pom.xml                           |  74 ++++++
 .../fr/soleil/docking/ADockingManager.java    | 179 +++++++++++++
 .../docking/action/NewPerspectiveAction.java  |  67 +++++
 .../action/RemovePerspectiveAction.java       |  64 +++++
 .../action/SaveDefaultPerspertiveAction.java  |  74 ++++++
 .../action/SelectPerspectiveAction.java       |  77 ++++++
 .../fr/soleil/docking/action/ViewAction.java  |  59 +++++
 .../docking/component/PerspectiveMenu.java    |  82 ++++++
 .../docking/exception/DockingException.java   |  28 +++
 .../docking/perspective/FilePerspective.java  |  20 ++
 .../docking/perspective/IPerspective.java     |  22 ++
 .../perspective/IPerspectiveFactory.java      |  67 +++++
 .../docking/perspective/Perspective.java      |  57 +++++
 .../perspective/PerspectiveFactory.java       | 235 ++++++++++++++++++
 .../perspective/ResourcePerspective.java      |  16 ++
 .../java/fr/soleil/docking/view/IView.java    | 100 ++++++++
 .../fr/soleil/docking/view/IViewFactory.java  |  89 +++++++
 .../fr/soleil/docking/view/IViewListener.java |   7 +
 .../fr/soleil/docking/view/ViewFactory.java   | 152 +++++++++++
 19 files changed, 1469 insertions(+)
 create mode 100644 dockingcore/pom.xml
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/ADockingManager.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/action/NewPerspectiveAction.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/action/RemovePerspectiveAction.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/action/SaveDefaultPerspertiveAction.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/action/SelectPerspectiveAction.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/action/ViewAction.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/component/PerspectiveMenu.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/exception/DockingException.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/perspective/FilePerspective.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/perspective/IPerspective.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/perspective/IPerspectiveFactory.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/perspective/Perspective.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/perspective/PerspectiveFactory.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/perspective/ResourcePerspective.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/view/IView.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/view/IViewFactory.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/view/IViewListener.java
 create mode 100644 dockingcore/src/main/java/fr/soleil/docking/view/ViewFactory.java

diff --git a/dockingcore/pom.xml b/dockingcore/pom.xml
new file mode 100644
index 0000000..183b542
--- /dev/null
+++ b/dockingcore/pom.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>super-pom-java</artifactId>
+    <groupId>fr.soleil</groupId>
+    <version>RELEASE</version>
+  </parent>
+
+  <groupId>fr.soleil.lib</groupId>
+  <artifactId>DockingCore</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+
+  <name>Docking Core</name>
+  <description>A project that defines some common abstractions in docking</description>
+
+  <developers>
+    <developer>
+      <id>girardot</id>
+      <name>Raphaël GIRARDOT</name>
+      <email>raphael.girardot@synchrotron-soleil.fr</email>
+      <organization>SOLEIL</organization>
+      <organizationUrl>http://www.synchrotron-soleil.fr</organizationUrl>
+      <roles>
+        <role>Manager</role>
+      </roles>
+      <timezone>1</timezone>
+    </developer>
+    <developer>
+      <id>viguier</id>
+      <name>Grégory VIGUIER</name>
+      <email>gregory.viguier@synchrotron-soleil.fr</email>
+      <organization>SOLEIL</organization>
+      <organizationUrl>http://www.synchrotron-soleil.fr</organizationUrl>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+      <timezone>1</timezone>
+    </developer>
+  </developers>
+
+  <scm>
+    <connection>scm:svn:https://svn.code.sf.net/p/comete/code/trunk/DockingCore</connection>
+    <developerConnection>scm:svn:https://svn.code.sf.net/p/comete/code/trunk/DockingCore</developerConnection>
+    <url>https://svn.code.sf.net/p/comete/code/trunk/DockingCore</url>
+  </scm>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <configuration>
+          <encoding>UTF-8</encoding>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <encoding>UTF-8</encoding>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.swinglabs</groupId>
+      <artifactId>swingx</artifactId>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/dockingcore/src/main/java/fr/soleil/docking/ADockingManager.java b/dockingcore/src/main/java/fr/soleil/docking/ADockingManager.java
new file mode 100644
index 0000000..38790bd
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/ADockingManager.java
@@ -0,0 +1,179 @@
+package fr.soleil.docking;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.util.List;
+import java.util.prefs.Preferences;
+
+import javax.swing.Action;
+import javax.swing.JComponent;
+
+import fr.soleil.docking.action.SaveDefaultPerspertiveAction;
+import fr.soleil.docking.exception.DockingException;
+import fr.soleil.docking.perspective.IPerspective;
+import fr.soleil.docking.perspective.IPerspectiveFactory;
+import fr.soleil.docking.view.IViewFactory;
+
+/**
+ * A class that prepares docking. Obtain your RootWindow from this class.
+ * 
+ * @author HARDION
+ * @author GIRARDOT
+ */
+public abstract class ADockingManager implements PropertyChangeListener {
+
+    private boolean automaticallySavePerspective = true;
+
+    public boolean isAutomaticallySavePerspective() {
+        return automaticallySavePerspective;
+    }
+
+    public void setAutomaticallySavePerspective(boolean automaticallySavePerspective) {
+        this.automaticallySavePerspective = automaticallySavePerspective;
+    }
+
+    protected IPerspectiveFactory perspectiveFactory = null;
+    protected IViewFactory viewFactory = null;
+
+    public ADockingManager(IViewFactory viewFactory, IPerspectiveFactory perspectiveFactory) {
+        this.viewFactory = viewFactory;
+        this.viewFactory.addPropertyChangeListener(this);
+        this.perspectiveFactory = perspectiveFactory;
+        this.perspectiveFactory.addPropertyChangeListener(this);
+        this.getDockingArea();
+        try {
+            this.resetLayout();
+        } catch (DockingException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public List<Action> getActionList() {
+        List<Action> result = null;
+        if (viewFactory != null) {
+            result = viewFactory.getActionList();
+        }
+        if (Boolean.getBoolean("DEBUG")) {
+            result.add(new SaveDefaultPerspertiveAction(this));
+        }
+        return result;
+    }
+
+    /**
+     * Returns this {@link ADockingManager}'s main docking area
+     * 
+     * @return A {@link JComponent}
+     */
+    public abstract JComponent getDockingArea();
+
+    /**
+     * Creates a new docking area
+     * 
+     * @return A {@link JComponent}
+     */
+    public abstract JComponent createNewDockingArea();
+
+    /**
+     * Returns the perspective factory
+     * 
+     * @return The perspective factory
+     */
+    public IPerspectiveFactory getPerspectiveFactory() {
+        return perspectiveFactory;
+    }
+
+    /**
+     * Returns the view factory
+     * 
+     * @return The view factory
+     */
+    public IViewFactory getViewFactory() {
+        return viewFactory;
+    }
+
+    public void loadPreferences(Preferences prefs) throws DockingException {
+        this.perspectiveFactory.loadPreferences(prefs);
+        this.viewFactory.loadPreferences(prefs);
+        this.loadPerspective(perspectiveFactory.getSelectedPerspective());
+    }
+
+    public void resetLayout() throws DockingException {
+        loadPerspective(perspectiveFactory.getDefault());
+    }
+
+    /**
+     * @param is
+     */
+    public abstract void loadPerspective(IPerspective perspective) throws DockingException;
+
+    public void savePreferences(Preferences prefs) throws DockingException {
+        // Save current Perspective
+        this.savePerspective(this.perspectiveFactory.getSelectedPerspective());
+
+        // Save Preferences of perspective Factory
+        this.perspectiveFactory.savePreferences(prefs);
+
+        // Save Preferences of Views
+        this.viewFactory.savePreferences(prefs);
+
+    }
+
+    /**
+     * @param perspective
+     * @param out
+     * @throws DockingException
+     */
+    protected abstract void savePerspective(IPerspective perspective) throws DockingException;
+
+    public void saveDefault(File file) throws DockingException {
+        this.savePerspective(this.perspectiveFactory.getSelectedPerspective());
+        this.perspectiveFactory.saveSelected(file);
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (evt.getSource().equals(perspectiveFactory)) {
+            if (evt.getPropertyName().equals(IPerspectiveFactory.SELECTED_PERSPECTIVE)) {
+                IPerspective oldd = (IPerspective) evt.getOldValue();
+                IPerspective neww = (IPerspective) evt.getNewValue();
+                try {
+                    if (automaticallySavePerspective) {
+                        this.savePerspective(oldd);
+                    }
+                    this.loadPerspective(neww);
+                } catch (DockingException e) {
+                    e.printStackTrace();
+                }
+            }
+        } else if (evt.getSource().equals(viewFactory)) {
+            if (evt.getPropertyName().equals(IViewFactory.VIEWS)) {
+                this.updateViews(evt);
+            }
+        }
+
+    }
+
+    protected abstract void updateViews(PropertyChangeEvent evt);
+
+    public void saveSelectedPerspective() throws DockingException {
+        this.savePerspective(this.perspectiveFactory.getSelectedPerspective());
+    }
+
+    /**
+     * Enable the docking or not If the docking is disable, the inherit class must disable all
+     * functionality of the docking. I must be comparable to a JPanel composed by JtabbedPane,
+     * JSplitPane etc...
+     * 
+     * @param enabledDocking
+     */
+    public abstract void setEnabledDocking(boolean enabledDocking);
+
+    /**
+     * Get the Enabled Docking property
+     * 
+     * @return true if the docking is enabled
+     */
+    public abstract boolean isEnabledDocking();
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/action/NewPerspectiveAction.java b/dockingcore/src/main/java/fr/soleil/docking/action/NewPerspectiveAction.java
new file mode 100644
index 0000000..eabdf29
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/action/NewPerspectiveAction.java
@@ -0,0 +1,67 @@
+/*
+ * Created on 10 juin 2005
+ * with Eclipse
+ */
+package fr.soleil.docking.action;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
+
+import fr.soleil.docking.perspective.IPerspective;
+import fr.soleil.docking.perspective.IPerspectiveFactory;
+
+public class NewPerspectiveAction extends AbstractAction {
+
+    private static final long serialVersionUID = -3295304363885371351L;
+
+    private final IPerspectiveFactory factory;
+
+    public NewPerspectiveAction(IPerspectiveFactory factory) {
+        super();
+
+        this.factory = factory;
+
+        // This is an instance initializer; it is executed just after the
+        // constructor of the superclass is invoked
+
+        // The following values are completely optional
+        putValue(NAME, "New");
+        // Set tool tip text
+        putValue(SHORT_DESCRIPTION, "New Perspective");
+
+        // This text is not directly used by any Swing component;
+        // however, this text could be used in a help system
+        putValue(LONG_DESCRIPTION, "Adding a new perspective");
+
+        // Set an icon
+        // Icon icon = new ImageIcon("icon.gif");
+        // putValue(Action.SMALL_ICON, icon);
+
+        // Set a mnemonic character. In most look and feels, this causes the
+        // specified character to be underlined This indicates that if the component
+        // using this action has the focus and In some look and feels, this causes
+        // the specified character in the label to be underlined and
+        putValue(MNEMONIC_KEY, new Integer(java.awt.event.KeyEvent.VK_N));
+
+        // Set an accelerator key; this value is used by menu items
+        putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl shift N"));
+
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        IPerspective current = factory.getSelectedPerspective();
+        String result = JOptionPane.showInputDialog("Enter the name of the new perspective");
+        if (!result.equals("")) {
+            IPerspective p = factory.createPerspective(result);
+            byte[] array = current.getByteArray();
+            byte[] copy = (array == null ? null : array.clone());
+            p.setByteArray(copy);
+            factory.setSelectedPerspective(p);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/dockingcore/src/main/java/fr/soleil/docking/action/RemovePerspectiveAction.java b/dockingcore/src/main/java/fr/soleil/docking/action/RemovePerspectiveAction.java
new file mode 100644
index 0000000..7ac13e4
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/action/RemovePerspectiveAction.java
@@ -0,0 +1,64 @@
+/*
+ * Created on 10 juin 2005
+ * with Eclipse
+ */
+package fr.soleil.docking.action;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
+
+import fr.soleil.docking.perspective.IPerspective;
+import fr.soleil.docking.perspective.IPerspectiveFactory;
+
+public class RemovePerspectiveAction extends AbstractAction {
+
+    private static final long serialVersionUID = 4431356413525394103L;
+
+    private final IPerspectiveFactory factory;
+
+    public RemovePerspectiveAction(IPerspectiveFactory factory) {
+        super();
+
+        this.factory = factory;
+
+        // This is an instance initializer; it is executed just after the
+        // constructor of the superclass is invoked
+
+        // The following values are completely optional
+        putValue(NAME, "Remove");
+        // Set tool tip text
+        putValue(SHORT_DESCRIPTION, "Remove Perspective");
+
+        // This text is not directly used by any Swing component;
+        // however, this text could be used in a help system
+        putValue(LONG_DESCRIPTION, "Removing a perspective");
+
+        // Set an icon
+        // Icon icon = new ImageIcon("icon.gif");
+        // putValue(Action.SMALL_ICON, icon);
+
+        // Set a mnemonic character. In most look and feels, this causes the
+        // specified character to be underlined This indicates that if the component
+        // using this action has the focus and In some look and feels, this causes
+        // the specified character in the label to be underlined and
+        putValue(MNEMONIC_KEY, new Integer(java.awt.event.KeyEvent.VK_R));
+
+        // Set an accelerator key; this value is used by menu items
+        putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl shift R"));
+
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        IPerspective result = (IPerspective) JOptionPane.showInputDialog(null, "Select the perspective to remove",
+                "Remove perspective", JOptionPane.PLAIN_MESSAGE, null, factory.getPerspectives(),
+                factory.getSelectedPerspective());
+        if (result != null) {
+            factory.removePerspective(result);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/dockingcore/src/main/java/fr/soleil/docking/action/SaveDefaultPerspertiveAction.java b/dockingcore/src/main/java/fr/soleil/docking/action/SaveDefaultPerspertiveAction.java
new file mode 100644
index 0000000..2f95f56
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/action/SaveDefaultPerspertiveAction.java
@@ -0,0 +1,74 @@
+/*
+ * Created on 10 juin 2005
+ * with Eclipse
+ */
+package fr.soleil.docking.action;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFileChooser;
+
+import org.jdesktop.swingx.JXErrorPane;
+
+import fr.soleil.docking.ADockingManager;
+
+public class SaveDefaultPerspertiveAction extends AbstractAction {
+
+    private static final long serialVersionUID = -5058889377558638684L;
+
+    private final ADockingManager dockingManager;
+
+    public SaveDefaultPerspertiveAction(ADockingManager manager) {
+        super();
+        this.dockingManager = manager;
+        // This is an instance initializer; it is executed just after the
+        // constructor of the superclass is invoked
+
+        // The following values are completely optional
+        putValue(NAME, "Save Default");
+        // Set tool tip text
+        putValue(SHORT_DESCRIPTION, "Save this perspective to file system");
+
+        // This text is not directly used by any Swing component;
+        // however, this text could be used in a help system
+        putValue(LONG_DESCRIPTION, "Save this perspective to file system");
+
+        // Set an icon
+        // Icon icon = new ImageIcon("icon.gif");
+        // putValue(Action.SMALL_ICON, view.getIcon());
+
+        // Set a mnemonic character. In most look and feels, this causes the
+        // specified character to be underlined This indicates that if the component
+        // using this action has the focus and In some look and feels, this causes
+        // the specified character in the label to be underlined and
+        // putValue(Action.MNEMONIC_KEY, new Integer(java.awt.event.KeyEvent.VK_N));
+
+        // Set an accelerator key; this value is used by menu items
+        // putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("alt shift N"));
+
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent evt) {
+        JFileChooser chooser = new JFileChooser();
+
+        if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
+            File file = chooser.getSelectedFile();
+            try {
+                if (!file.exists())
+                    file.createNewFile();
+                dockingManager.saveDefault(file);
+            } catch (Exception e) {
+                JXErrorPane.showDialog(e);
+            }
+        }
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/dockingcore/src/main/java/fr/soleil/docking/action/SelectPerspectiveAction.java b/dockingcore/src/main/java/fr/soleil/docking/action/SelectPerspectiveAction.java
new file mode 100644
index 0000000..ecbf614
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/action/SelectPerspectiveAction.java
@@ -0,0 +1,77 @@
+/*
+ * Created on 10 juin 2005
+ * with Eclipse
+ */
+package fr.soleil.docking.action;
+
+import java.awt.event.ActionEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.KeyStroke;
+
+import fr.soleil.docking.perspective.IPerspective;
+import fr.soleil.docking.perspective.IPerspectiveFactory;
+
+public class SelectPerspectiveAction extends AbstractAction implements PropertyChangeListener {
+
+    private static final long serialVersionUID = 6402682388656946588L;
+
+    private final IPerspectiveFactory factory;
+    private final IPerspective perspective;
+
+    public SelectPerspectiveAction(IPerspectiveFactory factory, IPerspective perspective) {
+        super();
+
+        this.factory = factory;
+        this.factory.addPropertyChangeListener(this);
+        this.perspective = perspective;
+
+        // This is an instance initializer; it is executed just after the
+        // constructor of the superclass is invoked
+
+        // The following values are completely optional
+        putValue(NAME, perspective.getName());
+        // Set tool tip text
+        putValue(SHORT_DESCRIPTION, "Select " + perspective.getName());
+
+        // This text is not directly used by any Swing component;
+        // however, this text could be used in a help system
+        putValue(LONG_DESCRIPTION, "Select " + perspective.getName() + " as current perspective");
+
+        // Set an icon
+        // Icon icon = new ImageIcon("icon.gif");
+        // putValue(Action.SMALL_ICON, icon);
+
+        // Set a mnemonic character. In most look and feels, this causes the
+        // specified character to be underlined This indicates that if the component
+        // using this action has the focus and In some look and feels, this causes
+        // the specified character in the label to be underlined and
+        putValue(MNEMONIC_KEY, new Integer(java.awt.event.KeyEvent.VK_N));
+
+        // Set an accelerator key; this value is used by menu items
+        putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("ctrl shift N"));
+
+        // Set selected
+        putValue(SELECTED_KEY, this.factory.getSelectedPerspective() == this.perspective);
+
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        factory.setSelectedPerspective(perspective);
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (evt.getPropertyName().equals(IPerspectiveFactory.SELECTED_PERSPECTIVE)) {
+            if (evt.getNewValue().equals(this.perspective)) {
+                putValue(SELECTED_KEY, true);
+            } else {
+                putValue(SELECTED_KEY, false);
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/dockingcore/src/main/java/fr/soleil/docking/action/ViewAction.java b/dockingcore/src/main/java/fr/soleil/docking/action/ViewAction.java
new file mode 100644
index 0000000..803c793
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/action/ViewAction.java
@@ -0,0 +1,59 @@
+package fr.soleil.docking.action;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import fr.soleil.docking.view.IView;
+
+public class ViewAction extends AbstractAction {
+
+    private static final long serialVersionUID = 2102313023512752659L;
+
+    private final IView view;
+
+    public ViewAction(IView view) {
+        super();
+        this.view = view;
+        // This is an instance initializer; it is executed just after the
+        // constructor of the superclass is invoked
+
+        // The following values are completely optional
+        putValue(NAME, view.getTitle());
+        // Set tool tip text
+        putValue(SHORT_DESCRIPTION, view.getTitle());
+
+        // This text is not directly used by any Swing component;
+        // however, this text could be used in a help system
+        putValue(LONG_DESCRIPTION, view.getTitle());
+
+        // Set an icon
+        // Icon icon = new ImageIcon("icon.gif");
+        putValue(SMALL_ICON, view.getIcon());
+
+        // Set a mnemonic character. In most look and feels, this causes the
+        // specified character to be underlined This indicates that if the component
+        // using this action has the focus and In some look and feels, this causes
+        // the specified character in the label to be underlined and
+        // putValue(Action.MNEMONIC_KEY, new Integer(java.awt.event.KeyEvent.VK_N));
+
+        // Set an accelerator key; this value is used by menu items
+        // putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("alt shift N"));
+
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (!view.isVisible()) {
+            view.setVisible(true);
+        } else {
+            view.setVisible(false);
+        }
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return view.isEnabled();
+    }
+
+}
\ No newline at end of file
diff --git a/dockingcore/src/main/java/fr/soleil/docking/component/PerspectiveMenu.java b/dockingcore/src/main/java/fr/soleil/docking/component/PerspectiveMenu.java
new file mode 100644
index 0000000..bba0fbb
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/component/PerspectiveMenu.java
@@ -0,0 +1,82 @@
+package fr.soleil.docking.component;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.List;
+
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JMenuItem;
+import javax.swing.JRadioButtonMenuItem;
+
+import fr.soleil.docking.action.NewPerspectiveAction;
+import fr.soleil.docking.perspective.IPerspectiveFactory;
+
+public class PerspectiveMenu extends javax.swing.JMenu implements PropertyChangeListener {
+
+    private static final long serialVersionUID = -6492472049072385936L;
+
+    protected IPerspectiveFactory factory;
+
+    public PerspectiveMenu(IPerspectiveFactory factory) {
+        super();
+        this.setText("Perspective");
+        this.factory = factory;
+        factory.addPropertyChangeListener(this);
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (evt.getSource() instanceof IPerspectiveFactory) {
+            if (evt.getPropertyName().equals(IPerspectiveFactory.PERSPECTIVES)) {
+
+            }
+        }
+    }
+
+    @Override
+    public JMenuItem add(Action a) {
+        if (a instanceof NewPerspectiveAction) {
+            this.addSeparator();
+        }
+        return super.add(a);
+    }
+
+    @Override
+    public void setPopupMenuVisible(boolean flag) {
+        if (flag) {
+            this.removeAll();
+            List<Action> actions = factory.getActionList();
+            for (Action action : actions) {
+                add(action);
+                // JRadioButtonMenuItem item = (JRadioButtonMenuItem) this.add(action);
+                // Boolean b = (Boolean) action.getValue("SELECTED_KEY");
+                // if (b != null) {
+                // item.setSelected(b);
+                // }
+            }
+        }
+        super.setPopupMenuVisible(flag);
+    }
+
+    @Override
+    protected JMenuItem createActionComponent(Action a) {
+        JMenuItem mi = new JRadioButtonMenuItem() {
+            private static final long serialVersionUID = -3334691946468856486L;
+
+            @Override
+            protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
+                PropertyChangeListener pcl = createActionChangeListener(this);
+                if (pcl == null) {
+                    pcl = super.createActionPropertyChangeListener(a);
+                }
+                return pcl;
+            }
+
+        };
+        mi.setHorizontalTextPosition(JButton.TRAILING);
+        mi.setVerticalTextPosition(JButton.CENTER);
+        return mi;
+    }
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/exception/DockingException.java b/dockingcore/src/main/java/fr/soleil/docking/exception/DockingException.java
new file mode 100644
index 0000000..87db8a8
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/exception/DockingException.java
@@ -0,0 +1,28 @@
+package fr.soleil.docking.exception;
+
+/**
+ * An Exception thrown in case of problems with docking
+ * 
+ * @author girardot
+ */
+public class DockingException extends Exception {
+
+    private static final long serialVersionUID = 5753611012723925293L;
+
+    public DockingException() {
+        super();
+    }
+
+    public DockingException(String message) {
+        super(message);
+    }
+
+    public DockingException(Throwable cause) {
+        super(cause);
+    }
+
+    public DockingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/perspective/FilePerspective.java b/dockingcore/src/main/java/fr/soleil/docking/perspective/FilePerspective.java
new file mode 100644
index 0000000..7de39db
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/perspective/FilePerspective.java
@@ -0,0 +1,20 @@
+package fr.soleil.docking.perspective;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class FilePerspective extends Perspective {
+
+    public FilePerspective(String name, File file) throws IOException {
+        super(name);
+        if ((file != null) && (file.isFile())) {
+            InputStream in = new FileInputStream(file);
+            if (in != null) {
+                byteArray = readByteArray(in);
+            }
+        }
+    }
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/perspective/IPerspective.java b/dockingcore/src/main/java/fr/soleil/docking/perspective/IPerspective.java
new file mode 100644
index 0000000..a45cd31
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/perspective/IPerspective.java
@@ -0,0 +1,22 @@
+package fr.soleil.docking.perspective;
+
+/**
+ * Objects that implement this interface should know where to put each dockable component.
+ * 
+ * @author Hardion
+ * @author GIRARDOT
+ */
+public interface IPerspective {
+
+    public String getName();
+
+    /**
+     * @return the byteArray
+     */
+    public byte[] getByteArray();
+
+    /**
+     * @param byteArray the byteArray to set
+     */
+    public void setByteArray(byte[] byteArray);
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/perspective/IPerspectiveFactory.java b/dockingcore/src/main/java/fr/soleil/docking/perspective/IPerspectiveFactory.java
new file mode 100644
index 0000000..2b2b389
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/perspective/IPerspectiveFactory.java
@@ -0,0 +1,67 @@
+package fr.soleil.docking.perspective;
+
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.util.List;
+import java.util.prefs.Preferences;
+
+import javax.swing.Action;
+
+import fr.soleil.docking.exception.DockingException;
+
+/**
+ * Factory that manages Perspectives
+ * 
+ * @author Hardion
+ * @author GIRARDOT
+ */
+public interface IPerspectiveFactory {
+
+    public static final String SELECTED_PERSPECTIVE = "selectedPerspective";
+    public static final String PERSPECTIVES = "perspectives";
+
+    /**
+     * Returns the Perspective associated with this id.
+     * 
+     * @param id The id of the desired Perspective.
+     * @return The Perspective associated with this id.
+     */
+    public IPerspective getPerspective(Object id);
+
+    /**
+     * Returns the selected IPerspective
+     * 
+     * @return The selected IPerspective
+     */
+    public IPerspective getSelectedPerspective();
+
+    /**
+     * Sets the selected IPerspective
+     * 
+     * @param selectedPerspective The IPerspective to set as selected
+     */
+    public void setSelectedPerspective(IPerspective selectedPerspective);
+
+    public void setSelectedPerspective(String perspective);
+
+    public void loadPreferences(Preferences prefs);
+
+    public void savePreferences(Preferences prefs);
+
+    public List<Action> getActionList();
+
+    public void saveSelected(File file) throws DockingException;
+
+    public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener);
+
+    public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener);
+
+    public IPerspective getDefault();
+
+    public IPerspective createPerspective(final String name);
+
+    public IPerspective removePerspective(IPerspective perspective);
+
+    public IPerspective[] getPerspectives();
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/perspective/Perspective.java b/dockingcore/src/main/java/fr/soleil/docking/perspective/Perspective.java
new file mode 100644
index 0000000..8fb7f95
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/perspective/Perspective.java
@@ -0,0 +1,57 @@
+/**
+ * 
+ */
+package fr.soleil.docking.perspective;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class Perspective implements IPerspective {
+    private final String name;
+    protected byte[] byteArray;
+
+    public Perspective(String name) {
+        this.name = name;
+        byteArray = new byte[0];
+    }
+
+    @Override
+    public byte[] getByteArray() {
+        return byteArray;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setByteArray(byte[] byteArray) {
+        this.byteArray = byteArray;
+    }
+
+    @Override
+    public String toString() {
+        return this.name;
+    }
+
+    /**
+     * Reads a <code>byte</code> array from an {@link InputStream} and returns it
+     * 
+     * @param in The {@link InputStream}
+     * @return A <code>byte[]</code>
+     * @throws IOException If a problem occurred while trying to read the {@link InputStream}
+     */
+    protected byte[] readByteArray(InputStream in) throws IOException {
+        byte[] result = null;
+        if (in != null) {
+            result = new byte[in.available()];
+            int length = in.read(result);
+            if (length != result.length) {
+                result = null;
+            }
+        }
+        return result;
+    }
+
+}
\ No newline at end of file
diff --git a/dockingcore/src/main/java/fr/soleil/docking/perspective/PerspectiveFactory.java b/dockingcore/src/main/java/fr/soleil/docking/perspective/PerspectiveFactory.java
new file mode 100644
index 0000000..84d2078
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/perspective/PerspectiveFactory.java
@@ -0,0 +1,235 @@
+package fr.soleil.docking.perspective;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+
+import javax.swing.Action;
+
+import fr.soleil.docking.action.NewPerspectiveAction;
+import fr.soleil.docking.action.RemovePerspectiveAction;
+import fr.soleil.docking.action.SelectPerspectiveAction;
+import fr.soleil.docking.exception.DockingException;
+
+public class PerspectiveFactory implements IPerspectiveFactory {
+
+    private static final String DEFAULT_PERSPECTIVE_NAME = "Default";
+
+    protected PropertyChangeSupport support;
+    private final List<IPerspective> perspectives;
+    private IPerspective selectedPerspective;
+    private final String defaultPerspectiveName;
+
+    public PerspectiveFactory() {
+        this(new Perspective(DEFAULT_PERSPECTIVE_NAME));
+    }
+
+    public PerspectiveFactory(IPerspective defaultt) {
+        perspectives = new ArrayList<IPerspective>(1);
+        defaultPerspectiveName = defaultt.getName();
+        perspectives.add(defaultt);
+        selectedPerspective = defaultt;
+        support = new PropertyChangeSupport(this);
+    }
+
+    @Override
+    public IPerspective createPerspective(final String name) {
+        IPerspective result = this.getPerspective(name);
+        if (result == null) {
+            result = new Perspective(name);
+            this.add(result);
+        }
+
+        return result;
+    }
+
+    /**
+     * @param e
+     * @return
+     * @see java.util.ArrayList#add(java.lang.Object)
+     */
+    public boolean add(IPerspective e) {
+        boolean result = perspectives.add(e);
+        if (result) {
+            support.fireIndexedPropertyChange(PERSPECTIVES, perspectives.indexOf(result), null, result);
+        }
+
+        return result;
+    }
+
+    @Override
+    public IPerspective getPerspective(Object name) {
+        IPerspective result = null;
+        for (IPerspective perspective : perspectives) {
+            if (perspective.getName().equalsIgnoreCase((String) name)) {
+                result = perspective;
+                break;
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public IPerspective getSelectedPerspective() {
+        return selectedPerspective;
+    }
+
+    @Override
+    public void setSelectedPerspective(IPerspective selectedPerspective) {
+        if (!this.selectedPerspective.equals(selectedPerspective) && this.perspectives.contains(selectedPerspective)) {
+            IPerspective old = this.selectedPerspective;
+            this.selectedPerspective = selectedPerspective;
+            support.firePropertyChange(SELECTED_PERSPECTIVE, old, this.selectedPerspective);
+        }
+    }
+
+    @Override
+    public void setSelectedPerspective(String perspective) {
+        setSelectedPerspective(getPerspective(perspective));
+    }
+
+    @Override
+    public void loadPreferences(Preferences prefs) {
+        Preferences factoryPrefs = prefs.node("PerspectiveFactory");
+        Preferences perspectivesPrefs = factoryPrefs.node("Perspectives");
+
+        String[] keys = new String[0];
+        try {
+            keys = perspectivesPrefs.keys();
+        } catch (BackingStoreException e1) {
+            e1.printStackTrace();
+        }
+
+        byte[] ko = new byte[0];
+        byte[] layout = null;
+        IPerspective perspective = null;
+        for (int i = 0; i < keys.length; i++) {
+            perspective = this.getPerspective(keys[i]);
+            if (perspective == null) {
+                perspective = this.createPerspective(keys[i]);
+            }
+            layout = perspectivesPrefs.getByteArray(keys[i], ko);
+            if (layout != ko) {
+                perspective.setByteArray(layout);
+            }
+        }
+
+        // get the value of
+        String selected = factoryPrefs.get("selected", selectedPerspective.getName());
+        this.setSelectedPerspective(this.getPerspective(selected));
+
+    }
+
+    @Override
+    public void savePreferences(Preferences prefs) {
+        Preferences factoryPrefs = prefs.node("PerspectiveFactory");
+        Preferences perspectivesPrefs = factoryPrefs.node("Perspectives");
+
+        try {
+            factoryPrefs.clear();
+            perspectivesPrefs.clear();
+        } catch (BackingStoreException e1) {
+            e1.printStackTrace();
+        }
+        factoryPrefs.put("selected", selectedPerspective.getName());
+        for (IPerspective perspective : perspectives) {
+
+            perspectivesPrefs.putByteArray(perspective.getName(), perspective.getByteArray());
+        }
+    }
+
+    @Override
+    public List<Action> getActionList() {
+        List<Action> result = new ArrayList<Action>(1);
+
+        for (IPerspective perspective : perspectives) {
+            result.add(new SelectPerspectiveAction(this, perspective));
+        }
+
+        result.add(new NewPerspectiveAction(this));
+        result.add(new RemovePerspectiveAction(this));
+
+        return result;
+    }
+
+    @Override
+    public void saveSelected(File file) throws DockingException {
+        DockingException dockingException = null;
+        FileOutputStream out = null;
+        try {
+            out = new FileOutputStream(file);
+            try {
+                out.write(selectedPerspective.getByteArray());
+            } catch (Exception e) {
+                if (dockingException == null) {
+                    dockingException = new DockingException("Error during file writing", e);
+                }
+            } finally {
+                try {
+                    out.close();
+                } catch (Exception e) {
+                    if (dockingException == null) {
+                        dockingException = new DockingException("Error while releasing file access", e);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            if (dockingException == null) {
+                dockingException = new DockingException("Error during file access", e);
+            }
+        }
+        if (dockingException != null) {
+            throw dockingException;
+        }
+    }
+
+    /**
+     * @param listener
+     * @see java.beans.PropertyChangeSupport#addPropertyChangeListener(java.beans.PropertyChangeListener)
+     */
+    @Override
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        support.addPropertyChangeListener(listener);
+    }
+
+    /**
+     * @param listener
+     * @see java.beans.PropertyChangeSupport#removePropertyChangeListener(java.beans.PropertyChangeListener)
+     */
+    @Override
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        support.removePropertyChangeListener(listener);
+    }
+
+    @Override
+    public IPerspective getDefault() {
+
+        return this.getPerspective(defaultPerspectiveName);
+    }
+
+    @Override
+    public IPerspective[] getPerspectives() {
+        return perspectives.toArray(new IPerspective[perspectives.size()]);
+    }
+
+    @Override
+    public IPerspective removePerspective(final IPerspective p) {
+        int index = perspectives.indexOf(p);
+        if (index != -1 && !(p instanceof ResourcePerspective) && !p.getName().equals(defaultPerspectiveName)) {
+            // Exist and it's not the default perspective
+            perspectives.remove(index);
+            support.fireIndexedPropertyChange(PERSPECTIVES, index, p, null);
+        }
+        return p;
+    }
+
+    public IPerspective removePerspective(final String name) {
+        return this.removePerspective(this.getPerspective(name));
+    }
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/perspective/ResourcePerspective.java b/dockingcore/src/main/java/fr/soleil/docking/perspective/ResourcePerspective.java
new file mode 100644
index 0000000..bf2d5b6
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/perspective/ResourcePerspective.java
@@ -0,0 +1,16 @@
+package fr.soleil.docking.perspective;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ResourcePerspective extends Perspective {
+
+    public ResourcePerspective(String name, String resource) throws IOException {
+        super(name);
+        InputStream in = ResourcePerspective.this.getClass().getResourceAsStream(resource);
+        if (in != null) {
+            byteArray = readByteArray(in);
+        }
+    }
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/view/IView.java b/dockingcore/src/main/java/fr/soleil/docking/view/IView.java
new file mode 100644
index 0000000..a69fbb5
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/view/IView.java
@@ -0,0 +1,100 @@
+package fr.soleil.docking.view;
+
+import java.awt.Color;
+import java.awt.Component;
+
+import javax.swing.Icon;
+
+/**
+ * A dynamically created view containing an id.
+ * 
+ * @author Hardion
+ * @author GIRARDOT
+ */
+public interface IView {
+
+    /**
+     * Returns the view id.
+     * 
+     * @return the view id
+     */
+    public Object getId();
+
+    /**
+     * @return the enabled
+     */
+    public boolean isEnabled();
+
+    /**
+     * @param enabled the enabled to set
+     */
+    public void setEnabled(boolean enabled);
+
+    /**
+     * @return the enabled
+     */
+    public boolean isVisible();
+
+    /**
+     * @param enabled the enabled to set
+     */
+    public void setVisible(boolean visible);
+
+    /**
+     * @return the title
+     */
+    public String getTitle();
+
+    /**
+     * @return the icon
+     */
+    public Icon getIcon();
+
+    /**
+     * @return the component
+     */
+    public Component getComponent();
+
+    /**
+     * Returns this {@link IView}'s background {@link Color}
+     * 
+     * @return A {@link Color}
+     */
+    public Color getViewBackground();
+
+    /**
+     * Sets the background {@link Color} of this {@link IView}
+     * 
+     * @param bg The background {@link Color} to set
+     */
+    public void setViewBackground(Color bg);
+
+    /**
+     * Returns this {@link IView}'s foreground {@link Color}
+     * 
+     * @return A {@link Color}
+     */
+    public Color getViewForeground();
+
+    /**
+     * Sets the foreground {@link Color} of this {@link IView}
+     * 
+     * @param fg The foreground {@link Color} to set
+     */
+    public void setViewForeground(Color fg);
+
+    /**
+     * Sets the {@link IView} closable or not.
+     * 
+     * @param closable The boolean to set.
+     */
+    public void setClosable(boolean closable);
+
+    /**
+     * Add an {@link IViewListener} to the view..
+     * 
+     * @param listener The {@link IViewListener} to add.
+     */
+    public void addViewListener(IViewListener listener);
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/view/IViewFactory.java b/dockingcore/src/main/java/fr/soleil/docking/view/IViewFactory.java
new file mode 100644
index 0000000..d2baff9
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/view/IViewFactory.java
@@ -0,0 +1,89 @@
+package fr.soleil.docking.view;
+
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.prefs.Preferences;
+
+import javax.swing.Action;
+
+/**
+ * A factory that takes care of initializing dockable components and transmitting models.
+ * 
+ * @author Hardion
+ * @author GIRARDOT
+ */
+public interface IViewFactory {
+
+    public static final String VIEWS = "views";
+
+    /**
+     * Returns the DynamicView associated with this id (creates the
+     * DynamicView).
+     * 
+     * @param id
+     *            The id of the desired DynamicView
+     * @return The DynamicView associated with this id
+     */
+    public IView getView(Object id);
+
+    public Collection<IView> getViews();
+
+    /**
+     * Returns the ActionList
+     * 
+     * @param id
+     *            The id of the desired DynamicView
+     * @return The DynamicView associated with this id
+     */
+    public List<Action> getActionList();
+
+    /**
+     * Saves preferences
+     * 
+     * @param prefs preferences in which to save
+     */
+    public void savePreferences(Preferences prefs);
+
+    /**
+     * Loads preferences
+     * 
+     * @param prefs preferences to load
+     */
+    public void loadPreferences(Preferences prefs);
+
+    public int size();
+
+    /**
+     * @param listener
+     * @see java.beans.PropertyChangeSupport#addPropertyChangeListener(java.beans.PropertyChangeListener)
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener);
+
+    /**
+     * @param listener
+     * @see java.beans.PropertyChangeSupport#removePropertyChangeListener(java.beans.PropertyChangeListener)
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener);
+
+    public Object readViewId(ObjectInputStream in) throws IOException;
+
+    public void writeViewId(Object id, ObjectOutputStream out) throws IOException;
+
+    public IView addView(IView view);
+
+    public boolean removeView(IView view);
+
+    /**
+     * Removes an {@link IView}, determined by an id, from list and from the
+     * docking area.
+     * 
+     * @param id The id of the {@link IView} to remove.
+     * @return The removed {@link IView} if such an {@link IView} existed and
+     *         was successfully removed, <code>null</code> otherwise.
+     */
+    public IView removeView(Object id);
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/view/IViewListener.java b/dockingcore/src/main/java/fr/soleil/docking/view/IViewListener.java
new file mode 100644
index 0000000..25dd4eb
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/view/IViewListener.java
@@ -0,0 +1,7 @@
+package fr.soleil.docking.view;
+
+public interface IViewListener {
+
+    public void viewClosed();
+
+}
diff --git a/dockingcore/src/main/java/fr/soleil/docking/view/ViewFactory.java b/dockingcore/src/main/java/fr/soleil/docking/view/ViewFactory.java
new file mode 100644
index 0000000..513458f
--- /dev/null
+++ b/dockingcore/src/main/java/fr/soleil/docking/view/ViewFactory.java
@@ -0,0 +1,152 @@
+package fr.soleil.docking.view;
+
+import java.awt.Component;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.prefs.Preferences;
+
+import javax.swing.Action;
+
+import fr.soleil.docking.action.ViewAction;
+
+public class ViewFactory implements IViewFactory {
+
+    protected final Collection<IView> views;
+    protected final PropertyChangeSupport support;
+
+    public ViewFactory() {
+        super();
+        views = Collections.newSetFromMap(new ConcurrentHashMap<IView, Boolean>());
+        support = new PropertyChangeSupport(this);
+    }
+
+    @Override
+    public IView getView(Object id) {
+        IView result = null;
+        for (IView view : views) {
+            if (view.getId().equals(id)) {
+                result = view;
+                break;
+            }
+        }
+        return result;
+    }
+
+    public Component getViewComponent(Object id) {
+        Component component;
+        IView view = getView(id);
+        if (view == null) {
+            component = null;
+        } else {
+            component = view.getComponent();
+        }
+        return component;
+    }
+
+    protected void setViewEnabled(Object id, boolean enabled) {
+        IView view = getView(id);
+        if (view != null) {
+            view.setVisible(enabled);
+            view.setEnabled(enabled);
+        }
+    }
+
+    @Override
+    public void loadPreferences(Preferences prefs) {
+        // Does nothing in particular. If you expect something to be done, you should extend this class and override
+        // this method
+    }
+
+    @Override
+    public void savePreferences(Preferences prefs) {
+        // Does nothing in particular. If you expect something to be done, you should extend this class and override
+        // this method
+    }
+
+    @Override
+    public IView addView(IView view) {
+        if (views.add(view)) {
+            support.firePropertyChange(VIEWS, null, view);
+        } else {
+            view = null;
+        }
+        return view;
+    }
+
+    @Override
+    public IView removeView(Object id) {
+        IView toRemove = getView(id);
+        if (!removeView(toRemove)) {
+            toRemove = null;
+        }
+        return toRemove;
+    }
+
+    @Override
+    public boolean removeView(IView view) {
+        boolean result;
+        if (view == null) {
+            result = false;
+        } else {
+            result = views.remove(view);
+            if (result) {
+                support.firePropertyChange(VIEWS, view, null);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public List<Action> getActionList() {
+        List<Action> result = new ArrayList<Action>(views.size());
+        for (IView view : views) {
+            result.add(new ViewAction(view));
+        }
+        return result;
+    }
+
+    @Override
+    public int size() {
+        return views.size();
+    }
+
+    @Override
+    public Collection<IView> getViews() {
+        return views;
+    }
+
+    @Override
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        support.addPropertyChangeListener(listener);
+    }
+
+    @Override
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        support.removePropertyChangeListener(listener);
+    }
+
+    @Override
+    public Object readViewId(ObjectInputStream in) throws IOException {
+        Object id = null;
+        try {
+            id = in.readObject();
+        } catch (ClassNotFoundException e) {
+            throw new IOException(e);
+        }
+        return id;
+    }
+
+    @Override
+    public void writeViewId(Object id, ObjectOutputStream out) throws IOException {
+        out.writeObject(id);
+    }
+
+}
\ No newline at end of file
-- 
GitLab