Author: jfuerth
Date: Mon Aug 25 16:01:10 2008
New Revision: 2606

Added:
trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPaneSection.java (contents, props changed) - copied, changed from r2604, /trunk/src/ca/sqlpower/architect/swingui/olap/PaneSectionImpl.java
Removed:
   trunk/src/ca/sqlpower/architect/swingui/olap/PaneSectionImpl.java
Modified:
   trunk/src/ca/sqlpower/architect/swingui/BasicTablePaneUI.java
   trunk/src/ca/sqlpower/architect/swingui/ContainerPaneUI.java
   trunk/src/ca/sqlpower/architect/swingui/PlayPenCoordinate.java
   trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java
   trunk/src/ca/sqlpower/architect/swingui/olap/DimensionPane.java
   trunk/src/ca/sqlpower/architect/swingui/olap/DnDOLAPTransferable.java
   trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPane.java
   trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPaneUI.java
   trunk/src/ca/sqlpower/architect/swingui/olap/PaneSection.java
   trunk/src/ca/sqlpower/architect/swingui/olap/VirtualCubePane.java

Log:
Further drag'n'drop fun: Now all OLAPPanes support drop of the appropriate item type, semi-magically.

This required us to make an addItem method in PaneSection, so PaneSectionImpl is now abstract and has been renamed to OLAPPaneSection. All uses of the former PaneSectionImpl now support adding items.

There is one known problem with this version: if you drag something into the empty space at the bottom of a single-item pane, you get an exception. We'll look into this tomorrow.

Modified: trunk/src/ca/sqlpower/architect/swingui/BasicTablePaneUI.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/BasicTablePaneUI.java       
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/BasicTablePaneUI.java Mon Aug 25 16:01:10 2008
@@ -266,11 +266,7 @@
                            } else {
                                    y += ip * fontHeight + PK_GAP;
                                }
-                               g2.drawLine(5, y, width - 6, y);
-                               g2.drawLine(2, y-3, 5, y);
-                               g2.drawLine(2, y+3, 5, y);
-                               g2.drawLine(width - 3, y-3, width - 6, y);
-                               g2.drawLine(width - 3, y+3, width - 6, y);
+                           paintInsertionPoint(g2, y, width);
                        }
                        
                        g.translate(-insets.left, -insets.top);

Modified: trunk/src/ca/sqlpower/architect/swingui/ContainerPaneUI.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/ContainerPaneUI.java        
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/ContainerPaneUI.java Mon Aug 25 16:01:10 2008
@@ -19,6 +19,7 @@

 package ca.sqlpower.architect.swingui;

+import java.awt.Graphics2D;
 import java.awt.Point;
 import java.io.Serializable;

@@ -34,4 +35,11 @@
     @Deprecated
     public abstract int pointToItemIndex(Point p);

+    protected void paintInsertionPoint(Graphics2D g2, int y, int width) {
+        g2.drawLine(5, y, width - 6, y);
+        g2.drawLine(2, y-3, 5, y);
+        g2.drawLine(2, y+3, 5, y);
+        g2.drawLine(width - 3, y-3, width - 6, y);
+        g2.drawLine(width - 3, y+3, width - 6, y);
+    }
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/PlayPenCoordinate.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/PlayPenCoordinate.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/PlayPenCoordinate.java Mon Aug 25 16:01:10 2008
@@ -54,7 +54,7 @@
     /**
      * The section of the represented location.
      */
-    private final PaneSection<I> section;
+    private final PaneSection<? extends I> section;

     /**
      * The item of the represented location.
@@ -66,7 +66,7 @@
      */
     private final int index;

