Author: truesweetman
Date: Tue Aug 26 15:43:14 2008
New Revision: 2614

Modified:
   trunk/src/ca/sqlpower/architect/swingui/PlayPen.java
   trunk/src/ca/sqlpower/architect/swingui/olap/DimensionPane.java
   trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPane.java
   trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPlayPenFactory.java
   trunk/src/ca/sqlpower/architect/swingui/olap/OLAPTree.java

Log:
Implemented synchronization for the OLAPPlayPen. It uses a similair method that the RelationalPlayPen uses. Currently, cubeUsages are not synchronized because they are not shown in the OLAPTree!

Modified: trunk/src/ca/sqlpower/architect/swingui/PlayPen.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/PlayPen.java        (original)
+++ trunk/src/ca/sqlpower/architect/swingui/PlayPen.java Tue Aug 26 15:43:14 2008
@@ -103,11 +103,30 @@
 import ca.sqlpower.architect.SQLRelationship;
 import ca.sqlpower.architect.SQLSchema;
 import ca.sqlpower.architect.SQLTable;
+import ca.sqlpower.architect.olap.MondrianModel;
+import ca.sqlpower.architect.olap.OLAPObject;
+import ca.sqlpower.architect.olap.MondrianModel.Cube;
+import ca.sqlpower.architect.olap.MondrianModel.DimensionUsage;
+import ca.sqlpower.architect.olap.MondrianModel.Hierarchy;
+import ca.sqlpower.architect.olap.MondrianModel.Level;
+import ca.sqlpower.architect.olap.MondrianModel.Measure;
+import ca.sqlpower.architect.olap.MondrianModel.Schema;
+import ca.sqlpower.architect.olap.MondrianModel.VirtualCube;
+import ca.sqlpower.architect.olap.MondrianModel.VirtualCubeDimension;
+import ca.sqlpower.architect.olap.MondrianModel.VirtualCubeMeasure;
 import ca.sqlpower.architect.swingui.action.CancelAction;
 import ca.sqlpower.architect.swingui.event.PlayPenLifecycleEvent;
 import ca.sqlpower.architect.swingui.event.PlayPenLifecycleListener;
 import ca.sqlpower.architect.swingui.event.SelectionEvent;
 import ca.sqlpower.architect.swingui.event.SelectionListener;
+import ca.sqlpower.architect.swingui.olap.CubePane;
+import ca.sqlpower.architect.swingui.olap.DimensionPane;
+import ca.sqlpower.architect.swingui.olap.OLAPPane;
+import ca.sqlpower.architect.swingui.olap.OLAPTree;
+import ca.sqlpower.architect.swingui.olap.PaneSection;
+import ca.sqlpower.architect.swingui.olap.UsageComponent;
+import ca.sqlpower.architect.swingui.olap.VirtualCubePane;
+import ca.sqlpower.architect.swingui.olap.DimensionPane.HierarchySection;
 import ca.sqlpower.architect.undo.UndoCompoundEvent;
 import ca.sqlpower.architect.undo.UndoCompoundEventListener;
 import ca.sqlpower.architect.undo.UndoCompoundEvent.EventTypes;
@@ -636,7 +655,6 @@
      */
        public Action getMouseZoomInAction(){
         if (zoomInAction == null) {
-            System.out.println("Don't you DARE Zoom In!");
             return session.getArchitectFrame().getZoomInAction();
         }
         return zoomInAction;
@@ -2693,6 +2711,353 @@
         }
         ignoreTreeSelection = false;
     }
