Author: jfuerth
Date: Tue Aug 26 15:56:41 2008
New Revision: 2617

Modified:
   trunk/regress/ca/sqlpower/architect/swingui/TestAutoLayoutAction.java
   trunk/src/ca/sqlpower/architect/swingui/ArchitectFrame.java
   trunk/src/ca/sqlpower/architect/swingui/ContainerPane.java
   trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java
   trunk/src/ca/sqlpower/architect/swingui/TablePane.java
   trunk/src/ca/sqlpower/architect/swingui/action/AutoLayoutAction.java
   trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java
   trunk/src/ca/sqlpower/architect/swingui/olap/OLAPEditSession.java
   trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPane.java
   trunk/src/ca/sqlpower/architect/swingui/olap/UsageComponent.java
   trunk/src/ca/sqlpower/architect/swingui/olap/VirtualCubePane.java

Log:
Implemented auto layout for OLAP playpens. This required changing the AutoLayoutAction's constructor so you pass in the specific play pen it's supposed to lay out.

Modified: trunk/regress/ca/sqlpower/architect/swingui/TestAutoLayoutAction.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/swingui/TestAutoLayoutAction.java (original) +++ trunk/regress/ca/sqlpower/architect/swingui/TestAutoLayoutAction.java Tue Aug 26 15:56:41 2008
@@ -45,7 +45,7 @@
TestingArchitectSwingSessionContext context = new TestingArchitectSwingSessionContext();
                ArchitectSwingSession session = context.createSession();
         PlayPen pp = session.getPlayPen();
- layoutAction = new AutoLayoutAction(session, "Tree Layout", "Basic tree layout", "auto_layout"); + layoutAction = new AutoLayoutAction(session, session.getPlayPen(), "Tree Layout", "Basic tree layout", "auto_layout");
                layout = new BasicTreeAutoLayout();
                pp.repaint();
                //action = af.getAutoLayoutAction();

Modified: trunk/src/ca/sqlpower/architect/swingui/ArchitectFrame.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/ArchitectFrame.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/ArchitectFrame.java Tue Aug 26 15:56:41 2008
@@ -374,7 +374,7 @@

         undoAction = new UndoAction(session, session.getUndoManager());
         redoAction = new RedoAction(session, session.getUndoManager());
