Author: jfuerth
Date: Wed Sep  3 12:52:54 2008
New Revision: 2689

Modified:
   trunk/src/ca/sqlpower/architect/olap/undo/OLAPUndoManager.java
   trunk/src/ca/sqlpower/architect/swingui/SwingUIProject.java
   trunk/src/ca/sqlpower/architect/swingui/olap/OLAPEditSession.java

Log:
Ultra-deluxe "unsaved changes" support for the OLAP edit sessions. This implementation is exactly what we've been planning to do for the Architect for years. This proof-of-concept has worked out beautifully, so we'll likely make the same changes to the relational modeling part soon.

Basically, we hook into the olap session's undo manager, and only consider the project modified if the undo manager isn't at the previously "remembered" position, which is set every time the project gets saved.

Modified: trunk/src/ca/sqlpower/architect/olap/undo/OLAPUndoManager.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/olap/undo/OLAPUndoManager.java (original) +++ trunk/src/ca/sqlpower/architect/olap/undo/OLAPUndoManager.java Wed Sep 3 12:52:54 2008
@@ -21,6 +21,7 @@

 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;

@@ -69,9 +70,42 @@
      */
     private int compoundEditDepth = 0;

+    private WeakReference<UndoableEdit> rememberedPosition;
+
     public OLAPUndoManager(OLAPObject root) {
OLAPUtil.listenToHierarchy(root, eventHandler, eventHandler, eventHandler);
         // TODO need to track the playpen components as well
+    }
+
+    /**
+     * Marks this undo manager's current position.
+     */
+    public void rememberPosition() {
+ // this might be a weak reference to null, for instance if there are no edits yet
+        // (but that's ok; it will still work)
+ rememberedPosition = new WeakReference<UndoableEdit>(editToBeUndone());
+        fireChangeEvent();
+    }
+
+    public boolean isAtRememberedPosition() {
+ return rememberedPosition != null && rememberedPosition.get() == editToBeUndone();
+    }
+
+    /**
+ * This override is just a hook for the "remembered position" system. If we + * are trimming off the first edit, and our remembered undoable edit was + * null (which only happens when the remembered position is before the first + * edit), we "unremember" the position because it is now impossible to get
+     * back there. If we didn't do this, if the user undoes back to the
+     * beginning of the undo vector, we would report that we're at the
+     * remembered position, but it would be a lie.
+     */
+    @Override
+    protected void trimEdits(int from, int to) {
+        super.trimEdits(from, to);
+        if (from == 0 && to > 0 && rememberedPosition.get() == null) {
+            rememberedPosition = null;
+        }
     }

     @Override

Modified: trunk/src/ca/sqlpower/architect/swingui/SwingUIProject.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/SwingUIProject.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/SwingUIProject.java Wed Sep 3 12:52:54 2008
@@ -140,6 +140,18 @@
         this.session = session;
     }

+    /**
+ * Override that also considers whether each OLAP edit session has modifications.
+     */
+    @Override
+    public boolean isModified() {
+        boolean olapModified = false;
+ for (OLAPEditSession oSession : getSession().getOLAPEditSessions()) {
+            olapModified |= oSession.isModified();
+        }
+        return olapModified || super.isModified();
+    }
+
     // ------------- READING THE PROJECT FILE ---------------

public void load(InputStream in, DataSourceCollection dataSources) throws IOException, ArchitectException {
@@ -649,7 +661,12 @@

             ioo.indent--;
             ioo.println(out, "</architect-project>"); //$NON-NLS-1$
+
             setModified(false);
+ for (OLAPEditSession oSession : getSession().getOLAPEditSessions()) {
+                oSession.saveNotify();
+            }
+
         } finally {
             if (out != null) out.close();
         }

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/OLAPEditSession.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/OLAPEditSession.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/olap/OLAPEditSession.java Wed Sep 3 12:52:54 2008
@@ -29,6 +29,8 @@
 import javax.swing.JScrollPane;
 import javax.swing.JSplitPane;
 import javax.swing.JToolBar;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;

 import ca.sqlpower.architect.layout.FruchtermanReingoldForceLayout;
 import ca.sqlpower.architect.olap.OLAPChildEvent;
@@ -131,6 +133,11 @@
         undoManager = new OLAPUndoManager(olapSession);
pp = OLAPPlayPenFactory.createPlayPen(swingSession, this, undoManager);

+        undoManager.addChangeListener(new ChangeListener() {
+            public void stateChanged(ChangeEvent e) {
+                d.setTitle(generateDialogTitle());
+            }
+        });
         // Don't create actions here. PlayPen is currently null.
     }

@@ -225,6 +232,8 @@

         OLAPPlayPenFactory.setupOLAPMouseWheelActions(pp, this);
         OLAPPlayPenFactory.setupOLAPKeyboardActions(pp, this);
+
+        undoManager.rememberPosition();
     }

     /**
@@ -244,12 +253,37 @@
     public JScrollPane getPPScrollPane() {
         return ppScrollPane;
     }
+
+    /**
+ * This method must be called just after this session has been saved with
+     * the project. It resets the save state, and might do other stuff that
+     * client code shouldn't care about.
+     */
+    public void saveNotify() {
+        undoManager.rememberPosition();
+    }

     /**
- * Returns the schema edit dialog's title that includes the schema's name. + * returns true if any aspect of this session has been modified since it was + * created or since the last time [EMAIL PROTECTED] #saveNotify()} was called, whichever
+     * is more recent.
+     */
+    public boolean isModified() {
+        return !undoManager.isAtRememberedPosition();
+    }
+
+    /**
+ * Returns the schema edit dialog's title that includes the schema's name and
+     * an asterisk if the schema has unsaved changes.
      */
     private String generateDialogTitle() {
-        return olapSession.getSchema().getName() + " - OLAP Schema Editor";
+        StringBuilder title = new StringBuilder();
+        if (!undoManager.isAtRememberedPosition()) {
+            title.append("*");
+        }
+        title.append(olapSession.getSchema().getName());
+        title.append(" - OLAP Schema Editor");
+        return title.toString();
     }

     /**

Reply via email to