+
+    /**
+     * Selects the playpen component that represents the given OLAPObjects.
+ * If the given OLAPObjects aren't in the playpen, this method has no effect.
+     *
+     * @param selection A list of OLAPObjects.
+     * @throws ArchitectException
+     */
+ public void selectObjects(List<OLAPObject> selections, OLAPTree tree) throws ArchitectException {
+        if (ignoreTreeSelection) return;
+        ignoreTreeSelection = true;
+        logger.debug("selecting: " + selections); //$NON-NLS-1$
+
+        // Parent objects to select because a child object was selected.
+        List<OLAPObject> extraSelections = new ArrayList<OLAPObject>();
+
+        // Objects that were already selected, only used for debugging.
+        List<OLAPObject> ignoredObjs = new ArrayList<OLAPObject>();
+
+        for (OLAPObject obj : selections) {
+            if (obj instanceof Cube) {
+                selectCube((Cube) obj, ignoredObjs);
+            } else if (obj instanceof VirtualCube) {
+                selectVirtualCube((VirtualCube) obj, ignoredObjs);
+ } else if (obj instanceof MondrianModel.Dimension || obj instanceof DimensionUsage) {
+                selectDimension(obj, ignoredObjs, extraSelections, tree);
+            } else if (obj instanceof Measure) {
+ selectMeasure((Measure) obj, ignoredObjs, extraSelections, tree); + } else if (obj instanceof VirtualCubeDimension || obj instanceof VirtualCubeMeasure) { + selectItemFromVirtualCube(obj, ignoredObjs, extraSelections, tree);
+            } else if (obj instanceof Hierarchy) {
+ selectHierarchy((Hierarchy) obj, ignoredObjs, extraSelections, tree);
+            } else if (obj instanceof Level) {
+ selectLevel((Level) obj, ignoredObjs, extraSelections, tree);
+            }
+
+ logger.debug("selectObjects ignoring: " + ignoredObjs); //$NON-NLS-1$ + logger.debug("selectObjects adding tables selections: " + extraSelections); //$NON-NLS-1$
+
+            // Deselects all other playpen components.
+            for (PlayPenComponent comp : getSelectedItems()) {
+                if (comp instanceof CubePane) {
+                    CubePane cp = (CubePane) comp;
+ if (!selections.contains(cp.getModel()) && !extraSelections.contains(cp.getModel())) { + cp.setSelected(false, SelectionEvent.SINGLE_SELECT);
+                    }
+
+ // Cannot deselect Objects while going through the selected items.
+                    List<OLAPObject> oos = new ArrayList<OLAPObject>();
+
+                    for (OLAPObject oo : cp.getSelectedItems()) {
+ if (!selections.contains(oo) && !extraSelections.contains(oo)) {
+                            oos.add(oo);
+                        }
+                    }
+                    for (OLAPObject oo : oos) {
+                        cp.deselectItem(oo);
+                    }
+                } else if (comp instanceof VirtualCubePane) {
+                    VirtualCubePane vcp = (VirtualCubePane) comp;
+ if (!selections.contains(vcp.getModel()) && !extraSelections.contains(vcp.getModel())) { + vcp.setSelected(false, SelectionEvent.SINGLE_SELECT);
+                    }
+
+ // Cannot deselect Objects while going through the selected items.
+                    List<OLAPObject> oos = new ArrayList<OLAPObject>();
+
+                    for (OLAPObject oo : vcp.getSelectedItems()) {
+ if (!selections.contains(oo) && !extraSelections.contains(oo)) {
+                            oos.add(oo);
+                        }
+                    }
+                    for (OLAPObject oo : oos) {
+                        vcp.deselectItem(oo);
+                    }
+                } else if (comp instanceof DimensionPane) {
+                    DimensionPane dp = (DimensionPane) comp;
+ if (!selections.contains(dp.getModel()) && !extraSelections.contains(dp.getModel())) { + dp.setSelected(false, SelectionEvent.SINGLE_SELECT);
+                    }
+
+ // Cannot deselect Objects while going through the selected items.
+                    List<OLAPObject> oos = new ArrayList<OLAPObject>();
+
+                    for (OLAPObject oo : dp.getSelectedItems()) {
+ if (!selections.contains(oo) && !extraSelections.contains(oo)) {
+                            oos.add(oo);
+                        }
+                    }
+
+                    // Get the hierarchies from the sections and add them.
+ for (PaneSection<? extends Level> hs : dp.getSelectedSections()) {
+                        if (hs instanceof HierarchySection) {
+ if (!selections.contains(((HierarchySection) hs).getHierarchy()) + && !extraSelections.contains(((HierarchySection) hs).getHierarchy())) { + oos.add(((HierarchySection) hs).getHierarchy());
+                            }
+                        }
+                    }
+                    for (OLAPObject oo : oos) {
+                        if (oo instanceof Level) {
+                            dp.deselectItem((Level) oo);
+                        } else if (oo instanceof Hierarchy) {
+ dp.deselectSection(dp.findSection((Hierarchy) oo));
+                        }
+                    }
+                } else if (comp instanceof UsageComponent) {
+                    UsageComponent uc = (UsageComponent) comp;
+ if (!selections.contains(uc.getModel()) && !extraSelections.contains(uc.getModel())) { + uc.setSelected(false, SelectionEvent.SINGLE_SELECT);
+                    }
+                } else {
+ throw new IllegalArgumentException("Unknown PlayPenComponent type " + comp.getClass() + "!");
+                }
+
+            }
+        }
+        ignoreTreeSelection = false;
+    }
+
+    /**
+     * Uses the given cube to select the matching CubePane on the PlayPen.
+     *
+     * @param cube The Cube whose pane is to be selected.
+     * @param ignoredObjs A list of ingored objects used for debugging.
+     * @return The CubePane that was selected or null if none was selected.
+     */
+    private CubePane selectCube(Cube cube, List<OLAPObject> ignoredObjs) {
+        CubePane cp = (CubePane)findPPComponent(cube);
+        if (cp != null && !cp.isSelected()) {
+            cp.setSelected(true, SelectionEvent.SINGLE_SELECT);
+        } else {
+            ignoredObjs.add(cube);
+        }
+        return cp;
+    }
+
+    /**
+ * Uses the given virtualCube to select the matching VirtualCubePane on the PlayPen.
+     *
+     * @param vCube The VirtualCube whose pane is to be selected.
+     * @param ignoredObjs A list of ingored objects used for debugging.
+ * @return The VirtualCubePane that was selected or null if none was selected.
+     */
+ private VirtualCubePane selectVirtualCube(VirtualCube vCube, List<OLAPObject> ignoredObjs) {
+        VirtualCubePane vcp = (VirtualCubePane)findPPComponent(vCube);
+        if (vcp != null && !vcp.isSelected()) {
+            vcp.setSelected(true, SelectionEvent.SINGLE_SELECT);
+        } else {
+            ignoredObjs.add(vCube);
+        }
+        return vcp;
+    }
+
+    /**
+ * Uses the given OLAPObject (which has to be Dimension or DimnesionUsage) to
+     * select the matching CubePane or DimensionPane on the PlayPen. Also
+ * ensures the OLAPTree also selects the dimension and it's parent if the
+     * dimension's parent is a cube and not the schema.
+     *
+     * @param obj
+ * The Dimension or DimensionUsage whose pane is to be selected.
+     * @param ignoredObjs
+     *            A list of ingored objects used for debugging.
+     * @param extraSelections
+ * A list of items that are selected, but not directly from the
+     *            user.
+     * @param tree
+     *            The OLAPTree assoicated with this PlayPen.
+     * @return The OLAPPane that was selected or null if none was selected.
+     */
+ private OLAPPane<?, ?> selectDimension(OLAPObject obj, List<OLAPObject> ignoredObjs, List<OLAPObject> extraSelections, OLAPTree tree) {
+        if (obj.getParent() instanceof Cube) {
+            CubePane cp = selectCube((Cube) obj.getParent(), ignoredObjs);
+            if (cp != null) {
+                selectParents(obj, cp.getModel(), tree, extraSelections);
+                cp.selectItem(obj);
+            }
+            return cp;
+        } else if (obj.getParent() instanceof Schema) {
+            DimensionPane dp = (DimensionPane)findPPComponent(obj);
+            if (dp != null && !dp.isSelected()) {
+                dp.setSelected(true, SelectionEvent.SINGLE_SELECT);
+            } else {
+                ignoredObjs.add(obj);
+            }
+            return dp;
+        } else {
+ throw new IllegalArgumentException("Parent type " + obj.getParent().getClass() + + " is not a valid parent for type " + obj.getClass() + "!");
+        }
+    }
+
+    /**
+ * Uses the given Measure to select the matching Measure and CubePane on the + * PlayPen. Also ensures the OLAPTree also selects the measure and the cube.
+     *
+     * @param measure
+     *            The measure to be selected in the playPen.
+     * @param ignoredObjs
+     *            A list of ingored objects used for debugging.
+     * @param extraSelections
+ * A list of items that are selected, but not directly from the
+     *            user.
+     * @param tree
+     *            The OLAPTree assoicated with this PlayPen.
+     * @return The CubePane that was selected or null if none was selected.
+     */
+ private CubePane selectMeasure(Measure measure, List<OLAPObject> ignoredObjs, List<OLAPObject> extraSelections, OLAPTree tree) {
+        if (measure.getParent() instanceof Cube) {
+ CubePane cp = selectCube((Cube) measure.getParent(), ignoredObjs);
+            if (cp != null) {
+ selectParents(measure, cp.getModel(), tree, extraSelections);
+                cp.selectItem(measure);
+            }
+            return cp;
+        } else {
+ throw new IllegalArgumentException("Parent type " + measure.getParent().getClass() + + " is not a valid parent for type " + measure.getClass() + "!");
+        }
+    }
+
+    /**
+ * Uses the given VirtualCubeMeasure or VirtualCubeDimension to select the
+     * matching Object and VirtualCubePane on the PlayPen. Also ensures the
+     * OLAPTree also selects the object and the virtualCube.
+     *
+     * @param obj
+ * The VirtualCubeMeasure or VirtualCubeDimensionto be select in
+     *            the playPen.
+     * @param ignoredObjs
+     *            A list of ingored objects used for debugging.
+     * @param extraSelections
+ * A list of items that are selected, but not directly from the
+     *            user.
+     * @param tree
+     *            The OLAPTree assoicated with this PlayPen.
+     * @return The VirtualCubePane that was selected or null if none was
+     *         selected.
+     */
+ private VirtualCubePane selectItemFromVirtualCube(OLAPObject obj, List<OLAPObject> ignoredObjs, List<OLAPObject> extraSelections, OLAPTree tree) {
+        if (obj.getParent() instanceof VirtualCube) {
+ VirtualCubePane vcp = selectVirtualCube((VirtualCube) obj.getParent(), ignoredObjs);
+            if (vcp != null) {
+                selectParents(obj, vcp.getModel(), tree, extraSelections);
+                vcp.selectItem(obj);
+            }
+            return vcp;
+        } else {
+ throw new IllegalArgumentException("Parent type " + obj.getParent().getClass() + + " is not a valid parent for type " + obj.getClass() + "!");
+        }
+    }
+
+    /**
+     * Uses the given Hierarchy to select the matching Hierarchy and it's
+ * DimensionPane on the PlayPen. Also ensures the OLAPTree also selects the
+     * hierarchy and the dimension.
+     *
+     * @param hierarchy
+     *            The hierarchy to be selected in the playPen.
+     * @param ignoredObjs
+     *            A list of ingored objects used for debugging.
+     * @param extraSelections
+ * A list of items that are selected, but not directly from the
+     *            user.
+     * @param tree
+     *            The OLAPTree assoicated with this PlayPen.
+ * @return The DimensionPane that was selected or null if none was selected.
+     */
+ private DimensionPane selectHierarchy(Hierarchy hierarchy, List<OLAPObject> ignoredObjs, List<OLAPObject> extraSelections, OLAPTree tree) {
+        if (hierarchy.getParent() instanceof MondrianModel.Dimension) {
+ DimensionPane dp = (DimensionPane)selectDimension(hierarchy.getParent(), ignoredObjs, extraSelections, tree);
+            if (dp != null) {
+ selectParents(hierarchy, dp.getModel(), tree, extraSelections);
+                dp.selectSection(dp.findSection((Hierarchy) hierarchy));
+            } else {
+ throw new NullPointerException("OLAPPane that contains " + hierarchy.getClass() + " not found.");
+            }
+            return dp;
+        } else {
+ throw new IllegalArgumentException("Parent type " + hierarchy.getParent().getClass() + + " is not a valid parent for type " + hierarchy.getClass() + "!");
+        }
+    }
+
+    /**
+ * Uses the given Level to select the matching Level and DimensionPane on + * the PlayPen. Also ensures the OLAPTree also selects the level and the
+     * dimension.
+     *
+     * @param level
+     *            The level to be selected in the playPen.
+     * @param ignoredObjs
+     *            A list of ingored objects used for debugging.
+     * @param extraSelections
+ * A list of items that are selected, but not directly from the
+     *            user.
+     * @param tree
+     *            The OLAPTree assoicated with this PlayPen.
+ * @return The DimensionPane that was selected or null if none was selected.
+     */
+ private DimensionPane selectLevel(Level level, List<OLAPObject> ignoredObjs, List<OLAPObject> extraSelections, OLAPTree tree) {
+        if (level.getParent() instanceof Hierarchy) {
+ DimensionPane dp = (DimensionPane)selectDimension(level.getParent().getParent(), ignoredObjs, extraSelections, tree);
+            if (dp != null) {
+                selectParents(level, dp.getModel(), tree, extraSelections);
+                dp.selectItem((Level) level);
+            } else {
+ throw new NullPointerException("OLAPPane that contains " + level.getClass() + " not found.");
+            }
+            return dp;
+        } else {
+ throw new IllegalArgumentException("Parent type " + level.getParent().getClass() + + " is not a valid parent for type " + level.getClass() + "!");
+        }
+    }
+
+    /**
+     * Uses the given OLAPObjects and selects them on the given OLAPTree.
+     *
+     * @param obj
+     *            The object to be selected on the Tree.
+     * @param parent
+     *            The object's parent to be selected on the Tree.
+     * @param tree
+     *            The OLAPTree assoicated with this PlayPen.
+     * @param extraSelections
+ * A list of items that are selected, but not directly from the
+     *            user.
+     */
+ private void selectParents(OLAPObject obj, OLAPObject parent, OLAPTree tree, List<OLAPObject> extraSelections) {
+        // ensures the table is selected on the dbTree
+        TreePath tp = tree.getTreePathForNode(parent);
+        if (!tree.isPathSelected(tp)) {
+            tree.addSelectionPath(tp);
+            tree.clearNonPlayPenSelections();
+
+            // ensures column tree path is selected after the table
+            TreePath childPath = tree.getTreePathForNode(obj);
+            tree.removeSelectionPath(childPath);
+            tree.addSelectionPath(childPath);
+        }
+        extraSelections.add(parent);
+    }
+
+

        public PlayPenContentPane getPlayPenContentPane() {
                return contentPane;

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/DimensionPane.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/DimensionPane.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/olap/DimensionPane.java Tue Aug 26 15:43:14 2008
@@ -57,7 +57,7 @@

     }