- autoLayoutAction = new AutoLayoutAction(session, Messages.getString("ArchitectFrame.autoLayoutActionName"), Messages.getString("ArchitectFrame.autoLayoutActionDescription"), "auto_layout"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + autoLayoutAction = new AutoLayoutAction(session, session.getPlayPen(), Messages.getString("ArchitectFrame.autoLayoutActionName"), Messages.getString("ArchitectFrame.autoLayoutActionDescription"), "auto_layout"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
         autoLayout = new FruchtermanReingoldForceLayout();
         autoLayoutAction.setLayout(autoLayout);
         exportDDLAction = new ExportDDLAction(session);

Modified: trunk/src/ca/sqlpower/architect/swingui/ContainerPane.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/ContainerPane.java  (original)
+++ trunk/src/ca/sqlpower/architect/swingui/ContainerPane.java Tue Aug 26 15:56:41 2008
@@ -46,6 +46,7 @@

 import org.apache.log4j.Logger;

+import ca.sqlpower.architect.layout.LayoutNode;
 import ca.sqlpower.architect.swingui.PlayPen.FloatingContainerPaneListener;
 import ca.sqlpower.architect.swingui.PlayPen.MouseModeType;
 import ca.sqlpower.architect.swingui.event.ItemSelectionEvent;
@@ -60,7 +61,7 @@
  */
 public abstract class ContainerPane<T extends Object, C extends Object>
 extends PlayPenComponent
-implements DragSourceListener {
+implements DragSourceListener, LayoutNode {

     /**
      * A special item index that represents the titlebar area.
@@ -564,4 +565,12 @@
      * If there is nothing transferable selected, returns null.
      */
     public abstract Transferable createTransferableForSelection();
+
+
+    /**
+ * Simple implementation for LayoutNode interface. Simply calls getName().
+     */
+    public String getNodeName() {
+        return getName();
+    }
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java Tue Aug 26 15:56:41 2008
@@ -102,6 +102,7 @@
             AutoLayoutAction layoutAction =
                 new AutoLayoutAction(
                         session,
+                        session.getPlayPen(),
Messages.getString("PlayPen.straightenLinesActionName"), //$NON-NLS-1$ Messages.getString("PlayPen.straightenLinesActionDescription"), //$NON-NLS-1$
                         icon);

Modified: trunk/src/ca/sqlpower/architect/swingui/TablePane.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/TablePane.java      (original)
+++ trunk/src/ca/sqlpower/architect/swingui/TablePane.java Tue Aug 26 15:56:41 2008
@@ -64,12 +64,11 @@
 import ca.sqlpower.architect.SQLRelationship;
 import ca.sqlpower.architect.SQLTable;
 import ca.sqlpower.architect.layout.LayoutEdge;
-import ca.sqlpower.architect.layout.LayoutNode;
 import ca.sqlpower.architect.swingui.action.EditSpecificIndexAction;
 import ca.sqlpower.swingui.ColorIcon;
 import ca.sqlpower.swingui.SPSUtils;

-public class TablePane extends ContainerPane<SQLTable, SQLColumn> implements LayoutNode {
+public class TablePane extends ContainerPane<SQLTable, SQLColumn> {

        private static final Logger logger = Logger.getLogger(TablePane.class);

@@ -827,13 +826,6 @@
      */
     public boolean canImport(JComponent c, DataFlavor[] flavors) {
         return bestImportFlavor(c, flavors) != null;
-    }
-
-
- // ------- LayoutNode methods that we didn't already happen to implement --------
-
-    public String getNodeName() {
-        return getName();
     }

     public List<LayoutEdge> getInboundEdges() {

Modified: trunk/src/ca/sqlpower/architect/swingui/action/AutoLayoutAction.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/action/AutoLayoutAction.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/action/AutoLayoutAction.java Tue Aug 26 15:56:41 2008
@@ -35,7 +35,7 @@
 import ca.sqlpower.architect.swingui.ContainerPane;
 import ca.sqlpower.architect.swingui.LayoutAnimator;
 import ca.sqlpower.architect.swingui.PlayPen;
-import ca.sqlpower.architect.swingui.TablePane;
+import ca.sqlpower.architect.swingui.PlayPenComponent;

 public class AutoLayoutAction extends AbstractArchitectAction {
private static final Logger logger = Logger.getLogger(AutoLayoutAction.class);
@@ -46,16 +46,18 @@

        private int framesPerSecond = 25;

- public AutoLayoutAction(ArchitectSwingSession session, String name, String description, String iconResourceName) {
-        super(session, name, description, iconResourceName);
+ public AutoLayoutAction(ArchitectSwingSession session, PlayPen playPen, String name, String description, String iconResourceName) {
+        super(session, playPen, name, description, iconResourceName);
     }

- public AutoLayoutAction(ArchitectSwingSession session, String name, String description, Icon icon) {
-        super(session, name, description, icon);
+ public AutoLayoutAction(ArchitectSwingSession session, PlayPen playPen, String name, String description, Icon icon) {
+        super(session, playPen, name, description, icon);
     }

        public void actionPerformed(ActionEvent evt) {

+           logger.debug("Auto layout action starting...");
+       
         // This funny construction creates a new instance of the current
         // type of layout.  It would be better to ask client code for a
         // layout factory, then use the factory to make new instances for
@@ -67,43 +69,64 @@
             throw new RuntimeException(e);
         }

- // ok, if it's broken, let's just fail silently and pretend the user missed the button. (that was sarcasm)
-               if (layout != null) {
-                       List<? extends LayoutNode> tablePanes = new 
ArrayList<TablePane>();
- for (ContainerPane<?, ?> cp : getPlayPen().getSelectedContainers()) {
-                   if (cp instanceof TablePane) {
-                       ((List<TablePane>) tablePanes).add((TablePane) cp);
-                   }
-               }
- List<LayoutNode> notLaidOut = new ArrayList<LayoutNode>(playpen.getTablePanes());
-            notLaidOut.removeAll(tablePanes);
-                       Point layoutAreaOffset = new Point();
-                       if (tablePanes.size() == 0 || tablePanes.size() == 1) {
-                               tablePanes = playpen.getTablePanes();
-                       } else if (tablePanes.size() != 
playpen.getTablePanes().size()){
-                               int maxWidth =0;
-                               for (LayoutNode tp : notLaidOut){
-                                       int width = tp.getWidth()+tp.getX();
-                                       if (width > maxWidth) {
-                                               maxWidth = width;
-                                       }
-                               }
-                               layoutAreaOffset = new Point(maxWidth,0);
-                       }
-
-                       List<? extends LayoutEdge> relationships = 
playpen.getRelationships();
- logger.debug("About to do layout. tablePanes="+tablePanes); //$NON-NLS-1$ - logger.debug("About to do layout. relationships="+relationships); //$NON-NLS-1$
-
-
- Rectangle layoutArea = new Rectangle(layoutAreaOffset, layout.getNewArea(tablePanes));
-                       layout.setup(tablePanes, relationships, layoutArea);
-            LayoutAnimator anim = new LayoutAnimator(playpen, layout);
-            anim.setAnimationEnabled(animationEnabled);
-            anim.setFramesPerSecond(framesPerSecond);
-                       anim.startAnimation();
-               }
+        logger.debug("Created new Layout instance: " + layout);
+
+        List<LayoutNode> nodes = new ArrayList<LayoutNode>();
+ for (ContainerPane<?, ?> cp : getPlayPen().getSelectedContainers()) {
+            if (cp instanceof LayoutNode) {
+                nodes.add((LayoutNode) cp);
+            }
+        }
+
+ // XXX the following block of code is a bit disturbing. Needs refactoring after we figure out what it's supposed to do.
+        List<LayoutNode> notLaidOut = extractLayoutNodes(playpen);
+        notLaidOut.removeAll(nodes);
+        Point layoutAreaOffset = new Point();
+        if (nodes.size() == 0 || nodes.size() == 1) {
+            nodes = extractLayoutNodes(playpen);
+        } else if (nodes.size() != extractLayoutNodes(playpen).size()){
+            int maxWidth = 0;
+            for (LayoutNode tp : notLaidOut) {
+                int width = tp.getWidth() + tp.getX();
+                if (width > maxWidth) {
+                    maxWidth = width;
+                }
+            }
+            layoutAreaOffset = new Point(maxWidth,0);
+        }
+
+        List<LayoutEdge> edges = extractLayoutEdges(playpen);
+        logger.debug("About to do layout. nodes=" + nodes); //$NON-NLS-1$
+        logger.debug("About to do layout. edges=" + edges); //$NON-NLS-1$
+
+
+ Rectangle layoutArea = new Rectangle(layoutAreaOffset, layout.getNewArea(nodes));
+        layout.setup(nodes, edges, layoutArea);
+        LayoutAnimator anim = new LayoutAnimator(playpen, layout);
+        anim.setAnimationEnabled(animationEnabled);
+        anim.setFramesPerSecond(framesPerSecond);
+        anim.startAnimation();
        }
+
+    private static List<LayoutNode> extractLayoutNodes(PlayPen pp) {
+        List<LayoutNode> nodes = new ArrayList<LayoutNode>();
+        for (PlayPenComponent ppc : pp.getPlayPenComponents()) {
+            if (ppc instanceof LayoutNode) {
+                nodes.add((LayoutNode) ppc);
+            }
+        }
+        return nodes;
+    }
+
+    private static List<LayoutEdge> extractLayoutEdges(PlayPen pp) {
+        List<LayoutEdge> edges = new ArrayList<LayoutEdge>();
+        for (PlayPenComponent ppc : pp.getPlayPenComponents()) {
+            if (ppc instanceof LayoutEdge) {
+                edges.add((LayoutEdge) ppc);
+            }
+        }
+        return edges;
+    }

        public boolean isAnimationEnabled() {
                return animationEnabled;

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java  (original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java Tue Aug 26 15:56:41 2008
@@ -38,6 +38,7 @@

 public class CubePane extends OLAPPane<Cube, OLAPObject> {

+    @SuppressWarnings("unused")
     private static final Logger logger = Logger.getLogger(CubePane.class);

     public CubePane(Cube model, PlayPenContentPane parent) {

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 Tue Aug 26 15:56:41 2008
@@ -30,6 +30,7 @@
 import javax.swing.JSplitPane;
 import javax.swing.JToolBar;

+import ca.sqlpower.architect.layout.FruchtermanReingoldForceLayout;
 import ca.sqlpower.architect.olap.OLAPChildEvent;
 import ca.sqlpower.architect.olap.OLAPChildListener;
 import ca.sqlpower.architect.olap.OLAPSession;
@@ -37,6 +38,7 @@
 import ca.sqlpower.architect.swingui.ArchitectSwingSession;
 import ca.sqlpower.architect.swingui.Messages;
 import ca.sqlpower.architect.swingui.PlayPen;
+import ca.sqlpower.architect.swingui.action.AutoLayoutAction;
 import ca.sqlpower.architect.swingui.action.ZoomAction;
 import ca.sqlpower.architect.swingui.action.ZoomResetAction;
 import ca.sqlpower.architect.swingui.action.ZoomToFitAction;
@@ -91,9 +93,11 @@
     private CreateCubeUsageAction createCubeUsageAction;
     private ExportSchemaAction exportSchemaAction;
     private OLAPDeleteSelectedAction olapDeleteSelectedAction;
+    private AutoLayoutAction autoLayoutAction;

     private final ArchitectSwingSession swingSession;

+

     /**
* Creates a new editor for the given OLAP schema. The schema's OLAPObjects should
@@ -116,6 +120,8 @@
         tree = new OLAPTree(swingSession, this, olapSession.getSchema());
         tree.setCellRenderer(new OLAPTreeCellRenderer());
         pp = OLAPPlayPenFactory.createPlayPen(swingSession, this);
+
+        // Don't create actions here. PlayPen is currently null.
     }

     /**
@@ -150,7 +156,9 @@
createCubeUsageAction = new CreateCubeUsageAction(swingSession, pp);
         exportSchemaAction = new ExportSchemaAction(swingSession, schema);
olapDeleteSelectedAction = new OLAPDeleteSelectedAction(swingSession, this);
-
+ autoLayoutAction = new AutoLayoutAction(swingSession, pp, "Automatic Layout", "Automatic Layout", "auto_layout"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        autoLayoutAction.setLayout(new FruchtermanReingoldForceLayout());
+
         JToolBar toolbar = new JToolBar(JToolBar.VERTICAL);
         toolbar.add(zoomInAction);
         toolbar.add(zoomOutAction);
@@ -158,7 +166,11 @@
         toolbar.add(zoomToFitAction);

         toolbar.addSeparator();
-
+
+        toolbar.add(autoLayoutAction);
+
+        toolbar.addSeparator();
+
         toolbar.add(createDimensionAction);
         toolbar.add(createCubeAction);
         toolbar.add(createVirtualCubeAction);
@@ -261,6 +273,10 @@

     public OLAPDeleteSelectedAction getOLAPDeleteSelectedAction() {
         return olapDeleteSelectedAction;
+    }
+
+    public AutoLayoutAction getAutoLayoutAction() {
+        return autoLayoutAction;
     }

     // ------ OLAPChildListener methods ------ //

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:56:41 2008
@@ -45,12 +45,14 @@
 import org.apache.log4j.Logger;

 import ca.sqlpower.architect.ArchitectException;
+import ca.sqlpower.architect.layout.LayoutEdge;
 import ca.sqlpower.architect.olap.OLAPObject;
 import ca.sqlpower.architect.olap.OLAPUtil;
 import ca.sqlpower.architect.olap.MondrianModel.Schema;
 import ca.sqlpower.architect.swingui.ASUtils;
 import ca.sqlpower.architect.swingui.ContainerPane;
 import ca.sqlpower.architect.swingui.PlayPen;
+import ca.sqlpower.architect.swingui.PlayPenComponent;
 import ca.sqlpower.architect.swingui.PlayPenContentPane;
 import ca.sqlpower.architect.swingui.PlayPenCoordinate;
 import ca.sqlpower.architect.swingui.PlayPen.FloatingContainerPaneListener;
@@ -599,4 +601,42 @@
         return insertionPoint;
     }

+    /**
+     * Returns all the UsageComponents in the play pen that this pane
+     * is the "pane2" for. This is part of the LayoutNode interface.
+     */
+    public final List<LayoutEdge> getInboundEdges() {
+        List<LayoutEdge> edges = new ArrayList<LayoutEdge>();
+
+        for (PlayPenComponent ppc : getPlayPen().getPlayPenComponents()) {
+            if (ppc instanceof UsageComponent) {
+                UsageComponent uc = (UsageComponent) ppc;
+                if (uc.getPane2() == this) {
+                    edges.add(uc);
+                }
+            }
+        }
+
+        return edges;
+    }
+
+    /**
+     * Returns all the UsageComponents in the play pen that this pane
+     * is the "pane1" for. This is part of the LayoutNode interface.
+     */
+    public final List<LayoutEdge> getOutboundEdges() {
+        List<LayoutEdge> edges = new ArrayList<LayoutEdge>();
+
+        for (PlayPenComponent ppc : getPlayPen().getPlayPenComponents()) {
+            if (ppc instanceof UsageComponent) {
+                UsageComponent uc = (UsageComponent) ppc;
+                if (uc.getPane1() == this) {
+                    edges.add(uc);
+                }
+            }
+        }
+
+        return edges;
+    }
+
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/UsageComponent.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/UsageComponent.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/olap/UsageComponent.java Tue Aug 26 15:56:41 2008
@@ -22,6 +22,8 @@
 import java.awt.Color;
 import java.awt.event.MouseEvent;

+import ca.sqlpower.architect.layout.LayoutEdge;
+import ca.sqlpower.architect.layout.LayoutNode;
 import ca.sqlpower.architect.olap.OLAPObject;
 import ca.sqlpower.architect.swingui.PlayPen;
 import ca.sqlpower.architect.swingui.PlayPenComponent;
@@ -34,7 +36,7 @@
* A component that visually indicates a usage of one olap pane by another. For example,
  * a dimension usage or a cube usage.
  */
-public class UsageComponent extends PlayPenComponent {
+public class UsageComponent extends PlayPenComponent implements LayoutEdge {

     private final OLAPObject model;
     private final OLAPPane<?, ?> pane1;
@@ -125,5 +127,13 @@
                 getPlayPen().getContentPane().remove(UsageComponent.this);
             }
         }
+    }
+
+    public LayoutNode getHeadNode() {
+        return pane2;
+    }
+
+    public LayoutNode getTailNode() {
+        return pane1;
     }
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/VirtualCubePane.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/VirtualCubePane.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/olap/VirtualCubePane.java Tue Aug 26 15:56:41 2008
@@ -133,4 +133,5 @@
         }
         return filtered;
     }
+
 }

Reply via email to