You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by sk...@apache.org on 2015/04/17 13:28:25 UTC

[1/3] cayenne git commit: CAY-2001 | Saving a display state of Project

Repository: cayenne
Updated Branches:
  refs/heads/master 85a127bd3 -> 1f514c4b1


CAY-2001 | Saving a display state of Project


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/2888668b
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/2888668b
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/2888668b

Branch: refs/heads/master
Commit: 2888668b11071e4dae0082f13d324aae53b805b2
Parents: 85a127b
Author: Savva Kolbachev <s....@gmail.com>
Authored: Wed Apr 15 18:12:16 2015 +0300
Committer: Savva Kolbachev <s....@gmail.com>
Committed: Wed Apr 15 18:12:16 2015 +0300

----------------------------------------------------------------------
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |   1 +
 .../modeler/CayenneModelerController.java       |   9 +-
 .../cayenne/modeler/ProjectController.java      |  24 +-
 .../apache/cayenne/modeler/ProjectTreeView.java |  57 +-
 .../modeler/editor/ProcedureTabbedView.java     |  14 +-
 .../modeler/pref/ProjectStatePreferences.java   | 323 ++++++++
 .../cayenne/modeler/util/ProjectStateUtil.java  | 785 +++++++++++++++++++
 7 files changed, 1190 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/2888668b/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index 66d3f09..533dfda 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -17,6 +17,7 @@ Changes/New Features:
 CAY-1991 More control over generated String property names
 CAY-1992 Allow to exclude DataMap java class from Modeler class generation
 CAY-1995 Add support for iterators to Select
+CAY-2001 Saving a display state of Project
 
 Bug Fixes:
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2888668b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java
index 87772b7..9f32197 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java
@@ -28,6 +28,7 @@ import org.apache.cayenne.modeler.pref.ComponentGeometry;
 import org.apache.cayenne.modeler.pref.FSPath;
 import org.apache.cayenne.modeler.util.CayenneController;
 import org.apache.cayenne.modeler.util.FileFilters;
+import org.apache.cayenne.modeler.util.ProjectStateUtil;
 import org.apache.cayenne.project.Project;
 import org.apache.cayenne.project.validation.ProjectValidator;
 import org.apache.cayenne.validation.ValidationFailure;