-    private class HierarchySection implements PaneSection<Level> {
+    public class HierarchySection implements PaneSection<Level> {

         private final Hierarchy hierarchy;

@@ -162,5 +162,20 @@
             }
         }
         return filtered;
+    }
+
+    /**
+     * Returns the HierarchySection that contains the given hierarchy.
+     * Returns null if it was not found.
+     */
+    public HierarchySection findSection(Hierarchy hierarchy) {
+        for (PaneSection<? extends Level> hs : sections) {
+           if (hs instanceof HierarchySection) {
+               if (((HierarchySection) hs).getHierarchy() == hierarchy){
+                   return ((HierarchySection) hs);
+               }
+           }
+        }
+        return null;
     }
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPane.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPane.java  (original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPane.java Tue Aug 26 15:43:14 2008
@@ -20,6 +20,7 @@
 package ca.sqlpower.architect.swingui.olap;

 import java.awt.Point;
+import java.awt.Rectangle;
 import java.awt.Window;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
@@ -30,6 +31,7 @@
 import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -259,7 +261,7 @@
             }
} else if (evt.getID() == MouseEvent.MOUSE_MOVED || evt.getID() == MouseEvent.MOUSE_DRAGGED) {
             logger.debug("Mouse moved/dragged to " + evt.getPoint());
-// setSelected(pp.getRubberBand().intersects(getBounds(new Rectangle())),SelectionEvent.SINGLE_SELECT); + setSelected(pp.getRubberBand().intersects(getBounds(new Rectangle())),SelectionEvent.SINGLE_SELECT);
         }
     }