- public PlayPenCoordinate(OLAPPane<T, I> pane, PaneSection<I> section, int index, I item) { + public PlayPenCoordinate(OLAPPane<T, I> pane, PaneSection<? extends I> section, int index, I item) {
         this.pane = pane;
         this.section = section;
         this.index = index;
@@ -77,7 +77,7 @@
         return pane;
     }

-    public PaneSection<I> getSection() {
+    public PaneSection<? extends I> getSection() {
         return section;
     }


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 Mon Aug 25 16:01:10 2008
@@ -19,11 +19,15 @@

 package ca.sqlpower.architect.swingui.olap;

+import java.util.ArrayList;
 import java.util.List;

+import org.apache.log4j.Logger;
+
 import ca.sqlpower.architect.ArchitectException;
 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.Dimension;
 import ca.sqlpower.architect.olap.MondrianModel.DimensionUsage;
 import ca.sqlpower.architect.olap.MondrianModel.Measure;
@@ -34,11 +38,27 @@

 public class CubePane extends OLAPPane<Cube, OLAPObject> {

+    private static final Logger logger = Logger.getLogger(CubePane.class);
+
     public CubePane(Cube model, PlayPenContentPane parent) {
         super(parent);
         this.model = model;
- PaneSection<OLAPObject> dimensionSection = new PaneSectionImpl(model.getDimensions(), "Dimensions:"); - PaneSection<OLAPObject> measureSection = new PaneSectionImpl(model.getMeasures(), "Measures:");
+
+        PaneSection<CubeDimension> dimensionSection =
+ new OLAPPaneSection<CubeDimension>(CubeDimension.class, model.getDimensions(), "Dimensions:") {
+
+            public void addItem(int idx, CubeDimension item) {
+                CubePane.this.model.addDimension(idx, item);
+            }
+        };
+
+ PaneSection<Measure> measureSection = new OLAPPaneSection<Measure>(Measure.class, model.getMeasures(), "Measures:") {
+
+            public void addItem(int idx, Measure item) {
+                CubePane.this.model.addMeasure(idx, item);
+            }
+        };
+
         sections.add(dimensionSection);
         sections.add(measureSection);
         updateUI();
@@ -85,6 +105,16 @@

         return panel;
     }
-
+
+    @Override
+ protected List<OLAPObject> filterDroppableItems(List<OLAPObject> items) {
+        List<OLAPObject> filtered = new ArrayList<OLAPObject>();
+        for (OLAPObject item : items) {
+            if (item instanceof Measure || item instanceof Dimension) {
+                filtered.add(item);
+            }
+        }
+        return filtered;
+    }

 }

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 Mon Aug 25 16:01:10 2008
@@ -25,6 +25,7 @@
 import ca.sqlpower.architect.ArchitectException;
 import ca.sqlpower.architect.olap.OLAPChildEvent;
 import ca.sqlpower.architect.olap.OLAPChildListener;
+import ca.sqlpower.architect.olap.OLAPObject;
 import ca.sqlpower.architect.olap.MondrianModel.Dimension;
 import ca.sqlpower.architect.olap.MondrianModel.Hierarchy;
 import ca.sqlpower.architect.olap.MondrianModel.Level;
@@ -77,6 +78,18 @@
             return hierarchy;
         }

+        public Class<Level> getItemType() {
+            return Level.class;
+        }
+
+        public void addItem(int idx, Level item) {
+            hierarchy.addLevel(idx, item);
+        }
+
+        public void addItem(Level item) {
+            addItem(getItems().size(), item);
+        }
+
     }

private final HierarchyWatcher hierarchyWatcher = new HierarchyWatcher();
@@ -138,5 +151,16 @@
         }

         return panel;
+    }
+
+    @Override
+    protected List<Level> filterDroppableItems(List<OLAPObject> items) {
+        List<Level> filtered = new ArrayList<Level>();
+        for (OLAPObject item : items) {
+            if (item instanceof Level) {
+                filtered.add((Level) item);
+            }
+        }
+        return filtered;
     }
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/DnDOLAPTransferable.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/DnDOLAPTransferable.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/olap/DnDOLAPTransferable.java Mon Aug 25 16:01:10 2008
@@ -126,7 +126,7 @@
                int itemIndex = coord.get(2);