@@ -60,7 +61,7 @@ public class CayenneModelerController extends CayenneController {
 
     protected CayenneModelerFrame frame;
 	private EditorView editorView;
-    
+
     public CayenneModelerController(){}
 
     public CayenneModelerController(Application application) {
@@ -106,6 +107,7 @@ public class CayenneModelerController extends CayenneController {
         frame.addWindowListener(new WindowAdapter() {
 
             public void windowClosing(WindowEvent e) {
+                ProjectStateUtil.saveLastState(projectController);
                 getApplication().getActionManager().getAction(ExitAction.class).exit();
             }
         });
@@ -188,7 +190,8 @@ public class CayenneModelerController extends CayenneController {
      * Action method invoked on project closing.
      */
     public void projectClosedAction() {
-        
+        ProjectStateUtil.saveLastState(projectController);
+
         // --- update view
         frame.setView(null);
 
@@ -238,6 +241,8 @@ public class CayenneModelerController extends CayenneController {
             frame.fireRecentFileListChanged();
         }
 
+        ProjectStateUtil.fireLastState(projectController);
+
         // for validation purposes combine load failures with post-load validation (not
         // sure if that'll cause duplicate messages?).
         List<ValidationFailure> allFailures = new ArrayList<ValidationFailure>();

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2888668b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java
index 2b8c668..4d75685 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectController.java
@@ -104,6 +104,7 @@ import org.apache.cayenne.modeler.event.QueryDisplayListener;
 import org.apache.cayenne.modeler.event.RelationshipDisplayEvent;
 import org.apache.cayenne.modeler.pref.DataMapDefaults;
 import org.apache.cayenne.modeler.pref.DataNodeDefaults;
+import org.apache.cayenne.modeler.pref.ProjectStatePreferences;
 import org.apache.cayenne.modeler.util.CayenneController;
 import org.apache.cayenne.modeler.util.CircularArray;
 import org.apache.cayenne.modeler.util.Comparators;
@@ -240,7 +241,7 @@ public class ProjectController extends CayenneController {
     protected CircularArray controllerStateHistory;
     protected int maxHistorySize = 20;
 
-    private EntityResolver entityResolver;    
+    private EntityResolver entityResolver;
 
     /**
      * Project files watcher. When project file is changed, user will be asked
@@ -390,6 +391,11 @@ public class ProjectController extends CayenneController {
 
     }
 
+    public ProjectStatePreferences getProjectStatePreferences() {
+        return (ProjectStatePreferences) application.getCayenneProjectPreferences().getProjectDetailObject(
+                ProjectStatePreferences.class, getPreferenceForDataDomain());
+    }
+
     public void projectOpened() {
         CayenneModelerFrame frame = (CayenneModelerFrame) getView();
         addDataNodeDisplayListener(frame);
@@ -568,6 +574,10 @@ public class ProjectController extends CayenneController {
         return currentState.parentPath;
     }
 
+    public DisplayEvent getLastDisplayEvent() {
+        return currentState.event;
+    }
+
     public void addDomainDisplayListener(DomainDisplayListener listener) {
         listenerList.add(DomainDisplayListener.class, listener);
     }
@@ -607,7 +617,7 @@ public class ProjectController extends CayenneController {
     public void removeDbEntityListener(DbEntityListener listener) {
         listenerList.remove(DbEntityListener.class, listener);
     }
-    
+
     public void addProjectOnSaveListener(ProjectOnSaveListener listener) {
     	listenerList.add(ProjectOnSaveListener.class, listener);
     }
@@ -615,7 +625,7 @@ public class ProjectController extends CayenneController {
     public void removeProjectOnSaveListener(ProjectOnSaveListener listener) {
     	listenerList.remove(ProjectOnSaveListener.class, listener);
     }
-    
+
     public void addObjEntityListener(ObjEntityListener listener) {
         listenerList.add(ObjEntityListener.class, listener);
     }
@@ -1586,7 +1596,7 @@ public class ProjectController extends CayenneController {
 
     /**
      * adds callback method manipulation listener
-     * 
+     *
      * @param listener
      *            listener
      */
@@ -1596,7 +1606,7 @@ public class ProjectController extends CayenneController {
 
     /**
      * fires callback method manipulation event
-     * 
+     *
      * @param e
      *            event
      */
@@ -1623,7 +1633,7 @@ public class ProjectController extends CayenneController {
 
     /**
      * adds listener class manipulation listener
-     * 
+     *
      * @param listener
      *            listener
      */
@@ -1633,7 +1643,7 @@ public class ProjectController extends CayenneController {
 
     /**
      * fires entity listener manipulation event
-     * 
+     *
      * @param e
      *            event
      */

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2888668b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectTreeView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectTreeView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectTreeView.java
index b38a7aa..4c002b0 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectTreeView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ProjectTreeView.java
@@ -96,6 +96,7 @@ import javax.swing.tree.ExpandVetoException;
 import javax.swing.tree.MutableTreeNode;
 import javax.swing.tree.TreePath;
 import javax.swing.tree.TreeSelectionModel;
+import java.awt.Rectangle;
 import java.awt.dnd.DnDConstants;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -150,7 +151,8 @@ public class ProjectTreeView extends JTree implements DomainDisplayListener,
                         for (int i = 0; i < paths.length; i++) {
                             projectPaths[i] = createProjectPath(paths[i]);
 
-                            if(i>0 && paths[i].getParentPath() != paths[i-1].getParentPath()) {
+                            TreePath parentPath = paths[i].getParentPath();
+                            if(i>0 && parentPath != null && !parentPath.equals(paths[i - 1].getParentPath())) {
                                 commonParentPath = false;
                             }
                         }
@@ -187,13 +189,17 @@ public class ProjectTreeView extends JTree implements DomainDisplayListener,
             @Override
             public void treeWillExpand(TreeExpansionEvent e) throws ExpandVetoException {
                 TreePath path = e.getPath();
-                processSelection(path);
+                if (!isPathSelected(path) && !isSelectionEmpty()) {
+                    setSelectionPath(path);
+                }
             }
 
             @Override
             public void treeWillCollapse(TreeExpansionEvent e) throws ExpandVetoException {
                 TreePath path = e.getPath();
-                processSelection(path);
+                if (!isPathSelected(path) && !isSelectionEmpty()) {
+                    setSelectionPath(path);
+                }
             }
         };
 
@@ -218,6 +224,7 @@ public class ProjectTreeView extends JTree implements DomainDisplayListener,
         mediator.addProcedureDisplayListener(this);
         mediator.addQueryListener(this);
         mediator.addQueryDisplayListener(this);
+        mediator.addMultipleObjectsDisplayListener(this);
 
         mediator.getApplication().getActionManager().setupCutCopyPaste(
                 this,
@@ -363,9 +370,35 @@ public class ProjectTreeView extends JTree implements DomainDisplayListener,
         });
     }
 
-    public void currentObjectsChanged(
-            MultipleObjectsDisplayEvent e,
-            Application application) {
+    public void currentObjectsChanged(MultipleObjectsDisplayEvent e, Application application) {
+        if (e.getSource() == this || e.getParentNode() == null) {
+            return;
+        }
+
+        ConfigurationNode[] nodes = e.getNodes();
+        TreePath[] treePaths = new TreePath[nodes.length];
+
+        for (int i = 0; i < nodes.length; i++) {
+            DefaultMutableTreeNode treeNode = getProjectModel().getNodeForObjectPath(new Object[] {e.getParentNode(), nodes[i]});
+            if (treeNode != null) {
+                treePaths[i] = new TreePath(treeNode.getPath());
+            } else if (e.getParentNode() == nodes[i]) {
+                treeNode = getProjectModel().getNodeForObjectPath(new Object[] {e.getParentNode()});
+                treePaths[i] = new TreePath(treeNode.getPath());
+            }
+        }
+
+        if (!isVisible(treePaths[0])) {
+            makeVisible(treePaths[0]);
+
+            Rectangle bounds = getPathBounds(treePaths[0]);
+            if (bounds != null) {
+                bounds.height = getVisibleRect().height;
+                scrollRectToVisible(bounds);
+            }
+        }
+
+        setSelectionPaths(treePaths);
     }
 
     public void procedureAdded(ProcedureEvent e) {
@@ -772,7 +805,17 @@ public class ProjectTreeView extends JTree implements DomainDisplayListener,
     /** Makes node current, visible and selected. */
     protected void showNode(DefaultMutableTreeNode node) {
         TreePath path = new TreePath(node.getPath());
-        scrollPathToVisible(path);
+
+        if (!isVisible(path)) {
+            makeVisible(path);
+
+            Rectangle bounds = getPathBounds(path);
+            if (bounds != null) {
+                bounds.height = getVisibleRect().height;
+                scrollRectToVisible(bounds);
+            }
+        }
+
         setSelectionPath(path);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2888668b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTabbedView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTabbedView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTabbedView.java
index f74e2dc..ab2f1f8 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTabbedView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ProcedureTabbedView.java
@@ -19,13 +19,6 @@
 
 package org.apache.cayenne.modeler.editor;
 
-import java.awt.Component;
-
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
 import org.apache.cayenne.map.ProcedureParameter;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
@@ -35,6 +28,12 @@ import org.apache.cayenne.modeler.event.ProcedureDisplayListener;
 import org.apache.cayenne.modeler.event.ProcedureParameterDisplayEvent;
 import org.apache.cayenne.modeler.event.ProcedureParameterDisplayListener;
 
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.Component;
+
 /**
  * Tabbed panel for stored procedure editing.
  * 
@@ -94,6 +93,7 @@ public class ProcedureTabbedView extends JTabbedPane implements ProcedureDisplay
         ProcedureParameter[] parameters = e.getProcedureParameters();
 
         if (parameters.length > 0) {
+            setSelectedComponent(procedureParameterPanel);
             procedureParameterPanel.selectParameters(parameters);
         }
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2888668b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/ProjectStatePreferences.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/ProjectStatePreferences.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/ProjectStatePreferences.java
new file mode 100644
index 0000000..502f037
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/ProjectStatePreferences.java
@@ -0,0 +1,323 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.pref;
+
+import org.apache.cayenne.pref.RenamedPreferences;
+
+import java.util.prefs.Preferences;
+
+public class ProjectStatePreferences extends RenamedPreferences {
+
+    private String event;
+    private String domain;
+    private String node;
+    private String dataMap;
+    private String objEntity;
+    private String dbEntity;
+    private String embeddable;
+    private String embAttrs;
+    private String objAttrs;
+    private String dbAttrs;
+    private String objRels;
+    private String dbRels;
+    private String procedure;
+    private String procedureParams;
+    private String query;
+    private String multipleObjects;
+    private String parentObject;
+
+    public static final String EVENT_PROPERTY = "event";
+    public static final String DOMAIN_PROPERTY = "domain";
+    public static final String NODE_PROPERTY = "node";
+    public static final String DATA_MAP_PROPERTY = "dataMap";
+    public static final String OBJ_ENTITY_PROPERTY = "objEntity";
+    public static final String DB_ENTITY_PROPERTY = "dbEntity";
+    public static final String EMBEDDABLE_PROPERTY = "embeddable";
+    public static final String EMBEDDABLE_ATTRS_PROPERTY = "embAttrs";
+    public static final String OBJ_ATTRS_PROPERTY = "objAttrs";
+    public static final String DB_ATTRS_PROPERTY = "dbAttrs";
+    public static final String OBJ_RELS_PROPERTY = "objRels";
+    public static final String DB_RELS_PROPERTY = "dbRels";
+    public static final String PROCEDURE_PROPERTY = "procedure";
+    public static final String PROCEDURE_PARAMS_PROPERTY = "procedureParams";
+    public static final String QUERY_PROPERTY = "query";
+    public static final String MULTIPLE_OBJECTS_PROPERTY = "multipleObjects";
+    public static final String PARENT_OBJECT_PROPERTY = "parentObject";
+
+    public ProjectStatePreferences(Preferences pref) {
+        super(pref);
+    }
+
+    public String getEvent() {
+        if (event == null) {
+            event = getCurrentPreference().get(EVENT_PROPERTY, "");
+        }
+
+        return event;
+    }
+
+    public void setEvent(String event) {
+        this.event = event;
+        if (event != null) {
+            getCurrentPreference().put(EVENT_PROPERTY, event);
+        }
+    }
+
+    public String getDomain() {
+        if (domain == null) {
+            domain = getCurrentPreference().get(DOMAIN_PROPERTY, "");
+        }
+
+        return domain;
+    }
+
+    public void setDomain(String domain) {
+        this.domain = domain;
+        if (domain != null) {
+            getCurrentPreference().put(DOMAIN_PROPERTY, domain);
+        }
+    }
+
+    public String getNode() {
+        if (node == null) {
+            node = getCurrentPreference().get(NODE_PROPERTY, "");
+        }
+
+        return node;
+    }
+
+    public void setNode(String node) {
+        this.node = node;
+        if (node != null) {
+            getCurrentPreference().put(NODE_PROPERTY, node);
+        }
+    }
+
+    public String getDataMap() {
+        if (dataMap == null) {
+            dataMap = getCurrentPreference().get(DATA_MAP_PROPERTY, "");
+        }
+
+        return dataMap;
+    }
+
+    public void setDataMap(String dataMap) {
+        this.dataMap = dataMap;
+        if (dataMap != null) {
+            getCurrentPreference().put(DATA_MAP_PROPERTY, dataMap);
+        }
+    }
+
+    public String getObjEntity() {
+        if (objEntity == null) {
+            objEntity = getCurrentPreference().get(OBJ_ENTITY_PROPERTY, "");
+        }
+
+        return objEntity;
+    }
+
+    public void setObjEntity(String objEntity) {
+        this.objEntity = objEntity;
+        if (objEntity != null) {
+            getCurrentPreference().put(OBJ_ENTITY_PROPERTY, objEntity);
+        }
+    }
+
+    public String getDbEntity() {
+        if (dbEntity == null) {
+            dbEntity = getCurrentPreference().get(DB_ENTITY_PROPERTY, "");
+        }
+
+        return dbEntity;
+    }
+
+    public void setDbEntity(String dbEntity) {
+        this.dbEntity = dbEntity;
+        if (dbEntity != null) {
+            getCurrentPreference().put(DB_ENTITY_PROPERTY, dbEntity);
+        }
+    }
+
+    public String getEmbeddable() {
+        if (embeddable == null) {
+            embeddable = getCurrentPreference().get(EMBEDDABLE_PROPERTY, "");
+        }
+
+        return embeddable;
+    }
+
+    public void setEmbeddable(String embeddable) {
+        this.embeddable = embeddable;
+        if (embeddable != null) {
+            getCurrentPreference().put(EMBEDDABLE_PROPERTY, embeddable);
+        }
+    }
+
+    public String getEmbAttrs() {
+        if (embAttrs == null) {
+            embAttrs = getCurrentPreference().get(EMBEDDABLE_ATTRS_PROPERTY, "");
+        }
+
+        return embAttrs;
+    }
+
+    public void setEmbAttrs(String embAttrs) {
+        this.embAttrs = embAttrs;
+        if (embAttrs != null) {
+            getCurrentPreference().put(EMBEDDABLE_ATTRS_PROPERTY, embAttrs);
+        }
+    }
+
+    public String getObjAttrs() {
+        if (objAttrs == null) {
+            objAttrs = getCurrentPreference().get(OBJ_ATTRS_PROPERTY, "");
+        }
+
+        return objAttrs;
+    }
+
+    public void setObjAttrs(String objAttrs) {
+        this.objAttrs = objAttrs;
+        if (objAttrs != null) {
+            getCurrentPreference().put(OBJ_ATTRS_PROPERTY, objAttrs);
+        }
+    }
+
+    public String getDbAttrs() {
+        if (dbAttrs == null) {
+            dbAttrs = getCurrentPreference().get(DB_ATTRS_PROPERTY, "");
+        }
+
+        return dbAttrs;
+    }
+
+    public void setDbAttrs(String dbAttrs) {
+        this.dbAttrs = dbAttrs;
+        if (dbAttrs != null) {
+            getCurrentPreference().put(DB_ATTRS_PROPERTY, dbAttrs);
+        }
+    }
+
+    public String getObjRels() {
+        if (objRels == null) {
+            objRels = getCurrentPreference().get(OBJ_RELS_PROPERTY, "");
+        }
+
+        return objRels;
+    }
+
+    public void setObjRels(String objRels) {
+        this.objRels = objRels;
+        if (objRels != null) {
+            getCurrentPreference().put(OBJ_RELS_PROPERTY, objRels);
+        }
+    }
+
+    public String getDbRels() {
+        if (dbRels == null) {
+            dbRels = getCurrentPreference().get(DB_RELS_PROPERTY, "");
+        }
+
+        return dbRels;
+    }
+
+    public void setDbRels(String dbRels) {
+        this.dbRels = dbRels;
+        if (dbRels != null) {
+            getCurrentPreference().put(DB_RELS_PROPERTY, dbRels);
+        }
+    }
+
+    public String getProcedure() {
+        if (procedure == null) {
+            procedure = getCurrentPreference().get(PROCEDURE_PROPERTY, "");
+        }
+
+        return procedure;
+    }
+
+    public void setProcedure(String procedure) {
+        this.procedure = procedure;
+        if (procedure != null) {
+            getCurrentPreference().put(PROCEDURE_PROPERTY, procedure);
+        }
+    }
+
+    public String getProcedureParams() {
+        if (procedureParams == null) {
+            procedureParams = getCurrentPreference().get(PROCEDURE_PARAMS_PROPERTY, "");
+        }
+
+        return procedureParams;
+    }
+
+    public void setProcedureParams(String procedureParams) {
+        this.procedureParams = procedureParams;
+        if (procedureParams != null) {
+            getCurrentPreference().put(PROCEDURE_PARAMS_PROPERTY, procedureParams);
+        }
+    }
+
+    public String getQuery() {
+        if (query == null) {
+            query = getCurrentPreference().get(QUERY_PROPERTY, "");
+        }
+
+        return query;
+    }
+
+    public void setQuery(String query) {
+        this.query = query;
+        if (query != null) {
+            getCurrentPreference().put(QUERY_PROPERTY, query);
+        }
+    }
+
+    public String getMultipleObjects() {
+        if (multipleObjects == null) {
+            multipleObjects = getCurrentPreference().get(MULTIPLE_OBJECTS_PROPERTY, "");
+        }
+
+        return multipleObjects;
+    }
+
+    public void setMultipleObjects(String multipleObjects) {
+        this.multipleObjects = multipleObjects;
+        if (multipleObjects != null) {
+            getCurrentPreference().put(MULTIPLE_OBJECTS_PROPERTY, multipleObjects);
+        }
+    }
+
+    public String getParentObject() {
+        if (parentObject == null) {
+            parentObject = getCurrentPreference().get(PARENT_OBJECT_PROPERTY, "");
+        }
+
+        return parentObject;
+    }
+
+    public void setParentObject(String parentObject) {
+        this.parentObject = parentObject;
+        if (parentObject != null) {
+            getCurrentPreference().put(PARENT_OBJECT_PROPERTY, parentObject);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2888668b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectStateUtil.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectStateUtil.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectStateUtil.java
new file mode 100644
index 0000000..98158ba
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectStateUtil.java
@@ -0,0 +1,785 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util;
+
+import org.apache.cayenne.configuration.ConfigurationNode;
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.Embeddable;
+import org.apache.cayenne.map.EmbeddableAttribute;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.map.Procedure;
+import org.apache.cayenne.map.ProcedureParameter;
+import org.apache.cayenne.map.Relationship;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.AttributeDisplayEvent;
+import org.apache.cayenne.modeler.event.DataMapDisplayEvent;
+import org.apache.cayenne.modeler.event.DataNodeDisplayEvent;
+import org.apache.cayenne.modeler.event.DisplayEvent;
+import org.apache.cayenne.modeler.event.DomainDisplayEvent;
+import org.apache.cayenne.modeler.event.EmbeddableAttributeDisplayEvent;
+import org.apache.cayenne.modeler.event.EmbeddableDisplayEvent;
+import org.apache.cayenne.modeler.event.EntityDisplayEvent;
+import org.apache.cayenne.modeler.event.MultipleObjectsDisplayEvent;
+import org.apache.cayenne.modeler.event.ProcedureDisplayEvent;
+import org.apache.cayenne.modeler.event.ProcedureParameterDisplayEvent;
+import org.apache.cayenne.modeler.event.QueryDisplayEvent;
+import org.apache.cayenne.modeler.event.RelationshipDisplayEvent;
+import org.apache.cayenne.modeler.pref.ProjectStatePreferences;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.util.CayenneMapEntry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.prefs.BackingStoreException;
+
+public final class ProjectStateUtil {
+
+    private static ProjectStatePreferences preferences;
+
+    private ProjectStateUtil() {
+    }
+
+    public static void saveLastState(ProjectController controller) {
+        DisplayEvent displayEvent = controller.getLastDisplayEvent();
+        Object[] multiplyObjects = controller.getCurrentPaths();
+
+        if (displayEvent == null && multiplyObjects == null) {
+            return;
+        }
+
+        preferences = controller.getProjectStatePreferences();
+        if (preferences.getCurrentPreference() == null) {
+            return;
+        }
+
+        try {
+            preferences.getCurrentPreference().clear();
+        } catch (BackingStoreException e) {
+            // ignore exception
+        }
+
+        if (displayEvent != null) {
+            DisplayEventType.valueOf(displayEvent.getClass().getSimpleName()).saveLastDisplayEvent(controller);
+        } else {
+            DisplayEventType.MultipleObjectsDisplayEvent.saveLastDisplayEvent(controller);
+        }
+    }
+
+    public static void fireLastState(ProjectController controller) {
+        preferences = controller.getProjectStatePreferences();
+
+        String displayEventName = preferences.getEvent();
+        if (!displayEventName.isEmpty()) {
+            DisplayEventType.valueOf(displayEventName).fireLastDisplayEvent(controller);
+        }
+    }
+
+    private static enum DisplayEventType {
+
+        DomainDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DomainDisplayEvent domainDisplayEvent = new DomainDisplayEvent(this, dataChannel);
+                controller.fireDomainDisplayEvent(domainDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(DomainDisplayEvent.toString());
+                preferences.setDomain(controller.getCurrentDataChanel().getName());
+            }
+        },
+
+        DataNodeDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+                if (dataNode == null) {
+                    return;
+                }
+
+                DataNodeDisplayEvent dataNodeDisplayEvent = new DataNodeDisplayEvent(this, dataChannel, dataNode);
+                controller.fireDataNodeDisplayEvent(dataNodeDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(DataNodeDisplayEvent.toString());
+                preferences.setDomain(controller.getCurrentDataChanel().getName());
+                preferences.setNode(controller.getCurrentDataNode().getName());
+            }
+        },
+
+        DataMapDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                DataMapDisplayEvent dataMapDisplayEvent = new DataMapDisplayEvent(this, dataMap, dataChannel, dataNode);
+                controller.fireDataMapDisplayEvent(dataMapDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(DataMapDisplayEvent.toString());
+                preferences.setDomain(controller.getCurrentDataChanel().getName());
+                preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
+                preferences.setDataMap(controller.getCurrentDataMap().getName());
+            }
+        },
+
+        EntityDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                Entity entity = getLastEntity(dataMap);
+                if (entity == null) {
+                    return;
+                }
+
+                EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
+                if (entity instanceof ObjEntity) {
+                    controller.fireObjEntityDisplayEvent(entityDisplayEvent);
+                } else if (entity instanceof DbEntity) {
+                    controller.fireDbEntityDisplayEvent(entityDisplayEvent);
+                }
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                if (controller.getCurrentObjAttributes().length != 0 || controller.getCurrentDbAttributes().length != 0) {
+                    AttributeDisplayEvent.saveLastDisplayEvent(controller);
+                } else if (controller.getCurrentObjRelationships().length != 0 || controller.getCurrentDbRelationships().length != 0) {
+                    RelationshipDisplayEvent.saveLastDisplayEvent(controller);
+                } else {
+                    preferences.setEvent(EntityDisplayEvent.toString());
+                    preferences.setDomain(controller.getCurrentDataChanel().getName());
+                    preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
+                    preferences.setDataMap(controller.getCurrentDataMap().getName());
+
+                    if (controller.getCurrentObjEntity() != null) {
+                        preferences.setObjEntity(controller.getCurrentObjEntity().getName());
+                        preferences.setDbEntity(null);
+                    } else if (controller.getCurrentDbEntity() != null) {
+                        preferences.setDbEntity(controller.getCurrentDbEntity().getName());
+                        preferences.setObjEntity(null);
+                    }
+                }
+            }
+        },
+
+        AttributeDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                Entity entity = getLastEntity(dataMap);
+                if (entity == null) {
+                    return;
+                }
+
+                Attribute[] attributes = getLastEntityAttributes(entity);
+
+                EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
+                AttributeDisplayEvent attributeDisplayEvent = new AttributeDisplayEvent(this, attributes, entity, dataMap, dataChannel);
+
+                if (entity instanceof ObjEntity) {
+                    controller.fireObjEntityDisplayEvent(entityDisplayEvent);
+                    controller.fireObjAttributeDisplayEvent(attributeDisplayEvent);
+                } else if (entity instanceof DbEntity) {
+                    controller.fireDbEntityDisplayEvent(entityDisplayEvent);
+                    controller.fireDbAttributeDisplayEvent(attributeDisplayEvent);
+                }
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(AttributeDisplayEvent.toString());
+                preferences.setDomain(controller.getCurrentDataChanel().getName());
+                preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
+                preferences.setDataMap(controller.getCurrentDataMap().getName());
+
+                if (controller.getCurrentObjEntity() != null) {
+                    preferences.setObjEntity(controller.getCurrentObjEntity().getName());
+                    preferences.setObjAttrs(parseToString(controller.getCurrentObjAttributes()));
+                    preferences.setDbEntity(null);
+                } else if (controller.getCurrentDbEntity() != null) {
+                    preferences.setDbEntity(controller.getCurrentDbEntity().getName());
+                    preferences.setDbAttrs(parseToString(controller.getCurrentDbAttributes()));
+                    preferences.setObjEntity(null);
+                }
+            }
+        },
+
+        RelationshipDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                Entity entity = getLastEntity(dataMap);
+                if (entity == null) {
+                    return;
+                }
+
+                Relationship[] relationships = getLastEntityRelationships(entity);
+
+                EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
+                RelationshipDisplayEvent displayEvent = new RelationshipDisplayEvent(this, relationships, entity, dataMap, dataChannel);
+
+                if (entity instanceof ObjEntity) {
+                    controller.fireObjEntityDisplayEvent(entityDisplayEvent);
+                    controller.fireObjRelationshipDisplayEvent(displayEvent);
+                } else if (entity instanceof DbEntity) {
+                    controller.fireDbEntityDisplayEvent(entityDisplayEvent);
+                    controller.fireDbRelationshipDisplayEvent(displayEvent);
+                }
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(RelationshipDisplayEvent.toString());
+                preferences.setDomain(controller.getCurrentDataChanel().getName());
+                preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
+                preferences.setDataMap(controller.getCurrentDataMap().getName());
+
+                if (controller.getCurrentObjEntity() != null) {
+                    preferences.setObjEntity(controller.getCurrentObjEntity().getName());
+                    preferences.setObjRels(parseToString(controller.getCurrentObjRelationships()));
+                    preferences.setDbEntity(null);
+                } else if (controller.getCurrentDbEntity() != null) {
+                    preferences.setDbEntity(controller.getCurrentDbEntity().getName());
+                    preferences.setDbRels(parseToString(controller.getCurrentDbRelationships()));
+                    preferences.setObjEntity(null);
+                }
+            }
+        },
+
+        EmbeddableDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                Embeddable embeddable = dataMap.getEmbeddable(preferences.getEmbeddable());
+                if (embeddable == null) {
+                    return;
+                }
+
+                EmbeddableDisplayEvent embeddableDisplayEvent = new EmbeddableDisplayEvent(this, embeddable, dataMap, dataChannel);
+                controller.fireEmbeddableDisplayEvent(embeddableDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                if (controller.getCurrentEmbAttributes().length != 0) {
+                    EmbeddableAttributeDisplayEvent.saveLastDisplayEvent(controller);
+                } else {
+                    preferences.setEvent(EmbeddableDisplayEvent.toString());
+                    preferences.setDomain(controller.getCurrentDataChanel().getName());
+                    preferences.setDataMap(controller.getCurrentDataMap().getName());
+                    preferences.setEmbeddable(controller.getCurrentEmbeddable().getClassName());
+                }
+            }
+        },
+
+        EmbeddableAttributeDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                Embeddable embeddable = dataMap.getEmbeddable(preferences.getEmbeddable());
+                if (embeddable == null) {
+                    return;
+                }
+
+                EmbeddableDisplayEvent embeddableDisplayEvent = new EmbeddableDisplayEvent(this, embeddable, dataMap, dataChannel);
+                controller.fireEmbeddableDisplayEvent(embeddableDisplayEvent);
+
+                EmbeddableAttribute[] embeddableAttributes = getLastEmbeddableAttributes(embeddable);
+                EmbeddableAttributeDisplayEvent attributeDisplayEvent = new EmbeddableAttributeDisplayEvent(this, embeddable, embeddableAttributes, dataMap, dataChannel);
+                controller.fireEmbeddableAttributeDisplayEvent(attributeDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(EmbeddableAttributeDisplayEvent.toString());
+                preferences.setDomain(controller.getCurrentDataChanel().getName());
+                preferences.setDataMap(controller.getCurrentDataMap().getName());
+                preferences.setEmbeddable(controller.getCurrentEmbeddable().getClassName());
+
+                EmbeddableAttribute[] currentEmbAttributes = controller.getCurrentEmbAttributes();
+                if (currentEmbAttributes == null) {
+                    preferences.setEmbAttrs("");
+                } else {
+                    StringBuilder sb = new StringBuilder();
+                    for (EmbeddableAttribute embeddableAttribute : currentEmbAttributes) {
+                        sb.append(embeddableAttribute.getName()).append(",");
+                    }
+                    preferences.setEmbAttrs(sb.toString());
+                }
+            }
+        },
+
+        ProcedureDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                Procedure procedure = dataMap.getProcedure(preferences.getProcedure());
+                if (procedure == null) {
+                    return;
+                }
+
+                ProcedureDisplayEvent procedureDisplayEvent = new ProcedureDisplayEvent(this, procedure, dataMap, dataChannel);
+                controller.fireProcedureDisplayEvent(procedureDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                if (controller.getCurrentProcedureParameters().length != 0) {
+                    ProcedureParameterDisplayEvent.saveLastDisplayEvent(controller);
+                } else {
+                    preferences.setEvent(ProcedureDisplayEvent.toString());
+                    preferences.setDomain(controller.getCurrentDataChanel().getName());
+                    preferences.setDataMap(controller.getCurrentDataMap().getName());
+                    preferences.setProcedure(controller.getCurrentProcedure().getName());
+                }
+            }
+        },
+
+        ProcedureParameterDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                Procedure procedure = dataMap.getProcedure(preferences.getProcedure());
+                if (procedure == null) {
+                    return;
+                }
+
+                ProcedureDisplayEvent procedureDisplayEvent = new ProcedureDisplayEvent(this, procedure, dataMap, dataChannel);
+                controller.fireProcedureDisplayEvent(procedureDisplayEvent);
+
+                ProcedureParameter[] procedureParameters = getLastProcedureParameters(procedure);
+                ProcedureParameterDisplayEvent procedureParameterDisplayEvent =
+                        new ProcedureParameterDisplayEvent(this, procedureParameters, procedure, dataMap, dataChannel);
+                controller.fireProcedureParameterDisplayEvent(procedureParameterDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(ProcedureParameterDisplayEvent.toString());
+                preferences.setDomain(controller.getCurrentDataChanel().getName());
+                preferences.setDataMap(controller.getCurrentDataMap().getName());
+                preferences.setProcedure(controller.getCurrentProcedure().getName());
+                preferences.setProcedureParams(parseToString(controller.getCurrentProcedureParameters()));
+            }
+        },
+
+        QueryDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+                if (!dataChannel.getName().equals(preferences.getDomain())) {
+                    return;
+                }
+
+                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+                if (dataMap == null) {
+                    return;
+                }
+
+                Query query = dataMap.getQuery(preferences.getQuery());
+                if (query == null) {
+                    return;
+                }
+
+                QueryDisplayEvent queryDisplayEvent = new QueryDisplayEvent(this, query, dataMap, dataChannel);
+                controller.fireQueryDisplayEvent(queryDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(QueryDisplayEvent.toString());
+                preferences.setDomain(controller.getCurrentDataChanel().getName());
+                preferences.setDataMap(controller.getCurrentDataMap().getName());
+                preferences.setQuery(controller.getCurrentQuery().getName());
+            }
+        },
+
+        MultipleObjectsDisplayEvent {
+            @Override
+            void fireLastDisplayEvent(ProjectController controller) {
+                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+
+                String parentObjectName = preferences.getParentObject();
+                ConfigurationNode parentObject;
+                ConfigurationNode[] multipleObjects;
+
+                if (dataChannel.getDataMap(parentObjectName) != null) {
+                    DataMap dataMap = dataChannel.getDataMap(parentObjectName);
+                    parentObject = dataMap;
+                    multipleObjects = getLastMultipleObjects(dataMap);
+                } else if (dataChannel.getNodeDescriptor(parentObjectName) != null) {
+                    DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(parentObjectName);
+                    parentObject = dataNode;
+                    multipleObjects = getLastMultipleObjects(dataNode);
+                } else {
+                    parentObject = dataChannel;
+                    multipleObjects = getLastMultipleObjects(dataChannel);
+                }
+
+                MultipleObjectsDisplayEvent multipleDisplayEvent = new MultipleObjectsDisplayEvent(this, multipleObjects, parentObject);
+                controller.fireMultipleObjectsDisplayEvent(multipleDisplayEvent);
+            }
+
+            @Override
+            void saveLastDisplayEvent(ProjectController controller) {
+                preferences.setEvent(MultipleObjectsDisplayEvent.toString());
+                preferences.setParentObject(getObjectName(controller.getCurrentParentPath()));
+
+                Object[] multipleObjects = controller.getCurrentPaths();
+                if (multipleObjects == null) {
+                    preferences.setMultipleObjects("");
+                } else {
+                    StringBuilder sb = new StringBuilder();
+                    for (Object object : multipleObjects) {
+                        String objectName = getObjectName(object);
+                        if (!objectName.isEmpty()) {
+                            sb.append(objectName).append(",");
+                        }
+                    }
+                    preferences.setMultipleObjects(sb.toString());
+                }
+            }
+        };
+
+        abstract void fireLastDisplayEvent(ProjectController controller);
+
+        abstract void saveLastDisplayEvent(ProjectController controller);
+    }
+
+    private static Entity getLastEntity(DataMap dataMap) {
+        return !preferences.getObjEntity().isEmpty()
+                ? dataMap.getObjEntity(preferences.getObjEntity())
+                : dataMap.getDbEntity(preferences.getDbEntity());
+    }
+
+    private static Attribute[] getLastEntityAttributes(Entity entity) {
+        return (entity instanceof ObjEntity)
+                ? getLastObjEntityAttributes((ObjEntity) entity)
+                : getLastDbEntityAttributes((DbEntity) entity);
+    }
+
+    private static Relationship[] getLastEntityRelationships(Entity entity) {
+        return (entity instanceof ObjEntity)
+                ? getLastObjEntityRelationships((ObjEntity) entity)
+                : getLastDbEntityRelationships((DbEntity) entity);
+    }
+
+    private static ObjAttribute[] getLastObjEntityAttributes(ObjEntity objEntity) {
+        List<ObjAttribute> attributeList = new ArrayList<ObjAttribute>();
+        ObjAttribute[] attributes = new ObjAttribute[0];
+
+        String objAttrs = preferences.getObjAttrs();
+        if (!objAttrs.isEmpty()) {
+            String[] lastObjAttrs = objAttrs.split(",");
+            for (String objAttrName : lastObjAttrs) {
+                attributeList.add(objEntity.getAttribute(objAttrName));
+            }
+        }
+
+        return attributeList.toArray(attributes);
+    }
+
+    private static DbAttribute[] getLastDbEntityAttributes(DbEntity dbEntity) {
+        List<DbAttribute> attributeList = new ArrayList<DbAttribute>();
+        DbAttribute[] attributes = new DbAttribute[0];
+
+        String dbAttrs = preferences.getDbAttrs();
+        if (!dbAttrs.isEmpty()) {
+            String[] lastDbAttrs = dbAttrs.split(",");
+            for (String dbAttrName : lastDbAttrs) {
+                attributeList.add(dbEntity.getAttribute(dbAttrName));
+            }
+        }
+
+        return attributeList.toArray(attributes);
+    }
+
+    private static ObjRelationship[] getLastObjEntityRelationships(ObjEntity objEntity) {
+        List<ObjRelationship> relationshipList = new ArrayList<ObjRelationship>();
+        ObjRelationship[] relationships = new ObjRelationship[0];
+
+        String objRels = preferences.getObjRels();
+        if (!objRels.isEmpty()) {
+            String[] lastObjRels = objRels.split(",");
+            for (String objRelName : lastObjRels) {
+                relationshipList.add(objEntity.getRelationship(objRelName));
+            }
+        }
+
+        return relationshipList.toArray(relationships);
+    }
+
+    private static DbRelationship[] getLastDbEntityRelationships(DbEntity dbEntity) {
+        List<DbRelationship> relationshipList = new ArrayList<DbRelationship>();
+        DbRelationship[] relationships = new DbRelationship[0];
+
+        String dbRels = preferences.getDbRels();
+        if (!dbRels.isEmpty()) {
+            String[] lastDbRels = dbRels.split(",");
+            for (String dbRelName : lastDbRels) {
+                relationshipList.add(dbEntity.getRelationship(dbRelName));
+            }
+        }
+
+        return relationshipList.toArray(relationships);
+    }
+
+    private static EmbeddableAttribute[] getLastEmbeddableAttributes(Embeddable embeddable) {
+        List<EmbeddableAttribute> embeddableAttributeList = new ArrayList<EmbeddableAttribute>();
+        EmbeddableAttribute[] attributes = new EmbeddableAttribute[0];
+
+        String embAttrs = preferences.getEmbAttrs();
+        if (!embAttrs.isEmpty()) {
+            String[] lastEmbAttrs = embAttrs.split(",");
+            for (String embAttrName : lastEmbAttrs) {
+                embeddableAttributeList.add(embeddable.getAttribute(embAttrName));
+            }
+        }
+
+        return embeddableAttributeList.toArray(attributes);
+    }
+
+    private static ProcedureParameter[] getLastProcedureParameters(Procedure procedure) {
+        List<ProcedureParameter> procedureParameterList = new ArrayList<ProcedureParameter>();
+        ProcedureParameter[] parameters = new ProcedureParameter[0];
+
+        String procedureParams = preferences.getProcedureParams();
+        if (!procedureParams.isEmpty()) {
+            String[] lastProcedureParams = procedureParams.split(",");
+            for (String procedureParamName : lastProcedureParams) {
+                for (ProcedureParameter procedureParameter : procedure.getCallParameters()) {
+                    if (procedureParameter.getName().equals(procedureParamName)) {
+                        procedureParameterList.add(procedureParameter);
+                    }
+                }
+            }
+        }
+
+        return procedureParameterList.toArray(parameters);
+    }
+
+    private static ConfigurationNode[] getLastMultipleObjects(DataChannelDescriptor dataChannel) {
+        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
+        ConfigurationNode[] nodes = new ConfigurationNode[0];
+
+        String multipleObjects = preferences.getMultipleObjects();
+        if (!multipleObjects.isEmpty()) {
+            String[] lastMultipleObjects = multipleObjects.split(",");
+
+            outer:
+            for (String objectName : lastMultipleObjects) {
+                if (dataChannel.getName().equals(objectName)) {
+                    configurationNodeList.add(dataChannel);
+                    continue outer;
+                }
+
+                for (DataNodeDescriptor dataNode : dataChannel.getNodeDescriptors()) {
+                    if (dataNode.getName().equals(objectName)) {
+                        configurationNodeList.add(dataNode);
+                        continue outer;
+                    }
+                }
+
+                for (DataMap dataMap : dataChannel.getDataMaps()) {
+                    if (dataMap.getName().equals(objectName)) {
+                        configurationNodeList.add(dataMap);
+                        continue outer;
+                    }
+                }
+            }
+        }
+
+        return configurationNodeList.toArray(nodes);
+    }
+
+    private static ConfigurationNode[] getLastMultipleObjects(DataNodeDescriptor dataNode) {
+        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
+        ConfigurationNode[] nodes = new ConfigurationNode[0];
+
+        String multipleObjects = preferences.getMultipleObjects();
+        if (!multipleObjects.isEmpty()) {
+            String[] lastMultipleObjects = multipleObjects.split(",");
+            for (String objectName : lastMultipleObjects) {
+                if (dataNode.getDataMapNames().contains(objectName)) {
+                    configurationNodeList.add(dataNode.getDataChannelDescriptor().getDataMap(objectName));
+                }
+            }
+        }
+
+        return configurationNodeList.toArray(nodes);
+    }
+
+    private static ConfigurationNode[] getLastMultipleObjects(DataMap dataMap) {
+        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
+        ConfigurationNode[] nodes = new ConfigurationNode[0];
+
+        String multipleObjects = preferences.getMultipleObjects();
+        if (!multipleObjects.isEmpty()) {
+            String[] lastMultipleObjects = multipleObjects.split(",");
+            for (String objectName : lastMultipleObjects) {
+                if (dataMap.getObjEntity(objectName) != null) {
+                    configurationNodeList.add(dataMap.getObjEntity(objectName));
+                } else if (dataMap.getDbEntity(objectName) != null) {
+                    configurationNodeList.add(dataMap.getDbEntity(objectName));
+                } else if (dataMap.getEmbeddable(objectName) != null) {
+                    configurationNodeList.add(dataMap.getEmbeddable(objectName));
+                } else if (dataMap.getProcedure(objectName) != null) {
+                    configurationNodeList.add(dataMap.getProcedure(objectName));
+                } else if (dataMap.getQuery(objectName) != null) {
+                    configurationNodeList.add(dataMap.getQuery(objectName));
+                }
+            }
+        }
+
+        return configurationNodeList.toArray(nodes);
+    }
+
+    private static String getObjectName(Object object) {
+        if (object instanceof CayenneMapEntry) {
+            return ((CayenneMapEntry) object).getName();
+        } else if (object instanceof DataChannelDescriptor) {
+            return ((DataChannelDescriptor) object).getName();
+        } else if (object instanceof DataNodeDescriptor) {
+            return ((DataNodeDescriptor) object).getName();
+        } else if (object instanceof DataMap) {
+            return ((DataMap) object).getName();
+        } else if (object instanceof Embeddable) {
+            return ((Embeddable) object).getClassName();
+        } else if (object instanceof Query) {
+            return ((Query) object).getName();
+        } else {
+            return "";
+        }
+    }
+
+    private static String parseToString(CayenneMapEntry[] array) {
+        if (array == null) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (CayenneMapEntry entry : array) {
+            sb.append(entry.getName()).append(",");
+        }
+
+        return sb.toString();
+    }
+
+}


[2/3] cayenne git commit: CAY-2001 | Saving a display state of Project

Posted by sk...@apache.org.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProcedureDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProcedureDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProcedureDisplayEventType.java
new file mode 100644
index 0000000..7bf2014
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProcedureDisplayEventType.java
@@ -0,0 +1,63 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Procedure;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.ProcedureDisplayEvent;
+
+class ProcedureDisplayEventType extends DisplayEventType {
+
+    public ProcedureDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        Procedure procedure = dataMap.getProcedure(preferences.getProcedure());
+        if (procedure == null) {
+            return;
+        }
+
+        ProcedureDisplayEvent procedureDisplayEvent = new ProcedureDisplayEvent(this, procedure, dataMap, dataChannel);
+        controller.fireProcedureDisplayEvent(procedureDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(ProcedureDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+        preferences.setProcedure(controller.getCurrentProcedure().getName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProcedureParameterDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProcedureParameterDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProcedureParameterDisplayEventType.java
new file mode 100644
index 0000000..244508f
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProcedureParameterDisplayEventType.java
@@ -0,0 +1,93 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Procedure;
+import org.apache.cayenne.map.ProcedureParameter;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.ProcedureDisplayEvent;
+import org.apache.cayenne.modeler.event.ProcedureParameterDisplayEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class ProcedureParameterDisplayEventType extends ProcedureDisplayEventType {
+
+    public ProcedureParameterDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        Procedure procedure = dataMap.getProcedure(preferences.getProcedure());
+        if (procedure == null) {
+            return;
+        }
+
+        ProcedureDisplayEvent procedureDisplayEvent = new ProcedureDisplayEvent(this, procedure, dataMap, dataChannel);
+        controller.fireProcedureDisplayEvent(procedureDisplayEvent);
+
+        ProcedureParameter[] procedureParameters = getLastProcedureParameters(procedure);
+        ProcedureParameterDisplayEvent procedureParameterDisplayEvent =
+                new ProcedureParameterDisplayEvent(this, procedureParameters, procedure, dataMap, dataChannel);
+        controller.fireProcedureParameterDisplayEvent(procedureParameterDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(ProcedureParameterDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+        preferences.setProcedure(controller.getCurrentProcedure().getName());
+        preferences.setProcedureParams(parseToString(controller.getCurrentProcedureParameters()));
+    }
+
+    protected ProcedureParameter[] getLastProcedureParameters(Procedure procedure) {
+        List<ProcedureParameter> procedureParameterList = new ArrayList<ProcedureParameter>();
+        ProcedureParameter[] parameters = new ProcedureParameter[0];
+
+        String procedureParams = preferences.getProcedureParams();
+        if (procedureParams.isEmpty()) {
+            return procedureParameterList.toArray(parameters);
+        }
+
+        for (String procedureParamName : procedureParams.split(",")) {
+            for (ProcedureParameter procedureParameter : procedure.getCallParameters()) {
+                if (procedureParameter.getName().equals(procedureParamName)) {
+                    procedureParameterList.add(procedureParameter);
+                }
+            }
+        }
+
+        return procedureParameterList.toArray(parameters);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProjectStateUtil.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProjectStateUtil.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProjectStateUtil.java
new file mode 100644
index 0000000..c077863
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/ProjectStateUtil.java
@@ -0,0 +1,72 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.pref.ProjectStatePreferences;
+
+import java.util.EventObject;
+import java.util.prefs.BackingStoreException;
+
+public final class ProjectStateUtil {
+
+    public ProjectStateUtil() {
+    }
+
+    public void saveLastState(ProjectController controller) {
+        EventObject displayEvent = controller.getLastDisplayEvent();
+        Object[] multiplyObjects = controller.getCurrentPaths();
+
+        if (displayEvent == null && multiplyObjects == null) {
+            return;
+        }
+
+        ProjectStatePreferences preferences = controller.getProjectStatePreferences();
+        if (preferences.getCurrentPreference() == null) {
+            return;
+        }
+
+        try {
+            preferences.getCurrentPreference().clear();
+        } catch (BackingStoreException e) {
+            // ignore exception
+        }
+
+        if (displayEvent != null) {
+            DisplayEventTypes.valueOf(displayEvent.getClass().getSimpleName())
+                    .createDisplayEventType(controller)
+                    .saveLastDisplayEvent();
+        } else if (multiplyObjects.length != 0) {
+            new MultipleObjectsDisplayEventType(controller).saveLastDisplayEvent();
+        }
+    }
+
+    public void fireLastState(ProjectController controller) {
+        ProjectStatePreferences preferences = controller.getProjectStatePreferences();
+
+        String displayEventName = preferences.getEvent();
+        if (!displayEventName.isEmpty()) {
+            DisplayEventTypes.valueOf(displayEventName)
+                    .createDisplayEventType(controller)
+                    .fireLastDisplayEvent();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/QueryDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/QueryDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/QueryDisplayEventType.java
new file mode 100644
index 0000000..e9b5817
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/QueryDisplayEventType.java
@@ -0,0 +1,62 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.QueryDisplayEvent;
+import org.apache.cayenne.query.Query;
+
+class QueryDisplayEventType extends DisplayEventType {
+
+    public QueryDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        Query query = dataMap.getQuery(preferences.getQuery());
+        if (query == null) {
+            return;
+        }
+
+        QueryDisplayEvent queryDisplayEvent = new QueryDisplayEvent(this, query, dataMap, dataChannel);
+        controller.fireQueryDisplayEvent(queryDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(QueryDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+        preferences.setQuery(controller.getCurrentQuery().getName());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/RelationshipDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/RelationshipDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/RelationshipDisplayEventType.java
new file mode 100644
index 0000000..854fe3a
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/RelationshipDisplayEventType.java
@@ -0,0 +1,107 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.Relationship;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.EntityDisplayEvent;
+import org.apache.cayenne.modeler.event.RelationshipDisplayEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class RelationshipDisplayEventType extends EntityDisplayEventType {
+
+    public RelationshipDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        Entity entity = getLastEntity(dataMap);
+        if (entity == null) {
+            return;
+        }
+
+        Relationship[] relationships = getLastEntityRelationships(entity);
+
+        EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
+        RelationshipDisplayEvent displayEvent = new RelationshipDisplayEvent(this, relationships, entity, dataMap, dataChannel);
+
+        if (entity instanceof ObjEntity) {
+            controller.fireObjEntityDisplayEvent(entityDisplayEvent);
+            controller.fireObjRelationshipDisplayEvent(displayEvent);
+        } else if (entity instanceof DbEntity) {
+            controller.fireDbEntityDisplayEvent(entityDisplayEvent);
+            controller.fireDbRelationshipDisplayEvent(displayEvent);
+        }
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(RelationshipDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+
+        if (controller.getCurrentObjEntity() != null) {
+            preferences.setObjEntity(controller.getCurrentObjEntity().getName());
+            preferences.setObjRels(parseToString(controller.getCurrentObjRelationships()));
+            preferences.setDbEntity(null);
+        } else if (controller.getCurrentDbEntity() != null) {
+            preferences.setDbEntity(controller.getCurrentDbEntity().getName());
+            preferences.setDbRels(parseToString(controller.getCurrentDbRelationships()));
+            preferences.setObjEntity(null);
+        }
+    }
+
+    protected Relationship[] getLastEntityRelationships(Entity entity) {
+        List<Relationship> relationshipList = new ArrayList<Relationship>();
+        Relationship[] relationships = new Relationship[0];
+
+        String rels = (entity instanceof ObjEntity)
+                ? preferences.getObjRels()
+                : preferences.getDbRels();
+
+        for (String objRelName : rels.split(",")) {
+            relationshipList.add(entity.getRelationship(objRelName));
+        }
+
+        return relationshipList.toArray(relationships);
+    }
+
+}


[3/3] cayenne git commit: CAY-2001 | Saving a display state of Project

Posted by sk...@apache.org.
CAY-2001 | Saving a display state of Project


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/1f514c4b
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/1f514c4b
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/1f514c4b

Branch: refs/heads/master
Commit: 1f514c4b151cc66673d1445cf88844473bce4942
Parents: 2888668
Author: Savva Kolbachev <s....@gmail.com>
Authored: Fri Apr 17 14:14:38 2015 +0300
Committer: Savva Kolbachev <s....@gmail.com>
Committed: Fri Apr 17 14:21:32 2015 +0300

----------------------------------------------------------------------
 .../modeler/CayenneModelerController.java       |  10 +-
 .../cayenne/modeler/util/ProjectStateUtil.java  | 785 -------------------
 .../util/state/AttributeDisplayEventType.java   | 107 +++
 .../util/state/DataMapDisplayEventType.java     |  58 ++
 .../util/state/DataNodeDisplayEventType.java    |  55 ++
 .../modeler/util/state/DisplayEventType.java    |  76 ++
 .../modeler/util/state/DisplayEventTypes.java   | 198 +++++
 .../util/state/DomainDisplayEventType.java      |  49 ++
 .../EmbeddableAttributeDisplayEventType.java    |  98 +++
 .../util/state/EmbeddableDisplayEventType.java  |  62 ++
 .../util/state/EntityDisplayEventType.java      |  84 ++
 .../state/MultipleObjectsDisplayEventType.java  | 166 ++++
 .../util/state/ProcedureDisplayEventType.java   |  63 ++
 .../ProcedureParameterDisplayEventType.java     |  93 +++
 .../modeler/util/state/ProjectStateUtil.java    |  72 ++
 .../util/state/QueryDisplayEventType.java       |  62 ++
 .../state/RelationshipDisplayEventType.java     | 107 +++
 17 files changed, 1356 insertions(+), 789 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java
index 9f32197..ac77093 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/CayenneModelerController.java
@@ -28,7 +28,7 @@ import org.apache.cayenne.modeler.pref.ComponentGeometry;
 import org.apache.cayenne.modeler.pref.FSPath;
 import org.apache.cayenne.modeler.util.CayenneController;
 import org.apache.cayenne.modeler.util.FileFilters;
-import org.apache.cayenne.modeler.util.ProjectStateUtil;
+import org.apache.cayenne.modeler.util.state.ProjectStateUtil;
 import org.apache.cayenne.project.Project;
 import org.apache.cayenne.project.validation.ProjectValidator;
 import org.apache.cayenne.validation.ValidationFailure;
@@ -57,6 +57,8 @@ import java.util.prefs.Preferences;
  */
 public class CayenneModelerController extends CayenneController {
 
+    private static final ProjectStateUtil PROJECT_STATE_UTIL = new ProjectStateUtil();
+
     protected ProjectController projectController;
 
     protected CayenneModelerFrame frame;
@@ -107,7 +109,7 @@ public class CayenneModelerController extends CayenneController {
         frame.addWindowListener(new WindowAdapter() {
 
             public void windowClosing(WindowEvent e) {
-                ProjectStateUtil.saveLastState(projectController);
+                PROJECT_STATE_UTIL.saveLastState(projectController);
                 getApplication().getActionManager().getAction(ExitAction.class).exit();
             }
         });
@@ -190,7 +192,7 @@ public class CayenneModelerController extends CayenneController {
      * Action method invoked on project closing.
      */
     public void projectClosedAction() {
-        ProjectStateUtil.saveLastState(projectController);
+        PROJECT_STATE_UTIL.saveLastState(projectController);
 
         // --- update view
         frame.setView(null);
@@ -241,7 +243,7 @@ public class CayenneModelerController extends CayenneController {
             frame.fireRecentFileListChanged();
         }
 
-        ProjectStateUtil.fireLastState(projectController);
+        PROJECT_STATE_UTIL.fireLastState(projectController);
 
         // for validation purposes combine load failures with post-load validation (not
         // sure if that'll cause duplicate messages?).

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectStateUtil.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectStateUtil.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectStateUtil.java
deleted file mode 100644
index 98158ba..0000000
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectStateUtil.java
+++ /dev/null
@@ -1,785 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.modeler.util;
-
-import org.apache.cayenne.configuration.ConfigurationNode;
-import org.apache.cayenne.configuration.DataChannelDescriptor;
-import org.apache.cayenne.configuration.DataNodeDescriptor;
-import org.apache.cayenne.map.Attribute;
-import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.Embeddable;
-import org.apache.cayenne.map.EmbeddableAttribute;
-import org.apache.cayenne.map.Entity;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.map.Procedure;
-import org.apache.cayenne.map.ProcedureParameter;
-import org.apache.cayenne.map.Relationship;
-import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.modeler.event.AttributeDisplayEvent;
-import org.apache.cayenne.modeler.event.DataMapDisplayEvent;
-import org.apache.cayenne.modeler.event.DataNodeDisplayEvent;
-import org.apache.cayenne.modeler.event.DisplayEvent;
-import org.apache.cayenne.modeler.event.DomainDisplayEvent;
-import org.apache.cayenne.modeler.event.EmbeddableAttributeDisplayEvent;
-import org.apache.cayenne.modeler.event.EmbeddableDisplayEvent;
-import org.apache.cayenne.modeler.event.EntityDisplayEvent;
-import org.apache.cayenne.modeler.event.MultipleObjectsDisplayEvent;
-import org.apache.cayenne.modeler.event.ProcedureDisplayEvent;
-import org.apache.cayenne.modeler.event.ProcedureParameterDisplayEvent;
-import org.apache.cayenne.modeler.event.QueryDisplayEvent;
-import org.apache.cayenne.modeler.event.RelationshipDisplayEvent;
-import org.apache.cayenne.modeler.pref.ProjectStatePreferences;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.util.CayenneMapEntry;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.prefs.BackingStoreException;
-
-public final class ProjectStateUtil {
-
-    private static ProjectStatePreferences preferences;
-
-    private ProjectStateUtil() {
-    }
-
-    public static void saveLastState(ProjectController controller) {
-        DisplayEvent displayEvent = controller.getLastDisplayEvent();
-        Object[] multiplyObjects = controller.getCurrentPaths();
-
-        if (displayEvent == null && multiplyObjects == null) {
-            return;
-        }
-
-        preferences = controller.getProjectStatePreferences();
-        if (preferences.getCurrentPreference() == null) {
-            return;
-        }
-
-        try {
-            preferences.getCurrentPreference().clear();
-        } catch (BackingStoreException e) {
-            // ignore exception
-        }
-
-        if (displayEvent != null) {
-            DisplayEventType.valueOf(displayEvent.getClass().getSimpleName()).saveLastDisplayEvent(controller);
-        } else {
-            DisplayEventType.MultipleObjectsDisplayEvent.saveLastDisplayEvent(controller);
-        }
-    }
-
-    public static void fireLastState(ProjectController controller) {
-        preferences = controller.getProjectStatePreferences();
-
-        String displayEventName = preferences.getEvent();
-        if (!displayEventName.isEmpty()) {
-            DisplayEventType.valueOf(displayEventName).fireLastDisplayEvent(controller);
-        }
-    }
-
-    private static enum DisplayEventType {
-
-        DomainDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DomainDisplayEvent domainDisplayEvent = new DomainDisplayEvent(this, dataChannel);
-                controller.fireDomainDisplayEvent(domainDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(DomainDisplayEvent.toString());
-                preferences.setDomain(controller.getCurrentDataChanel().getName());
-            }
-        },
-
-        DataNodeDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
-                if (dataNode == null) {
-                    return;
-                }
-
-                DataNodeDisplayEvent dataNodeDisplayEvent = new DataNodeDisplayEvent(this, dataChannel, dataNode);
-                controller.fireDataNodeDisplayEvent(dataNodeDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(DataNodeDisplayEvent.toString());
-                preferences.setDomain(controller.getCurrentDataChanel().getName());
-                preferences.setNode(controller.getCurrentDataNode().getName());
-            }
-        },
-
-        DataMapDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                DataMapDisplayEvent dataMapDisplayEvent = new DataMapDisplayEvent(this, dataMap, dataChannel, dataNode);
-                controller.fireDataMapDisplayEvent(dataMapDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(DataMapDisplayEvent.toString());
-                preferences.setDomain(controller.getCurrentDataChanel().getName());
-                preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
-                preferences.setDataMap(controller.getCurrentDataMap().getName());
-            }
-        },
-
-        EntityDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                Entity entity = getLastEntity(dataMap);
-                if (entity == null) {
-                    return;
-                }
-
-                EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
-                if (entity instanceof ObjEntity) {
-                    controller.fireObjEntityDisplayEvent(entityDisplayEvent);
-                } else if (entity instanceof DbEntity) {
-                    controller.fireDbEntityDisplayEvent(entityDisplayEvent);
-                }
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                if (controller.getCurrentObjAttributes().length != 0 || controller.getCurrentDbAttributes().length != 0) {
-                    AttributeDisplayEvent.saveLastDisplayEvent(controller);
-                } else if (controller.getCurrentObjRelationships().length != 0 || controller.getCurrentDbRelationships().length != 0) {
-                    RelationshipDisplayEvent.saveLastDisplayEvent(controller);
-                } else {
-                    preferences.setEvent(EntityDisplayEvent.toString());
-                    preferences.setDomain(controller.getCurrentDataChanel().getName());
-                    preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
-                    preferences.setDataMap(controller.getCurrentDataMap().getName());
-
-                    if (controller.getCurrentObjEntity() != null) {
-                        preferences.setObjEntity(controller.getCurrentObjEntity().getName());
-                        preferences.setDbEntity(null);
-                    } else if (controller.getCurrentDbEntity() != null) {
-                        preferences.setDbEntity(controller.getCurrentDbEntity().getName());
-                        preferences.setObjEntity(null);
-                    }
-                }
-            }
-        },
-
-        AttributeDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                Entity entity = getLastEntity(dataMap);
-                if (entity == null) {
-                    return;
-                }
-
-                Attribute[] attributes = getLastEntityAttributes(entity);
-
-                EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
-                AttributeDisplayEvent attributeDisplayEvent = new AttributeDisplayEvent(this, attributes, entity, dataMap, dataChannel);
-
-                if (entity instanceof ObjEntity) {
-                    controller.fireObjEntityDisplayEvent(entityDisplayEvent);
-                    controller.fireObjAttributeDisplayEvent(attributeDisplayEvent);
-                } else if (entity instanceof DbEntity) {
-                    controller.fireDbEntityDisplayEvent(entityDisplayEvent);
-                    controller.fireDbAttributeDisplayEvent(attributeDisplayEvent);
-                }
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(AttributeDisplayEvent.toString());
-                preferences.setDomain(controller.getCurrentDataChanel().getName());
-                preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
-                preferences.setDataMap(controller.getCurrentDataMap().getName());
-
-                if (controller.getCurrentObjEntity() != null) {
-                    preferences.setObjEntity(controller.getCurrentObjEntity().getName());
-                    preferences.setObjAttrs(parseToString(controller.getCurrentObjAttributes()));
-                    preferences.setDbEntity(null);
-                } else if (controller.getCurrentDbEntity() != null) {
-                    preferences.setDbEntity(controller.getCurrentDbEntity().getName());
-                    preferences.setDbAttrs(parseToString(controller.getCurrentDbAttributes()));
-                    preferences.setObjEntity(null);
-                }
-            }
-        },
-
-        RelationshipDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                Entity entity = getLastEntity(dataMap);
-                if (entity == null) {
-                    return;
-                }
-
-                Relationship[] relationships = getLastEntityRelationships(entity);
-
-                EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
-                RelationshipDisplayEvent displayEvent = new RelationshipDisplayEvent(this, relationships, entity, dataMap, dataChannel);
-
-                if (entity instanceof ObjEntity) {
-                    controller.fireObjEntityDisplayEvent(entityDisplayEvent);
-                    controller.fireObjRelationshipDisplayEvent(displayEvent);
-                } else if (entity instanceof DbEntity) {
-                    controller.fireDbEntityDisplayEvent(entityDisplayEvent);
-                    controller.fireDbRelationshipDisplayEvent(displayEvent);
-                }
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(RelationshipDisplayEvent.toString());
-                preferences.setDomain(controller.getCurrentDataChanel().getName());
-                preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
-                preferences.setDataMap(controller.getCurrentDataMap().getName());
-
-                if (controller.getCurrentObjEntity() != null) {
-                    preferences.setObjEntity(controller.getCurrentObjEntity().getName());
-                    preferences.setObjRels(parseToString(controller.getCurrentObjRelationships()));
-                    preferences.setDbEntity(null);
-                } else if (controller.getCurrentDbEntity() != null) {
-                    preferences.setDbEntity(controller.getCurrentDbEntity().getName());
-                    preferences.setDbRels(parseToString(controller.getCurrentDbRelationships()));
-                    preferences.setObjEntity(null);
-                }
-            }
-        },
-
-        EmbeddableDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                Embeddable embeddable = dataMap.getEmbeddable(preferences.getEmbeddable());
-                if (embeddable == null) {
-                    return;
-                }
-
-                EmbeddableDisplayEvent embeddableDisplayEvent = new EmbeddableDisplayEvent(this, embeddable, dataMap, dataChannel);
-                controller.fireEmbeddableDisplayEvent(embeddableDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                if (controller.getCurrentEmbAttributes().length != 0) {
-                    EmbeddableAttributeDisplayEvent.saveLastDisplayEvent(controller);
-                } else {
-                    preferences.setEvent(EmbeddableDisplayEvent.toString());
-                    preferences.setDomain(controller.getCurrentDataChanel().getName());
-                    preferences.setDataMap(controller.getCurrentDataMap().getName());
-                    preferences.setEmbeddable(controller.getCurrentEmbeddable().getClassName());
-                }
-            }
-        },
-
-        EmbeddableAttributeDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                Embeddable embeddable = dataMap.getEmbeddable(preferences.getEmbeddable());
-                if (embeddable == null) {
-                    return;
-                }
-
-                EmbeddableDisplayEvent embeddableDisplayEvent = new EmbeddableDisplayEvent(this, embeddable, dataMap, dataChannel);
-                controller.fireEmbeddableDisplayEvent(embeddableDisplayEvent);
-
-                EmbeddableAttribute[] embeddableAttributes = getLastEmbeddableAttributes(embeddable);
-                EmbeddableAttributeDisplayEvent attributeDisplayEvent = new EmbeddableAttributeDisplayEvent(this, embeddable, embeddableAttributes, dataMap, dataChannel);
-                controller.fireEmbeddableAttributeDisplayEvent(attributeDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(EmbeddableAttributeDisplayEvent.toString());
-                preferences.setDomain(controller.getCurrentDataChanel().getName());
-                preferences.setDataMap(controller.getCurrentDataMap().getName());
-                preferences.setEmbeddable(controller.getCurrentEmbeddable().getClassName());
-
-                EmbeddableAttribute[] currentEmbAttributes = controller.getCurrentEmbAttributes();
-                if (currentEmbAttributes == null) {
-                    preferences.setEmbAttrs("");
-                } else {
-                    StringBuilder sb = new StringBuilder();
-                    for (EmbeddableAttribute embeddableAttribute : currentEmbAttributes) {
-                        sb.append(embeddableAttribute.getName()).append(",");
-                    }
-                    preferences.setEmbAttrs(sb.toString());
-                }
-            }
-        },
-
-        ProcedureDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                Procedure procedure = dataMap.getProcedure(preferences.getProcedure());
-                if (procedure == null) {
-                    return;
-                }
-
-                ProcedureDisplayEvent procedureDisplayEvent = new ProcedureDisplayEvent(this, procedure, dataMap, dataChannel);
-                controller.fireProcedureDisplayEvent(procedureDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                if (controller.getCurrentProcedureParameters().length != 0) {
-                    ProcedureParameterDisplayEvent.saveLastDisplayEvent(controller);
-                } else {
-                    preferences.setEvent(ProcedureDisplayEvent.toString());
-                    preferences.setDomain(controller.getCurrentDataChanel().getName());
-                    preferences.setDataMap(controller.getCurrentDataMap().getName());
-                    preferences.setProcedure(controller.getCurrentProcedure().getName());
-                }
-            }
-        },
-
-        ProcedureParameterDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                Procedure procedure = dataMap.getProcedure(preferences.getProcedure());
-                if (procedure == null) {
-                    return;
-                }
-
-                ProcedureDisplayEvent procedureDisplayEvent = new ProcedureDisplayEvent(this, procedure, dataMap, dataChannel);
-                controller.fireProcedureDisplayEvent(procedureDisplayEvent);
-
-                ProcedureParameter[] procedureParameters = getLastProcedureParameters(procedure);
-                ProcedureParameterDisplayEvent procedureParameterDisplayEvent =
-                        new ProcedureParameterDisplayEvent(this, procedureParameters, procedure, dataMap, dataChannel);
-                controller.fireProcedureParameterDisplayEvent(procedureParameterDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(ProcedureParameterDisplayEvent.toString());
-                preferences.setDomain(controller.getCurrentDataChanel().getName());
-                preferences.setDataMap(controller.getCurrentDataMap().getName());
-                preferences.setProcedure(controller.getCurrentProcedure().getName());
-                preferences.setProcedureParams(parseToString(controller.getCurrentProcedureParameters()));
-            }
-        },
-
-        QueryDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-                if (!dataChannel.getName().equals(preferences.getDomain())) {
-                    return;
-                }
-
-                DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
-                if (dataMap == null) {
-                    return;
-                }
-
-                Query query = dataMap.getQuery(preferences.getQuery());
-                if (query == null) {
-                    return;
-                }
-
-                QueryDisplayEvent queryDisplayEvent = new QueryDisplayEvent(this, query, dataMap, dataChannel);
-                controller.fireQueryDisplayEvent(queryDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(QueryDisplayEvent.toString());
-                preferences.setDomain(controller.getCurrentDataChanel().getName());
-                preferences.setDataMap(controller.getCurrentDataMap().getName());
-                preferences.setQuery(controller.getCurrentQuery().getName());
-            }
-        },
-
-        MultipleObjectsDisplayEvent {
-            @Override
-            void fireLastDisplayEvent(ProjectController controller) {
-                DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
-
-                String parentObjectName = preferences.getParentObject();
-                ConfigurationNode parentObject;
-                ConfigurationNode[] multipleObjects;
-
-                if (dataChannel.getDataMap(parentObjectName) != null) {
-                    DataMap dataMap = dataChannel.getDataMap(parentObjectName);
-                    parentObject = dataMap;
-                    multipleObjects = getLastMultipleObjects(dataMap);
-                } else if (dataChannel.getNodeDescriptor(parentObjectName) != null) {
-                    DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(parentObjectName);
-                    parentObject = dataNode;
-                    multipleObjects = getLastMultipleObjects(dataNode);
-                } else {
-                    parentObject = dataChannel;
-                    multipleObjects = getLastMultipleObjects(dataChannel);
-                }
-
-                MultipleObjectsDisplayEvent multipleDisplayEvent = new MultipleObjectsDisplayEvent(this, multipleObjects, parentObject);
-                controller.fireMultipleObjectsDisplayEvent(multipleDisplayEvent);
-            }
-
-            @Override
-            void saveLastDisplayEvent(ProjectController controller) {
-                preferences.setEvent(MultipleObjectsDisplayEvent.toString());
-                preferences.setParentObject(getObjectName(controller.getCurrentParentPath()));
-
-                Object[] multipleObjects = controller.getCurrentPaths();
-                if (multipleObjects == null) {
-                    preferences.setMultipleObjects("");
-                } else {
-                    StringBuilder sb = new StringBuilder();
-                    for (Object object : multipleObjects) {
-                        String objectName = getObjectName(object);
-                        if (!objectName.isEmpty()) {
-                            sb.append(objectName).append(",");
-                        }
-                    }
-                    preferences.setMultipleObjects(sb.toString());
-                }
-            }
-        };
-
-        abstract void fireLastDisplayEvent(ProjectController controller);
-
-        abstract void saveLastDisplayEvent(ProjectController controller);
-    }
-
-    private static Entity getLastEntity(DataMap dataMap) {
-        return !preferences.getObjEntity().isEmpty()
-                ? dataMap.getObjEntity(preferences.getObjEntity())
-                : dataMap.getDbEntity(preferences.getDbEntity());
-    }
-
-    private static Attribute[] getLastEntityAttributes(Entity entity) {
-        return (entity instanceof ObjEntity)
-                ? getLastObjEntityAttributes((ObjEntity) entity)
-                : getLastDbEntityAttributes((DbEntity) entity);
-    }
-
-    private static Relationship[] getLastEntityRelationships(Entity entity) {
-        return (entity instanceof ObjEntity)
-                ? getLastObjEntityRelationships((ObjEntity) entity)
-                : getLastDbEntityRelationships((DbEntity) entity);
-    }
-
-    private static ObjAttribute[] getLastObjEntityAttributes(ObjEntity objEntity) {
-        List<ObjAttribute> attributeList = new ArrayList<ObjAttribute>();
-        ObjAttribute[] attributes = new ObjAttribute[0];
-
-        String objAttrs = preferences.getObjAttrs();
-        if (!objAttrs.isEmpty()) {
-            String[] lastObjAttrs = objAttrs.split(",");
-            for (String objAttrName : lastObjAttrs) {
-                attributeList.add(objEntity.getAttribute(objAttrName));
-            }
-        }
-
-        return attributeList.toArray(attributes);
-    }
-
-    private static DbAttribute[] getLastDbEntityAttributes(DbEntity dbEntity) {
-        List<DbAttribute> attributeList = new ArrayList<DbAttribute>();
-        DbAttribute[] attributes = new DbAttribute[0];
-
-        String dbAttrs = preferences.getDbAttrs();
-        if (!dbAttrs.isEmpty()) {
-            String[] lastDbAttrs = dbAttrs.split(",");
-            for (String dbAttrName : lastDbAttrs) {
-                attributeList.add(dbEntity.getAttribute(dbAttrName));
-            }
-        }
-
-        return attributeList.toArray(attributes);
-    }
-
-    private static ObjRelationship[] getLastObjEntityRelationships(ObjEntity objEntity) {
-        List<ObjRelationship> relationshipList = new ArrayList<ObjRelationship>();
-        ObjRelationship[] relationships = new ObjRelationship[0];
-
-        String objRels = preferences.getObjRels();
-        if (!objRels.isEmpty()) {
-            String[] lastObjRels = objRels.split(",");
-            for (String objRelName : lastObjRels) {
-                relationshipList.add(objEntity.getRelationship(objRelName));
-            }
-        }
-
-        return relationshipList.toArray(relationships);
-    }
-
-    private static DbRelationship[] getLastDbEntityRelationships(DbEntity dbEntity) {
-        List<DbRelationship> relationshipList = new ArrayList<DbRelationship>();
-        DbRelationship[] relationships = new DbRelationship[0];
-
-        String dbRels = preferences.getDbRels();
-        if (!dbRels.isEmpty()) {
-            String[] lastDbRels = dbRels.split(",");
-            for (String dbRelName : lastDbRels) {
-                relationshipList.add(dbEntity.getRelationship(dbRelName));
-            }
-        }
-
-        return relationshipList.toArray(relationships);
-    }
-
-    private static EmbeddableAttribute[] getLastEmbeddableAttributes(Embeddable embeddable) {
-        List<EmbeddableAttribute> embeddableAttributeList = new ArrayList<EmbeddableAttribute>();
-        EmbeddableAttribute[] attributes = new EmbeddableAttribute[0];
-
-        String embAttrs = preferences.getEmbAttrs();
-        if (!embAttrs.isEmpty()) {
-            String[] lastEmbAttrs = embAttrs.split(",");
-            for (String embAttrName : lastEmbAttrs) {
-                embeddableAttributeList.add(embeddable.getAttribute(embAttrName));
-            }
-        }
-
-        return embeddableAttributeList.toArray(attributes);
-    }
-
-    private static ProcedureParameter[] getLastProcedureParameters(Procedure procedure) {
-        List<ProcedureParameter> procedureParameterList = new ArrayList<ProcedureParameter>();
-        ProcedureParameter[] parameters = new ProcedureParameter[0];
-
-        String procedureParams = preferences.getProcedureParams();
-        if (!procedureParams.isEmpty()) {
-            String[] lastProcedureParams = procedureParams.split(",");
-            for (String procedureParamName : lastProcedureParams) {
-                for (ProcedureParameter procedureParameter : procedure.getCallParameters()) {
-                    if (procedureParameter.getName().equals(procedureParamName)) {
-                        procedureParameterList.add(procedureParameter);
-                    }
-                }
-            }
-        }
-
-        return procedureParameterList.toArray(parameters);
-    }
-
-    private static ConfigurationNode[] getLastMultipleObjects(DataChannelDescriptor dataChannel) {
-        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
-        ConfigurationNode[] nodes = new ConfigurationNode[0];
-
-        String multipleObjects = preferences.getMultipleObjects();
-        if (!multipleObjects.isEmpty()) {
-            String[] lastMultipleObjects = multipleObjects.split(",");
-
-            outer:
-            for (String objectName : lastMultipleObjects) {
-                if (dataChannel.getName().equals(objectName)) {
-                    configurationNodeList.add(dataChannel);
-                    continue outer;
-                }
-
-                for (DataNodeDescriptor dataNode : dataChannel.getNodeDescriptors()) {
-                    if (dataNode.getName().equals(objectName)) {
-                        configurationNodeList.add(dataNode);
-                        continue outer;
-                    }
-                }
-
-                for (DataMap dataMap : dataChannel.getDataMaps()) {
-                    if (dataMap.getName().equals(objectName)) {
-                        configurationNodeList.add(dataMap);
-                        continue outer;
-                    }
-                }
-            }
-        }
-
-        return configurationNodeList.toArray(nodes);
-    }
-
-    private static ConfigurationNode[] getLastMultipleObjects(DataNodeDescriptor dataNode) {
-        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
-        ConfigurationNode[] nodes = new ConfigurationNode[0];
-
-        String multipleObjects = preferences.getMultipleObjects();
-        if (!multipleObjects.isEmpty()) {
-            String[] lastMultipleObjects = multipleObjects.split(",");
-            for (String objectName : lastMultipleObjects) {
-                if (dataNode.getDataMapNames().contains(objectName)) {
-                    configurationNodeList.add(dataNode.getDataChannelDescriptor().getDataMap(objectName));
-                }
-            }
-        }
-
-        return configurationNodeList.toArray(nodes);
-    }
-
-    private static ConfigurationNode[] getLastMultipleObjects(DataMap dataMap) {
-        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
-        ConfigurationNode[] nodes = new ConfigurationNode[0];
-
-        String multipleObjects = preferences.getMultipleObjects();
-        if (!multipleObjects.isEmpty()) {
-            String[] lastMultipleObjects = multipleObjects.split(",");
-            for (String objectName : lastMultipleObjects) {
-                if (dataMap.getObjEntity(objectName) != null) {
-                    configurationNodeList.add(dataMap.getObjEntity(objectName));
-                } else if (dataMap.getDbEntity(objectName) != null) {
-                    configurationNodeList.add(dataMap.getDbEntity(objectName));
-                } else if (dataMap.getEmbeddable(objectName) != null) {
-                    configurationNodeList.add(dataMap.getEmbeddable(objectName));
-                } else if (dataMap.getProcedure(objectName) != null) {
-                    configurationNodeList.add(dataMap.getProcedure(objectName));
-                } else if (dataMap.getQuery(objectName) != null) {
-                    configurationNodeList.add(dataMap.getQuery(objectName));
-                }
-            }
-        }
-
-        return configurationNodeList.toArray(nodes);
-    }
-
-    private static String getObjectName(Object object) {
-        if (object instanceof CayenneMapEntry) {
-            return ((CayenneMapEntry) object).getName();
-        } else if (object instanceof DataChannelDescriptor) {
-            return ((DataChannelDescriptor) object).getName();
-        } else if (object instanceof DataNodeDescriptor) {
-            return ((DataNodeDescriptor) object).getName();
-        } else if (object instanceof DataMap) {
-            return ((DataMap) object).getName();
-        } else if (object instanceof Embeddable) {
-            return ((Embeddable) object).getClassName();
-        } else if (object instanceof Query) {
-            return ((Query) object).getName();
-        } else {
-            return "";
-        }
-    }
-
-    private static String parseToString(CayenneMapEntry[] array) {
-        if (array == null) {
-            return "";
-        }
-
-        StringBuilder sb = new StringBuilder();
-        for (CayenneMapEntry entry : array) {
-            sb.append(entry.getName()).append(",");
-        }
-
-        return sb.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/AttributeDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/AttributeDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/AttributeDisplayEventType.java
new file mode 100644
index 0000000..4fb2659
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/AttributeDisplayEventType.java
@@ -0,0 +1,107 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.AttributeDisplayEvent;
+import org.apache.cayenne.modeler.event.EntityDisplayEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class AttributeDisplayEventType extends EntityDisplayEventType {
+
+    public AttributeDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        Entity entity = getLastEntity(dataMap);
+        if (entity == null) {
+            return;
+        }
+
+        Attribute[] attributes = getLastEntityAttributes(entity);
+
+        EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
+        AttributeDisplayEvent attributeDisplayEvent = new AttributeDisplayEvent(this, attributes, entity, dataMap, dataChannel);
+
+        if (entity instanceof ObjEntity) {
+            controller.fireObjEntityDisplayEvent(entityDisplayEvent);
+            controller.fireObjAttributeDisplayEvent(attributeDisplayEvent);
+        } else if (entity instanceof DbEntity) {
+            controller.fireDbEntityDisplayEvent(entityDisplayEvent);
+            controller.fireDbAttributeDisplayEvent(attributeDisplayEvent);
+        }
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(AttributeDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+
+        if (controller.getCurrentObjEntity() != null) {
+            preferences.setObjEntity(controller.getCurrentObjEntity().getName());
+            preferences.setObjAttrs(parseToString(controller.getCurrentObjAttributes()));
+            preferences.setDbEntity(null);
+        } else if (controller.getCurrentDbEntity() != null) {
+            preferences.setDbEntity(controller.getCurrentDbEntity().getName());
+            preferences.setDbAttrs(parseToString(controller.getCurrentDbAttributes()));
+            preferences.setObjEntity(null);
+        }
+    }
+
+    protected Attribute[] getLastEntityAttributes(Entity entity) {
+        List<Attribute> attributeList = new ArrayList<Attribute>();
+        Attribute[] attributes = new Attribute[0];
+
+        String attrs = (entity instanceof ObjEntity)
+                ? preferences.getObjAttrs()
+                : preferences.getDbAttrs();
+
+        for (String attrName : attrs.split(",")) {
+            attributeList.add(entity.getAttribute(attrName));
+        }
+
+        return attributeList.toArray(attributes);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DataMapDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DataMapDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DataMapDisplayEventType.java
new file mode 100644
index 0000000..66ae7aa
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DataMapDisplayEventType.java
@@ -0,0 +1,58 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.DataMapDisplayEvent;
+
+class DataMapDisplayEventType extends DisplayEventType {
+
+    public DataMapDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        DataMapDisplayEvent dataMapDisplayEvent = new DataMapDisplayEvent(this, dataMap, dataChannel, dataNode);
+        controller.fireDataMapDisplayEvent(dataMapDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(DataMapDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DataNodeDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DataNodeDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DataNodeDisplayEventType.java
new file mode 100644
index 0000000..5593a77
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DataNodeDisplayEventType.java
@@ -0,0 +1,55 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.DataNodeDisplayEvent;
+
+class DataNodeDisplayEventType extends DisplayEventType {
+
+    public DataNodeDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+        if (dataNode == null) {
+            return;
+        }
+
+        DataNodeDisplayEvent dataNodeDisplayEvent = new DataNodeDisplayEvent(this, dataChannel, dataNode);
+        controller.fireDataNodeDisplayEvent(dataNodeDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(DataNodeDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setNode(controller.getCurrentDataNode().getName());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DisplayEventType.java
new file mode 100644
index 0000000..73ba690
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DisplayEventType.java
@@ -0,0 +1,76 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Embeddable;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.pref.ProjectStatePreferences;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.util.CayenneMapEntry;
+
+public abstract class DisplayEventType {
+
+    protected ProjectController controller;
+    protected ProjectStatePreferences preferences;
+
+    public DisplayEventType(ProjectController controller) {
+        this.controller = controller;
+        this.preferences = controller.getProjectStatePreferences();
+    }
+
+    public abstract void fireLastDisplayEvent();
+
+    public abstract void saveLastDisplayEvent();
+
+    protected String getObjectName(Object object) {
+        if (object instanceof CayenneMapEntry) {
+            return ((CayenneMapEntry) object).getName();
+        } else if (object instanceof DataChannelDescriptor) {
+            return ((DataChannelDescriptor) object).getName();
+        } else if (object instanceof DataNodeDescriptor) {
+            return ((DataNodeDescriptor) object).getName();
+        } else if (object instanceof DataMap) {
+            return ((DataMap) object).getName();
+        } else if (object instanceof Embeddable) {
+            return ((Embeddable) object).getClassName();
+        } else if (object instanceof Query) {
+            return ((Query) object).getName();
+        } else {
+            return "";
+        }
+    }
+
+    protected String parseToString(CayenneMapEntry[] array) {
+        if (array == null) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (CayenneMapEntry entry : array) {
+            sb.append(entry.getName()).append(",");
+        }
+
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DisplayEventTypes.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DisplayEventTypes.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DisplayEventTypes.java
new file mode 100644
index 0000000..44bac2c
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DisplayEventTypes.java
@@ -0,0 +1,198 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.AttributeDisplayEvent;
+import org.apache.cayenne.modeler.event.DataMapDisplayEvent;
+import org.apache.cayenne.modeler.event.DataNodeDisplayEvent;
+import org.apache.cayenne.modeler.event.DomainDisplayEvent;
+import org.apache.cayenne.modeler.event.EmbeddableAttributeDisplayEvent;
+import org.apache.cayenne.modeler.event.EmbeddableDisplayEvent;
+import org.apache.cayenne.modeler.event.EntityDisplayEvent;
+import org.apache.cayenne.modeler.event.MultipleObjectsDisplayEvent;
+import org.apache.cayenne.modeler.event.ProcedureDisplayEvent;
+import org.apache.cayenne.modeler.event.ProcedureParameterDisplayEvent;
+import org.apache.cayenne.modeler.event.QueryDisplayEvent;
+import org.apache.cayenne.modeler.event.RelationshipDisplayEvent;
+
+public enum DisplayEventTypes {
+
+    DomainDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new DomainDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return DomainDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    DataNodeDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new DataNodeDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return DataNodeDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    DataMapDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new DataMapDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return DataMapDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    EntityDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            if (controller.getCurrentObjAttributes().length != 0 || controller.getCurrentDbAttributes().length != 0) {
+                return new AttributeDisplayEventType(controller);
+            } else if (controller.getCurrentObjRelationships().length != 0 || controller.getCurrentDbRelationships().length != 0) {
+                return new RelationshipDisplayEventType(controller);
+            } else {
+                return new EntityDisplayEventType(controller);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return EntityDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    AttributeDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new AttributeDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return AttributeDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    RelationshipDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new RelationshipDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return RelationshipDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    EmbeddableDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            if (controller.getCurrentEmbAttributes().length != 0) {
+                return new EmbeddableAttributeDisplayEventType(controller);
+            } else {
+                return new EmbeddableDisplayEventType(controller);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return EmbeddableDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    EmbeddableAttributeDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new EmbeddableAttributeDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return EmbeddableAttributeDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    ProcedureDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            if (controller.getCurrentProcedureParameters().length != 0) {
+                return new ProcedureParameterDisplayEventType(controller);
+            } else {
+                return new ProcedureDisplayEventType(controller);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return ProcedureDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    ProcedureParameterDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new ProcedureParameterDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return ProcedureParameterDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    QueryDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new QueryDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return QueryDisplayEvent.class.getSimpleName();
+        }
+    },
+
+    MultipleObjectsDisplayEvent {
+        @Override
+        DisplayEventType createDisplayEventType(ProjectController controller) {
+            return new MultipleObjectsDisplayEventType(controller);
+        }
+
+        @Override
+        public String toString() {
+            return MultipleObjectsDisplayEvent.class.getSimpleName();
+        }
+    };
+
+    abstract DisplayEventType createDisplayEventType(ProjectController controller);
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DomainDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DomainDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DomainDisplayEventType.java
new file mode 100644
index 0000000..293422f
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/DomainDisplayEventType.java
@@ -0,0 +1,49 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.DomainDisplayEvent;
+
+class DomainDisplayEventType extends DisplayEventType {
+
+    public DomainDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DomainDisplayEvent domainDisplayEvent = new DomainDisplayEvent(this, dataChannel);
+        controller.fireDomainDisplayEvent(domainDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(DomainDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EmbeddableAttributeDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EmbeddableAttributeDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EmbeddableAttributeDisplayEventType.java
new file mode 100644
index 0000000..568e467
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EmbeddableAttributeDisplayEventType.java
@@ -0,0 +1,98 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Embeddable;
+import org.apache.cayenne.map.EmbeddableAttribute;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.EmbeddableAttributeDisplayEvent;
+import org.apache.cayenne.modeler.event.EmbeddableDisplayEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class EmbeddableAttributeDisplayEventType extends EmbeddableDisplayEventType {
+
+    public EmbeddableAttributeDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        Embeddable embeddable = dataMap.getEmbeddable(preferences.getEmbeddable());
+        if (embeddable == null) {
+            return;
+        }
+
+        EmbeddableDisplayEvent embeddableDisplayEvent = new EmbeddableDisplayEvent(this, embeddable, dataMap, dataChannel);
+        controller.fireEmbeddableDisplayEvent(embeddableDisplayEvent);
+
+        EmbeddableAttribute[] embeddableAttributes = getLastEmbeddableAttributes(embeddable);
+        EmbeddableAttributeDisplayEvent attributeDisplayEvent = new EmbeddableAttributeDisplayEvent(this, embeddable, embeddableAttributes, dataMap, dataChannel);
+        controller.fireEmbeddableAttributeDisplayEvent(attributeDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(EmbeddableAttributeDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+        preferences.setEmbeddable(controller.getCurrentEmbeddable().getClassName());
+
+        EmbeddableAttribute[] currentEmbAttributes = controller.getCurrentEmbAttributes();
+        if (currentEmbAttributes == null) {
+            preferences.setEmbAttrs("");
+        } else {
+            StringBuilder sb = new StringBuilder();
+            for (EmbeddableAttribute embeddableAttribute : currentEmbAttributes) {
+                sb.append(embeddableAttribute.getName()).append(",");
+            }
+            preferences.setEmbAttrs(sb.toString());
+        }
+    }
+
+    protected EmbeddableAttribute[] getLastEmbeddableAttributes(Embeddable embeddable) {
+        List<EmbeddableAttribute> embeddableAttributeList = new ArrayList<EmbeddableAttribute>();
+        EmbeddableAttribute[] attributes = new EmbeddableAttribute[0];
+
+        String embAttrs = preferences.getEmbAttrs();
+        if (embAttrs.isEmpty()) {
+            return embeddableAttributeList.toArray(attributes);
+        }
+
+        for (String embAttrName : embAttrs.split(",")) {
+            embeddableAttributeList.add(embeddable.getAttribute(embAttrName));
+        }
+
+        return embeddableAttributeList.toArray(attributes);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EmbeddableDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EmbeddableDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EmbeddableDisplayEventType.java
new file mode 100644
index 0000000..a815972
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EmbeddableDisplayEventType.java
@@ -0,0 +1,62 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Embeddable;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.EmbeddableDisplayEvent;
+
+class EmbeddableDisplayEventType extends DisplayEventType {
+
+    public EmbeddableDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        Embeddable embeddable = dataMap.getEmbeddable(preferences.getEmbeddable());
+        if (embeddable == null) {
+            return;
+        }
+
+        EmbeddableDisplayEvent embeddableDisplayEvent = new EmbeddableDisplayEvent(this, embeddable, dataMap, dataChannel);
+        controller.fireEmbeddableDisplayEvent(embeddableDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(EmbeddableDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+        preferences.setEmbeddable(controller.getCurrentEmbeddable().getClassName());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EntityDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EntityDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EntityDisplayEventType.java
new file mode 100644
index 0000000..1559fa1
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/EntityDisplayEventType.java
@@ -0,0 +1,84 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.EntityDisplayEvent;
+
+class EntityDisplayEventType extends DisplayEventType {
+
+    public EntityDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+        if (!dataChannel.getName().equals(preferences.getDomain())) {
+            return;
+        }
+
+        DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(preferences.getNode());
+        DataMap dataMap = dataChannel.getDataMap(preferences.getDataMap());
+        if (dataMap == null) {
+            return;
+        }
+
+        Entity entity = getLastEntity(dataMap);
+        if (entity == null) {
+            return;
+        }
+
+        EntityDisplayEvent entityDisplayEvent = new EntityDisplayEvent(this, entity, dataMap, dataNode, dataChannel);
+        if (entity instanceof ObjEntity) {
+            controller.fireObjEntityDisplayEvent(entityDisplayEvent);
+        } else if (entity instanceof DbEntity) {
+            controller.fireDbEntityDisplayEvent(entityDisplayEvent);
+        }
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(EntityDisplayEvent.class.getSimpleName());
+        preferences.setDomain(controller.getCurrentDataChanel().getName());
+        preferences.setNode(controller.getCurrentDataNode() != null ? controller.getCurrentDataNode().getName() : "");
+        preferences.setDataMap(controller.getCurrentDataMap().getName());
+
+        if (controller.getCurrentObjEntity() != null) {
+            preferences.setObjEntity(controller.getCurrentObjEntity().getName());
+            preferences.setDbEntity(null);
+        } else if (controller.getCurrentDbEntity() != null) {
+            preferences.setDbEntity(controller.getCurrentDbEntity().getName());
+            preferences.setObjEntity(null);
+        }
+    }
+
+    protected Entity getLastEntity(DataMap dataMap) {
+        return !preferences.getObjEntity().isEmpty()
+                ? dataMap.getObjEntity(preferences.getObjEntity())
+                : dataMap.getDbEntity(preferences.getDbEntity());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/1f514c4b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/MultipleObjectsDisplayEventType.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/MultipleObjectsDisplayEventType.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/MultipleObjectsDisplayEventType.java
new file mode 100644
index 0000000..bc7251e
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/state/MultipleObjectsDisplayEventType.java
@@ -0,0 +1,166 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.util.state;
+
+import org.apache.cayenne.configuration.ConfigurationNode;
+import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.DataNodeDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.event.MultipleObjectsDisplayEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class MultipleObjectsDisplayEventType extends DisplayEventType {
+
+    public MultipleObjectsDisplayEventType(ProjectController controller) {
+        super(controller);
+    }
+
+    @Override
+    public void fireLastDisplayEvent() {
+        DataChannelDescriptor dataChannel = (DataChannelDescriptor) controller.getProject().getRootNode();
+
+        String parentObjectName = preferences.getParentObject();
+        ConfigurationNode parentObject;
+        ConfigurationNode[] multipleObjects;
+
+        if (dataChannel.getDataMap(parentObjectName) != null) {
+            DataMap dataMap = dataChannel.getDataMap(parentObjectName);
+            parentObject = dataMap;
+            multipleObjects = getLastMultipleObjects(dataMap);
+        } else if (dataChannel.getNodeDescriptor(parentObjectName) != null) {
+            DataNodeDescriptor dataNode = dataChannel.getNodeDescriptor(parentObjectName);
+            parentObject = dataNode;
+            multipleObjects = getLastMultipleObjects(dataNode);
+        } else {
+            parentObject = dataChannel;
+            multipleObjects = getLastMultipleObjects(dataChannel);
+        }
+
+        MultipleObjectsDisplayEvent multipleDisplayEvent = new MultipleObjectsDisplayEvent(this, multipleObjects, parentObject);
+        controller.fireMultipleObjectsDisplayEvent(multipleDisplayEvent);
+    }
+
+    @Override
+    public void saveLastDisplayEvent() {
+        preferences.setEvent(MultipleObjectsDisplayEvent.class.getSimpleName());
+        preferences.setParentObject(getObjectName(controller.getCurrentParentPath()));
+
+        Object[] multipleObjects = controller.getCurrentPaths();
+        if (multipleObjects == null) {
+            preferences.setMultipleObjects("");
+        } else {
+            StringBuilder sb = new StringBuilder();
+            for (Object object : multipleObjects) {
+                String objectName = getObjectName(object);
+                if (!objectName.isEmpty()) {
+                    sb.append(objectName).append(",");
+                }
+            }
+            preferences.setMultipleObjects(sb.toString());
+        }
+    }
+
+    protected ConfigurationNode[] getLastMultipleObjects(DataChannelDescriptor dataChannel) {
+        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
+        ConfigurationNode[] nodes = new ConfigurationNode[0];
+
+        String multipleObjects = preferences.getMultipleObjects();
+        if (multipleObjects.isEmpty()) {
+            return configurationNodeList.toArray(nodes);
+        }
+
+        for (String objectName : multipleObjects.split(",")) {
+            ConfigurationNode configNode = getConfigNode(dataChannel, objectName);
+            if (configNode != null) {
+                configurationNodeList.add(configNode);
+            }
+        }
+
+        return configurationNodeList.toArray(nodes);
+    }
+
+    protected ConfigurationNode[] getLastMultipleObjects(DataNodeDescriptor dataNode) {
+        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
+        ConfigurationNode[] nodes = new ConfigurationNode[0];
+
+        String multipleObjects = preferences.getMultipleObjects();
+        if (multipleObjects.isEmpty()) {
+            return configurationNodeList.toArray(nodes);
+        }
+
+        for (String objectName : multipleObjects.split(",")) {
+            if (dataNode.getDataMapNames().contains(objectName)) {
+                configurationNodeList.add(dataNode.getDataChannelDescriptor().getDataMap(objectName));
+            }
+        }
+
+        return configurationNodeList.toArray(nodes);
+    }
+
+    protected ConfigurationNode[] getLastMultipleObjects(DataMap dataMap) {
+        List<ConfigurationNode> configurationNodeList = new ArrayList<ConfigurationNode>();
+        ConfigurationNode[] nodes = new ConfigurationNode[0];
+
+        String multipleObjects = preferences.getMultipleObjects();
+        if (multipleObjects.isEmpty()) {
+            return configurationNodeList.toArray(nodes);
+        }
+
+        for (String objectName : multipleObjects.split(",")) {
+            if (dataMap.getObjEntity(objectName) != null) {
+                configurationNodeList.add(dataMap.getObjEntity(objectName));
+            } else if (dataMap.getDbEntity(objectName) != null) {
+                configurationNodeList.add(dataMap.getDbEntity(objectName));
+            } else if (dataMap.getEmbeddable(objectName) != null) {
+                configurationNodeList.add(dataMap.getEmbeddable(objectName));
+            } else if (dataMap.getProcedure(objectName) != null) {
+                configurationNodeList.add(dataMap.getProcedure(objectName));
+            } else if (dataMap.getQuery(objectName) != null) {
+                configurationNodeList.add(dataMap.getQuery(objectName));
+            }
+        }
+
+        return configurationNodeList.toArray(nodes);
+    }
+
+    private ConfigurationNode getConfigNode(DataChannelDescriptor dataChannel, String objectName) {
+        if (dataChannel.getName().equals(objectName)) {
+            return dataChannel;
+        }
+
+        for (DataNodeDescriptor dataNode : dataChannel.getNodeDescriptors()) {
+            if (dataNode.getName().equals(objectName)) {
+                return dataNode;
+            }
+        }
+
+        for (DataMap dataMap : dataChannel.getDataMaps()) {
+            if (dataMap.getName().equals(objectName)) {
+                return dataMap;
+            }
+        }
+
+        return null;
+    }
+
+}
\ No newline at end of file