@@ -270,8 +272,10 @@
      *
      * @param sect the section to deselect.
      */
-    public void deselectSection(PaneSection<C> sect) {
+    public void deselectSection(PaneSection<? extends C> sect) {
         selectedSections.remove(sect);
+ // TODO make a firePlayPenCoordinateEvent and change this event to that
+        fireItemsDeselected(Collections.singleton((C) null));
         repaint();
     }

@@ -281,6 +285,8 @@
      */
     public void selectSection(PaneSection<? extends C> sect) {
         selectedSections.add(sect);
+ // TODO make a firePlayPenCoordinateEvent and change this event to that
+        fireItemsSelected(Collections.singleton((C) null));
         repaint();
     }

@@ -592,4 +598,5 @@
     public PlayPenCoordinate<T, C> getInsertionPoint() {
         return insertionPoint;
     }
+
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPlayPenFactory.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPlayPenFactory.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPlayPenFactory.java Tue Aug 26 15:43:14 2008
@@ -20,24 +20,46 @@
 package ca.sqlpower.architect.swingui.olap;

 import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;

 import javax.swing.Action;
 import javax.swing.ActionMap;
 import javax.swing.InputMap;
 import javax.swing.JComponent;
+import javax.swing.JTree;
 import javax.swing.KeyStroke;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreePath;

 import org.apache.log4j.Logger;

+import ca.sqlpower.architect.ArchitectException;
+import ca.sqlpower.architect.ArchitectRuntimeException;
 import ca.sqlpower.architect.olap.OLAPChildEvent;
 import ca.sqlpower.architect.olap.OLAPChildListener;
+import ca.sqlpower.architect.olap.OLAPObject;
 import ca.sqlpower.architect.olap.OLAPUtil;
+import ca.sqlpower.architect.olap.MondrianModel.Cube;
+import ca.sqlpower.architect.olap.MondrianModel.CubeDimension;
+import ca.sqlpower.architect.olap.MondrianModel.Hierarchy;
+import ca.sqlpower.architect.olap.MondrianModel.Level;
+import ca.sqlpower.architect.olap.MondrianModel.Measure;
+import ca.sqlpower.architect.olap.MondrianModel.VirtualCube;
+import ca.sqlpower.architect.olap.MondrianModel.VirtualCubeMeasure;
 import ca.sqlpower.architect.swingui.ArchitectSwingSession;
 import ca.sqlpower.architect.swingui.PlayPen;
 import ca.sqlpower.architect.swingui.PlayPenComponent;
+import ca.sqlpower.architect.swingui.event.ItemSelectionEvent;
+import ca.sqlpower.architect.swingui.event.ItemSelectionListener;
+import ca.sqlpower.architect.swingui.event.PlayPenContentEvent;
+import ca.sqlpower.architect.swingui.event.PlayPenContentListener;
 import ca.sqlpower.architect.swingui.event.PlayPenLifecycleEvent;
 import ca.sqlpower.architect.swingui.event.PlayPenLifecycleListener;
 import ca.sqlpower.architect.swingui.event.SelectionEvent;
+import ca.sqlpower.architect.swingui.event.SelectionListener;
+import ca.sqlpower.architect.swingui.olap.DimensionPane.HierarchySection;

 public class OLAPPlayPenFactory {

@@ -58,6 +80,10 @@
         pp.setPopupFactory(new ContextMenuFactory(session, oSession));
OLAPUtil.listenToHierarchy(oSession.getOlapSession().getSchema(), ppcl, null);

+ SelectionSynchronizer synchronizer = new SelectionSynchronizer(oSession.getOlapTree(), pp);
+        pp.addSelectionListener(synchronizer);
+        oSession.getOlapTree().addTreeSelectionListener(synchronizer);
+        pp.getContentPane().addPlayPenContentListener(synchronizer);
         return pp;
     }

@@ -181,6 +207,190 @@
          */
         public void PlayPenLifeEnding(PlayPenLifecycleEvent e) {
OLAPUtil.unlistenToHierarchy(session.getOlapSession().getSchema(), this, null);
+        }
+    }
+
+    static class SelectionSynchronizer
+    implements SelectionListener,
+            ItemSelectionListener<Cube, OLAPObject>,
+            TreeSelectionListener, PlayPenContentListener {
+
+        private int eventDepth = 0;
+        private final OLAPTree tree;
+        private final PlayPen pp;
+
+        public SelectionSynchronizer(OLAPTree tree, PlayPen pp) {
+            this.tree = tree;
+            this.pp = pp;
+        }
+
+        /**
+         * Synchronizes the olapTree selection with the playpen selections
+         * @throws ArchitectException
+         *
+         */
+        public void updateOLAPTree() {
+            if (eventDepth != 1) return;
+            tree.clearSelection();
+            List<TreePath> selectionPaths = new ArrayList<TreePath>();
+            boolean addedPaths = false;
+            // Keep track of the last tree path
+            TreePath lastPath = null;
+            // finds all the TreePaths to select
+            for (PlayPenComponent comp : pp.getSelectedItems()) {
+ TreePath tp = tree.getTreePathForNode((OLAPObject) comp.getModel());
+                if (!selectionPaths.contains(tp)) {
+                    selectionPaths.add(tp);
+                    addedPaths = true;
+                    lastPath = tp;
+                }
+
+                if (comp instanceof VirtualCubePane) {
+ for (OLAPObject oo :((VirtualCubePane) comp).getSelectedItems()) {
+                        tp = tree.getTreePathForNode(oo);
+                        if (!selectionPaths.contains(tp)) {
+                            selectionPaths.add(tp);
+                            addedPaths = true;
+                            lastPath = tp;
+                        }
+                    }
+                } else if (comp instanceof CubePane) {
+ for (OLAPObject oo :((CubePane) comp).getSelectedItems()) {
+                        tp = tree.getTreePathForNode(oo);
+                        if (!selectionPaths.contains(tp)) {
+                            selectionPaths.add(tp);
+                            addedPaths = true;
+                            lastPath = tp;
+                        }
+                    }
+                } else if (comp instanceof DimensionPane) {
+ for (OLAPObject oo :((DimensionPane) comp).getSelectedItems()) {
+                        tp = tree.getTreePathForNode(oo);
+                        if (!selectionPaths.contains(tp)) {
+                            selectionPaths.add(tp);
+                            addedPaths = true;
+                            lastPath = tp;
+                        }
+                    }
+ for (PaneSection<? extends Level> sect :((DimensionPane) comp).getSelectedSections()) {
+                        Hierarchy hierarchy;
+                        if (sect instanceof HierarchySection) {
+ hierarchy = ((HierarchySection) sect).getHierarchy();
+                        } else {
+ throw new IllegalArgumentException("Unknown section type " + sect.getClass() + " in a DimensionPane!");
+                        }
+                        tp = tree.getTreePathForNode(hierarchy);
+                        if (!selectionPaths.contains(tp)) {
+                            selectionPaths.add(tp);
+                            addedPaths = true;
+                            lastPath = tp;
+                        }
+                    }
+                } else if (comp instanceof UsageComponent) {
+ tp = tree.getTreePathForNode(((UsageComponent) comp).getModel());
+                    if (!selectionPaths.contains(tp)) {
+                        selectionPaths.add(tp);
+                        addedPaths = true;
+                        lastPath = tp;
+                    }
+                }
+            }
+
+            // Scroll to last tree path.
+            if (lastPath != null) {
+                tree.scrollPathToVisible(lastPath);
+            }
+
+ tree.setSelectionPaths(selectionPaths.toArray(new TreePath[selectionPaths.size()]));
+            if (addedPaths) {
+                tree.clearNonPlayPenSelections();
+            }
+        }
+
+        /**
+ * Selects the corresponding objects from the give TreePaths on the PlayPen.
+         *
+         * @param treePaths TreePaths containing the objects to select.
+         */
+        private void selectInPlayPen(TreePath[] treePaths) {
+            if (eventDepth != 1) return;
+            if (treePaths == null) {
+                pp.selectNone();
+            } else {
+                List<OLAPObject> objects = new ArrayList<OLAPObject>();
+                for (TreePath tp : treePaths) {
+ OLAPObject obj = (OLAPObject) tp.getLastPathComponent();
+                    // only select playpen represented objects.
+ if ((obj instanceof Cube || obj instanceof VirtualCube || obj instanceof Measure + || obj instanceof CubeDimension || obj instanceof VirtualCubeMeasure + || obj instanceof Level || obj instanceof Hierarchy) &&
+                            !objects.contains(obj)) {
+                        objects.add(obj);
+                    }
+                }
+                try {
+                    pp.selectObjects(objects, tree);
+                } catch (ArchitectException e) {
+                    throw new ArchitectRuntimeException(e);
+                }
+            }
+        }
+
+        public void itemDeselected(SelectionEvent e) {
+            try {
+                eventDepth++;
+                updateOLAPTree();
+            } finally {
+                eventDepth--;
+            }
+        }
+
+        public void itemSelected(SelectionEvent e) {
+            try {
+                eventDepth++;
+                updateOLAPTree();
+            } finally {
+                eventDepth--;
+            }
+        }
+
+        public void valueChanged(TreeSelectionEvent e) {
+            try {
+                eventDepth++;
+ selectInPlayPen(((JTree) e.getSource()).getSelectionPaths());
+            } finally {
+                eventDepth--;
+            }
+        }
+
+        public void PlayPenComponentAdded(PlayPenContentEvent e) {
+            if (e.getPlayPenComponent() instanceof CubePane) {
+ ((CubePane) e.getPlayPenComponent()).addItemSelectionListener(this);
+            }
+        }
+
+        public void PlayPenComponentRemoved(PlayPenContentEvent e) {
+            if (e.getPlayPenComponent() instanceof CubePane) {
+ ((CubePane) e.getPlayPenComponent()).removeItemSelectionListener(this);
+            }
+        }
+
+ public void itemsDeselected(ItemSelectionEvent<Cube, OLAPObject> e) {
+            try {
+                eventDepth++;
+                updateOLAPTree();
+            } finally {
+                eventDepth--;
+            }
+        }
+
+        public void itemsSelected(ItemSelectionEvent<Cube, OLAPObject> e) {
+            try {
+                eventDepth++;
+                updateOLAPTree();
+            } finally {
+                eventDepth--;
+            }
         }
     }
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/OLAPTree.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/OLAPTree.java  (original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/OLAPTree.java Tue Aug 26 15:43:14 2008
@@ -21,6 +21,8 @@

 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.List;

 import javax.swing.JPopupMenu;
 import javax.swing.JTree;
@@ -29,7 +31,14 @@
 import org.apache.log4j.Logger;

 import ca.sqlpower.architect.olap.OLAPObject;
+import ca.sqlpower.architect.olap.MondrianModel.Cube;
+import ca.sqlpower.architect.olap.MondrianModel.CubeDimension;
+import ca.sqlpower.architect.olap.MondrianModel.Hierarchy;
+import ca.sqlpower.architect.olap.MondrianModel.Level;
+import ca.sqlpower.architect.olap.MondrianModel.Measure;
 import ca.sqlpower.architect.olap.MondrianModel.Schema;
+import ca.sqlpower.architect.olap.MondrianModel.VirtualCube;
+import ca.sqlpower.architect.olap.MondrianModel.VirtualCubeMeasure;
 import ca.sqlpower.architect.swingui.ArchitectSwingSession;
 import ca.sqlpower.swingui.JTreeCollapseAllAction;
 import ca.sqlpower.swingui.JTreeExpandAllAction;
@@ -43,7 +52,10 @@
     private final JTreeCollapseAllAction collapseAllAction;
     private final JTreeExpandAllAction expandAllAction;

+    private Schema schema;
+
public OLAPTree(ArchitectSwingSession session, OLAPEditSession oSession, Schema schema) {
+        this.schema = schema;
         setModel(new OLAPTreeModel(schema));
         addMouseListener(new PopupListener());
collapseAllAction = new JTreeCollapseAllAction(this, "Collapse All");
@@ -102,4 +114,50 @@
             }
         }
     }