OLAPPane<OLAPObject,OLAPObject> ppc = (OLAPPane<OLAPObject,OLAPObject>)
                        pp.getPlayPenContentPane().getComponent(paneIndex);
-               PaneSection<OLAPObject> s = ppc.getSections().get(sectIndex);
+ PaneSection<? extends OLAPObject> s = ppc.getSections().get(sectIndex);
                OLAPObject item;
                if (itemIndex >= 0) {
                    item = s.getItems().get(itemIndex);

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 Mon Aug 25 16:01:10 2008
@@ -44,7 +44,8 @@

 import ca.sqlpower.architect.ArchitectException;
 import ca.sqlpower.architect.olap.OLAPObject;
-import ca.sqlpower.architect.olap.MondrianModel.Measure;
+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;
@@ -72,12 +73,12 @@
* The set of sections is allowed to change at any time, but an appropriate
      * event will be fired when it does change.
      */
- protected final List<PaneSection<C>> sections = new ArrayList<PaneSection<C>>(); + protected final List<PaneSection<? extends C>> sections = new ArrayList<PaneSection<? extends C>>();

     /**
      * Tracks which scetions in this container are currently selected.
      */
- protected final Set<PaneSection<C>> selectedSections = new HashSet<PaneSection<C>>(); + protected final Set<PaneSection<? extends C>> selectedSections = new HashSet<PaneSection<? extends C>>();

     /**
      * The point where a dropped item would be inserted if the drop were
@@ -94,7 +95,7 @@
     /**
      * Returns this pane's list of sections.
      */
-    public List<PaneSection<C>> getSections() {
+    public List<PaneSection<? extends C>> getSections() {
         return sections;
     }

@@ -278,7 +279,7 @@
      * Selects the section.
      *
      */
-    public void selectSection(PaneSection<C> sect) {
+    public void selectSection(PaneSection<? extends C> sect) {
         selectedSections.add(sect);
         repaint();
     }
@@ -290,7 +291,7 @@
      *            The section to check
      * @return true if section is currently selected.
      */
-    public boolean isSectionSelected(PaneSection<C> sect) {
+    public boolean isSectionSelected(PaneSection<? extends C> sect) {
         return selectedSections.contains(sect);
     }

@@ -298,9 +299,9 @@
* Returns a list of the sections that are currently in the selection that
      * also currently exist in the model.
      */
-    public List<PaneSection<C>> getSelectedSections() {
- List<PaneSection<C>> selectedSects = new ArrayList<PaneSection<C>>();
-        for (PaneSection<C> sect : getSections()) {
+    public List<PaneSection<? extends C>> getSelectedSections() {
+ List<PaneSection<? extends C>> selectedSects = new ArrayList<PaneSection<? extends C>>();
+        for (PaneSection<? extends C> sect : getSections()) {
             if (isSectionSelected(sect)) {
                 selectedSects.add(sect);
             }
@@ -318,7 +319,7 @@
      */
     public List<PlayPenCoordinate<T, C>> getSelectedCoordinates() {
List<PlayPenCoordinate<T, C>> selection = new ArrayList<PlayPenCoordinate<T,C>>();
-        for (PaneSection<C> sect : getSections()) {
+        for (PaneSection<? extends C> sect : getSections()) {
             if (isSectionSelected(sect)) {
                 selection.add(new PlayPenCoordinate<T, C>(
this, sect, PlayPenCoordinate.ITEM_INDEX_SECTION_TITLE, null));
@@ -434,7 +435,9 @@
      */
     public void drop(DropTargetDropEvent dtde) {
logger.debug("Drop target drop event on "+getName()+": "+dtde); //$NON-NLS-1$ //$NON-NLS-2$
+        Schema schema = OLAPUtil.getSession(getModel()).getSchema();
         try {
+            schema.startCompoundEdit("Drag and Drop");
             Transferable t = dtde.getTransferable();
DataFlavor importFlavor = bestImportFlavor(null, t.getTransferDataFlavors());
             logger.debug("Import flavor: " + importFlavor);
@@ -444,26 +447,105 @@
             }
List<List<Integer>> paths = (List<List<Integer>>) t.getTransferData(importFlavor);
             logger.debug("Paths = " + paths);
- List<PlayPenCoordinate<? extends OLAPObject, ? extends OLAPObject>> items = + List<PlayPenCoordinate<? extends OLAPObject, ? extends OLAPObject>> coords =
                 DnDOLAPTransferable.resolve(getPlayPen(), paths);
-            logger.debug("Resolved Paths = " + items);
-            boolean accepted = false;
- for (PlayPenCoordinate<? extends OLAPObject, ? extends OLAPObject> ppco : items) {
-                if (ppco.getItem() instanceof Measure) {
- logger.debug("Trying to add measure " + ppco.getItem()); - // TODO offer this to the OLAPPane subclass via abstract method
-                    getModel().addChild(ppco.getItem());
-                    accepted = true;
+            logger.debug("Resolved Paths = " + coords);
+            List<OLAPObject> items = new ArrayList<OLAPObject>();
+ for (PlayPenCoordinate<? extends OLAPObject, ? extends OLAPObject> coord : coords) { + if (coord.getIndex() == PlayPenCoordinate.ITEM_INDEX_SECTION_TITLE) {
+                    for (OLAPObject item : coord.getSection().getItems()) {
+                        items.add(item);
+                    }
+                } else if (coord.getIndex() >= 0) {
+                    if (coord.getItem() == null) {
+                        throw new NullPointerException(
+                                "Found a coordinate with nonnegative " +
+                                "item index but null item: " + coord);
+                    }
+                    items.add(coord.getItem());
                 }
             }
+
+            List<C> acceptedItems = filterDroppableItems(items);
+
+ // XXX we don't want to weaken the type here (PaneSection<C> would be better)
+            // but without this, the whole thing collapses
+ PaneSection<OLAPObject> insertSection = (PaneSection<OLAPObject>) getInsertionPoint().getSection();
+            int insertIndex = getInsertionPoint().getIndex();
+
+            if (insertSection == null) {
+                insertSection = (PaneSection<OLAPObject>) sections.get(0);
+                insertIndex = insertSection.getItems().size();
+            }
+
+            for (C item : acceptedItems) {
+                logger.debug("Trying to add " + item);
+                if (item.getParent() != null) {
+
+                    /*
+ * this is the index of the item we want to move, in the + * section we plan to move it _to_. This is only relevant + * when moving an item to a new place it the same section. + * If this DnD operation is from one section to a different + * section, removedItemIndex will be -1, which is expected
+                     * and handled properly below.
+                     *
+ * Why all the fuss? If you are moving an item down within + * the section it came from, the insertion point's index + * has to be adjusted to account for the subsequent items
+                     * shifting up to take the place of the removed item.
+                     */
+ int removedItemIndex = insertSection.getItems().indexOf(item); + logger.debug("Removed item index in target section: " + removedItemIndex);
+
+                    item.getParent().removeChild(item);
+
+                    if (removedItemIndex >= 0 &&
+                            insertSection.getItemType().isInstance(item) &&
+                            insertIndex > removedItemIndex) {
+                        insertIndex--;
+                    }
+                }
+
+ if (insertIndex >= 0 && insertSection.getItemType().isInstance(item)) {
+                    insertSection.addItem(insertIndex++, item);
+                } else {
+                    getModel().addChild(item);
+                }
+            }
+
+            if (!acceptedItems.isEmpty()) {
+                getPlayPen().selectNone();
+                setSelected(true, SelectionEvent.SINGLE_SELECT);
+                for (C item : acceptedItems) {
+                    selectItem(item);
+                }
+            }
+
             dtde.acceptDrop(DnDConstants.ACTION_MOVE);
-            dtde.dropComplete(accepted);
+            dtde.dropComplete(!acceptedItems.isEmpty());
         } catch (Exception e) {
             throw new RuntimeException(e);
         } finally {
             setInsertionPoint(null);
+            schema.endCompoundEdit();
         }
     }
+
+    /**
+ * Accepts a clump of items that have been dragged from elsewhere (normally + * the tree or another pane). Implementations of this method are free to
+     * pick and choose which items to import.
+     * <p>
+ * This method will always be called by the superclass in the context of a
+     * compound edit on the schema this pane's model belongs to.
+     *
+     * @param items
+     *            The items that were dropped.
+ * @return The list of items that can be dropped on this pane. It will be
+     *         some subset of the given list of items.
+     */
+ protected abstract List<C> filterDroppableItems(List<OLAPObject> items);

     /**
      * Called if the user has modified the current drop gesture.

Copied: trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPaneSection.java (from r2604, /trunk/src/ca/sqlpower/architect/swingui/olap/PaneSectionImpl.java)
==============================================================================
--- /trunk/src/ca/sqlpower/architect/swingui/olap/PaneSectionImpl.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPaneSection.java Mon Aug 25 16:01:10 2008
@@ -24,13 +24,15 @@
 /**
  * Generic implementation of a pane section. Should suffice for most uses.
  */
-public class PaneSectionImpl<C> implements PaneSection<C> {
+public abstract class OLAPPaneSection<C> implements PaneSection<C> {

     private final List<C> items;
     private final String title;
+    private final Class<C> type;

-    public PaneSectionImpl(List<C> items, String title) {
+    public OLAPPaneSection(Class<C> type, List<C> items, String title) {
         super();
+        this.type = type;
         this.items = items;
         this.title = title;
     }
@@ -52,6 +54,17 @@
         return title;
     }

+    public Class<C> getItemType() {
+        return type;
+    }
+
+    /**
+     * Calls addItem(getItems().size(), item).
+     */
+    public void addItem(C item) {
+        addItem(getItems().size(), item);
+    }
+
     @Override
     public String toString() {
         return getTitle();

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPaneUI.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPaneUI.java        
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/OLAPPaneUI.java Mon Aug 25 16:01:10 2008
@@ -125,7 +125,7 @@
         int fontHeight = metrics.getHeight();

         height += fontHeight + GAP + BOX_LINE_THICKNESS;
-        for (PaneSection<C> ps : olapPane.getSections()) {
+        for (PaneSection<? extends C> ps : olapPane.getSections()) {
             if (ps.getTitle() != null) {
                 height += fontHeight + SECTION_HEADER_GAP;
             }
@@ -146,7 +146,7 @@
         // Width calculation
         width = MINIMUM_WIDTH;
         width = Math.max(width, calculateTextWidth(cp, cp.getName()));
-        for (PaneSection<C> ps : olapPane.getSections()) {
+        for (PaneSection<? extends C> ps : olapPane.getSections()) {
             width = Math.max(width, calculateMaxSectionWidth(ps, cp));
         }
         Insets insets = cp.getMargin();
@@ -240,7 +240,7 @@

         // Draw each of the individual sections of this container pane.
         boolean firstSection = true;
-        for(PaneSection<C> ps : olapPane.getSections()) {
+        for(PaneSection<? extends C> ps : olapPane.getSections()) {
             if (!firstSection) {
                 g2.drawLine(
0, y + (INTER_SECTION_GAP + fontHeight - ascent) / 2,
@@ -263,9 +263,6 @@

         g2.setStroke(oldStroke);

-        if (olapPane.getInsertionPoint() != null) {
-            g2.fill3DRect(10, 10, 30, 30, true);
-        }
     }

     public boolean contains(Point p) {
@@ -291,7 +288,7 @@
* @return The section the given point is located in, plus the passed-in
      *         point may have been translated.
      */
- public PaneSection<C> toSectionLocation(Point point, boolean editPoint) { + public PaneSection<? extends C> toSectionLocation(Point point, boolean editPoint) {
         Point p = editPoint ? point : new Point(point);

         Font font = olapPane.getFont();
@@ -311,7 +308,7 @@
logger.debug("SECLOC: looking through sections; translatedY="+translatedY);

         boolean firstSection = true;
-        for (PaneSection<C> sect : olapPane.getSections()) {
+        for (PaneSection<? extends C> sect : olapPane.getSections()) {
             int sectionHeight = fontHeight * sect.getItems().size();
             if (sect.getTitle() != null) {
                 sectionHeight += fontHeight + SECTION_HEADER_GAP;
@@ -349,7 +346,7 @@
                     "; descent = " + descent); //$NON-NLS-1$
         }

-        PaneSection<C> sect;
+        PaneSection<? extends C> sect;
         int returnVal;
         if (p.y < 0) {
             logger.debug("y<0"); //$NON-NLS-1$
@@ -411,7 +408,7 @@
                     "; descent = " + descent); //$NON-NLS-1$
         }

-        PaneSection<C> sect;
+        PaneSection<? extends C> sect;
         C item;
         int index;
         if (p.y < 0) {
@@ -472,9 +469,9 @@
      * @param sect A section in this pane.
      * @return
      */
-    public int firstItemIndex(PaneSection<C> sect) {
+    public int firstItemIndex(PaneSection<? extends C> sect) {
         int index = 0;
-        for (PaneSection<C> s : olapPane.getSections()) {
+        for (PaneSection<? extends C> s : olapPane.getSections()) {
             if (sect == s) {
                 return index;
             }
@@ -499,11 +496,16 @@
* @return The Y coordinate of the baseline of the last item drawn, relative to the
      *         component
      */
- private int drawSection(PaneSection<C> ps, Graphics2D g, OLAPPane<T, C> cp, final int startY) { + private int drawSection(PaneSection<? extends C> ps, Graphics2D g, OLAPPane<T, C> cp, final int startY) { + PlayPenCoordinate<T, C> insertionPoint = olapPane.getInsertionPoint();
+        if (insertionPoint == null || insertionPoint.getSection() != ps) {
+            insertionPoint = null;
+        }
int width = cp.getWidth() - cp.getInsets().left - cp.getInsets().right;
         FontMetrics metrics = cp.getFontMetrics(cp.getFont());
         int fontHeight = metrics.getHeight();
         int ascent = metrics.getAscent();
+        int insertionPointAdjustment = metrics.getDescent();

         int y = startY;

@@ -519,9 +521,16 @@
                         hwidth, fontHeight);
                 g.setColor(cp.getForegroundColor());
             }
+
g.drawString(ps.getTitle(), BOX_LINE_THICKNESS, y += fontHeight);
             y += SECTION_HEADER_GAP;
         }
+
+ // putting the insertion point above the section title looks dumb, so we do it here instead
+        if (insertionPoint != null &&
+ insertionPoint.getIndex() == PlayPenCoordinate.ITEM_INDEX_SECTION_TITLE) {
+            paintInsertionPoint(g, y + insertionPointAdjustment, hwidth);
+        }

         // print items
         int i = 0;
@@ -534,11 +543,24 @@
                         hwidth, fontHeight);
                 g.setColor(cp.getForegroundColor());
             }
+
+            if (insertionPoint != null &&
+                    insertionPoint.getIndex() == i) {
+ paintInsertionPoint(g, y + insertionPointAdjustment, hwidth);
+            }
+
             String itemName = OLAPUtil.nameFor(item);
g.drawString(itemName == null ? "(null)" : itemName, BOX_LINE_THICKNESS +
                     cp.getMargin().left, y += fontHeight);
             i++;
         }
+
+        // in case insertion point is after last item
+        if (insertionPoint != null &&
+                insertionPoint.getIndex() == i) {
+            paintInsertionPoint(g, y + insertionPointAdjustment, hwidth);
+        }
+
         return y;
     }

@@ -561,7 +583,7 @@
     /**
      * Calculates the width of a sectionPane.
      */
- private int calculateMaxSectionWidth(PaneSection<C> ps, ContainerPane<?, ?> cp) { + private int calculateMaxSectionWidth(PaneSection<? extends C> ps, ContainerPane<?, ?> cp) {
         int width = calculateTextWidth(cp, ps.getTitle());
         for (C oo : ps.getItems()) {
             if (oo == null) {

Modified: trunk/src/ca/sqlpower/architect/swingui/olap/PaneSection.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/PaneSection.java       
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/PaneSection.java Mon Aug 25 16:01:10 2008
@@ -38,4 +38,27 @@
* Returns the items in this section, in the order they should be displayed.
      */
     List<C> getItems();
+
+    /**
+     * Returns the type of items that appear in this section.
+     */
+    Class<C> getItemType();
+
+    /**
+     * Inserts the given item at the given index within this section.
+     *
+     * @param idx
+ * The index to add at. Must be between 0 and getItems().size()
+     *            inclusive.
+     * @param item
+     *            The item to add.
+     */
+    void addItem(int idx, C item);
+
+    /**
+     * Inserts the given item at the end of this section.
+     *
+     * @param item The item to add.
+     */
+    void addItem(C item);
 }

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 Mon Aug 25 16:01:10 2008
@@ -19,6 +19,7 @@

 package ca.sqlpower.architect.swingui.olap;

+import java.util.ArrayList;
 import java.util.List;

 import ca.sqlpower.architect.ArchitectException;
@@ -44,9 +45,27 @@
         if (model.getCubeUsage() == null) {
             model.setCubeUsage(new CubeUsages());
         }
- PaneSection<OLAPObject> cubeSection = new PaneSectionImpl(model.getCubeUsage().getCubeUsages(), "Cube Usages:"); - PaneSection<OLAPObject> dimensionSection = new PaneSectionImpl(model.getDimensions(), "Dimensions:"); - PaneSection<OLAPObject> measureSection = new PaneSectionImpl(model.getMeasures(), "Measures:");
+        PaneSection<CubeUsage> cubeSection =
+ new OLAPPaneSection<CubeUsage>(CubeUsage.class, model.getCubeUsage().getCubeUsages(), "Cube Usages:") {
+
+            public void addItem(int idx, CubeUsage item) {
+ VirtualCubePane.this.model.getCubeUsage().addCubeUsage(idx, item);
+            }
+        };
+        PaneSection<VirtualCubeDimension> dimensionSection =
+ new OLAPPaneSection<VirtualCubeDimension>(VirtualCubeDimension.class, model.getDimensions(), "Dimensions:") {
+
+            public void addItem(int idx, VirtualCubeDimension item) {
+                VirtualCubePane.this.model.addDimension(idx, item);
+            }
+        };
+        PaneSection<VirtualCubeMeasure> measureSection =
+ new OLAPPaneSection<VirtualCubeMeasure>(VirtualCubeMeasure.class, model.getMeasures(), "Measures:") {
+
+            public void addItem(int idx, VirtualCubeMeasure item) {
+                VirtualCubePane.this.model.addMeasure(idx, item);
+            }
+        };
         sections.add(cubeSection);
         sections.add(dimensionSection);
         sections.add(measureSection);
@@ -101,4 +120,17 @@

         return panel;
     }
-}
+
+    @Override
+ protected List<OLAPObject> filterDroppableItems(List<OLAPObject> items) {
+        List<OLAPObject> filtered = new ArrayList<OLAPObject>();
+        for (OLAPObject item : items) {
+            if (item instanceof CubeUsage ||
+                    item instanceof VirtualCubeDimension ||
+                    item instanceof VirtualCubeMeasure) {
+                filtered.add(item);
+            }
+        }
+        return filtered;
+    }
+}
\ No newline at end of file

Reply via email to