+
+    /**
+ * Returns the TreePath built from the getParent() of the given OLAPObject.
+     *
+     * @param obj OLAPObject to build TreePath upon.
+     * @return TreePath for given object.
+     */
+    public TreePath getTreePathForNode(OLAPObject o) {
+        List<OLAPObject> path = new ArrayList<OLAPObject>();
+        while (o != null) {
+            path.add(0, o);
+            if (o == schema) break;
+            o = o.getParent();
+        }
+        return new TreePath(path.toArray());
+    }
+
+    /**
+ * Removes all selections of objects that are not represented on the playpen.
+     *
+     */
+    public void clearNonPlayPenSelections() {
+        if (getSelectionPaths() == null) return;
+        for (TreePath tp : getSelectionPaths()) {
+            OLAPObject obj = (OLAPObject) tp.getLastPathComponent();
+ if (!(obj instanceof Cube || obj instanceof VirtualCube || obj instanceof Measure + || obj instanceof CubeDimension || obj instanceof VirtualCubeMeasure
+                    || obj instanceof Level || obj instanceof Hierarchy)) {
+                removeSelectionPath(tp);
+            }
+        }
+    }
+
+    /**
+     * Checks to see if the Schema reference from the the OLAPTree is the
+ * same as the one held by the PlayPen. If it is, we are looking at the
+     * Schema.
+     */
+    protected boolean isSchemaNode(TreePath tp) {
+        if (tp == null) {
+            return false;
+        } else {
+            return schema == tp.getLastPathComponent();
+        }
+    }
+
 }

Reply via email to