Author: thomasobrien95
Date: Wed May 20 07:54:47 2009
New Revision: 3054
Added:
trunk/src/ca/sqlpower/architect/swingui/olap/JoinEntryPanel.java
Modified:
trunk/regress/ca/sqlpower/architect/layout/TestFruchtermanReingoldForceLayout.java
trunk/regress/ca/sqlpower/architect/swingui/TestColumnEditPanel.java
trunk/regress/ca/sqlpower/architect/swingui/TestPlayPen.java
trunk/regress/ca/sqlpower/architect/swingui/action/TestCreateRelationshipAction.java
trunk/regress/ca/sqlpower/architect/undo/TestArchitectUndoManager.java
trunk/src/ca/sqlpower/architect/swingui/ColumnMappingPanel.java
trunk/src/ca/sqlpower/architect/swingui/MappingReport.java
trunk/src/ca/sqlpower/architect/swingui/PlayPen.java
trunk/src/ca/sqlpower/architect/swingui/PrintPanel.java
trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java
trunk/src/ca/sqlpower/architect/swingui/action/ExportPlaypenToPDFAction.java
trunk/src/ca/sqlpower/architect/swingui/olap/CubeEditPanel.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/OLAPPlayPenFactory.java
trunk/src/ca/sqlpower/architect/swingui/olap/VirtualCubePane.java
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateCubeAction.java
trunk/src/ca/sqlpower/architect/swingui/olap/action/EditCubeAction.java
Log:
This change introduces a join editor into the OLAP editor. Some changes
are still needed to finish this panel which will be done after this
commit.
A large number of files have been touched by this change as the playpen
now has a dialog owner given in its constructor. This dialog owner
will be used to properly parent new dialogs to the correct playpen
depending on which relational or olap playpen the dialog comes from.
Modified:
trunk/regress/ca/sqlpower/architect/layout/TestFruchtermanReingoldForceLayout.java
==============================================================================
---
trunk/regress/ca/sqlpower/architect/layout/TestFruchtermanReingoldForceLayout.java
(original)
+++
trunk/regress/ca/sqlpower/architect/layout/TestFruchtermanReingoldForceLayout.java
Wed May 20 07:54:47 2009
@@ -23,6 +23,7 @@
import java.io.IOException;
import junit.framework.TestCase;
+import ca.sqlpower.architect.swingui.ArchitectSwingSession;
import ca.sqlpower.architect.swingui.PlayPen;
import ca.sqlpower.architect.swingui.TestingArchitectSwingSessionContext;
import ca.sqlpower.architect.swingui.TablePane;
@@ -43,7 +44,8 @@
public void setUp() throws SQLObjectException, IOException {
context = new TestingArchitectSwingSessionContext();
db = new SQLDatabase();
- pp = new PlayPen(context.createSession());
+ final ArchitectSwingSession session = context.createSession();
+ pp = new PlayPen(session, session.getArchitectFrame());
table1= new SQLTable(db,true);
tp = new TablePane(table1,pp.getContentPane());
pp.addTablePane(tp,new Point(10,10));
@@ -57,7 +59,8 @@
}
public void testIsDoneNoElem() throws SQLObjectException {
- PlayPen p = new PlayPen(context.createSession());
+ final ArchitectSwingSession session = context.createSession();
+ PlayPen p = new PlayPen(session, session.getArchitectFrame());
layout.setup(p.getTablePanes(),p.getRelationships(),frame);
assertTrue(layout.isDone());
}
Modified:
trunk/regress/ca/sqlpower/architect/swingui/TestColumnEditPanel.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/swingui/TestColumnEditPanel.java
(original)
+++ trunk/regress/ca/sqlpower/architect/swingui/TestColumnEditPanel.java
Wed May 20 07:54:47 2009
@@ -176,7 +176,7 @@
public void testColumnStaysSelectedWhenMovedToPK() throws
SQLObjectException, IOException {
TestingArchitectSwingSessionContext context = new
TestingArchitectSwingSessionContext();
ArchitectSwingSession session = context.createSession();
- PlayPen pp = new PlayPen(session);
+ PlayPen pp = new PlayPen(session, session.getArchitectFrame());
TablePane tp = new TablePane(table, pp.getContentPane());
tp.setSelected(true,SelectionEvent.SINGLE_SELECT);
tp.selectItem(table.getColumnIndex(col3));
Modified: trunk/regress/ca/sqlpower/architect/swingui/TestPlayPen.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/swingui/TestPlayPen.java
(original)
+++ trunk/regress/ca/sqlpower/architect/swingui/TestPlayPen.java Wed May 20
07:54:47 2009
@@ -384,7 +384,7 @@
// Second pass get a copy make sure all of
// the original mutable objects returned from getters are
different
// between the two objects, but have the same values.
- PlayPen duplicate = new PlayPen(pp.getSession(), pp);
+ PlayPen duplicate = new PlayPen(pp.getSession(), pp,
pp.getDialogOwner());
for (PropertyDescriptor property : settableProperties) {
if (copyIgnoreProperties.contains(property.getName()))
continue;
Object oldVal;
Modified:
trunk/regress/ca/sqlpower/architect/swingui/action/TestCreateRelationshipAction.java
==============================================================================
---
trunk/regress/ca/sqlpower/architect/swingui/action/TestCreateRelationshipAction.java
(original)
+++
trunk/regress/ca/sqlpower/architect/swingui/action/TestCreateRelationshipAction.java
Wed May 20 07:54:47 2009
@@ -43,7 +43,7 @@
SQLDatabase db = new SQLDatabase();
TestingArchitectSwingSessionContext context = new
TestingArchitectSwingSessionContext();
ArchitectSwingSession session = context.createSession();
- pp = new PlayPen(session);
+ pp = new PlayPen(session, session.getArchitectFrame());
fkTable = new SQLTable(db,true);
TablePane tp = new TablePane(fkTable,pp.getContentPane());
pp.addTablePane(tp,new Point(1,1));
Modified:
trunk/regress/ca/sqlpower/architect/undo/TestArchitectUndoManager.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/undo/TestArchitectUndoManager.java
(original)
+++ trunk/regress/ca/sqlpower/architect/undo/TestArchitectUndoManager.java
Wed May 20 07:54:47 2009
@@ -138,7 +138,7 @@
System.out.println("-----------------Start setup
for "+getName()+"----------------");
TestingArchitectSwingSessionContext context = new
TestingArchitectSwingSessionContext();
session = context.createSession();
- pp = new PlayPen(session);
+ pp = new PlayPen(session, session.getArchitectFrame());
SQLDatabase db = session.getTargetDatabase();
fkTable = new SQLTable(db,true);
fkTable.setName("child");
@@ -243,7 +243,7 @@
}
public void testMove() throws SQLObjectException, IOException {
- PlayPen pp = new PlayPen(session);
+ PlayPen pp = new PlayPen(session, session.getArchitectFrame());
SQLTable table = new SQLTable(session.getTargetDatabase(),true);
TablePane tp = new TablePane(table,pp.getContentPane());
pp.addTablePane(tp, new Point());
@@ -268,7 +268,7 @@
public void testMultiMove() throws SQLObjectException
{
- PlayPen pp = new PlayPen(session);
+ PlayPen pp = new PlayPen(session, session.getArchitectFrame());
SQLDatabase db = session.getTargetDatabase();
SQLTable table = new SQLTable(db,true);
TablePane tp = new TablePane(table,pp.getContentPane());
@@ -308,7 +308,7 @@
}
public void testCompoundEditEvent() throws SQLObjectException{
- PlayPen pp = new PlayPen(session);
+ PlayPen pp = new PlayPen(session, session.getArchitectFrame());
ArchitectUndoManager manager = new ArchitectUndoManager(pp);
pp.getPlayPenContentPane().addPropertyChangeListener("location",
manager.getEventAdapter());
pp.getPlayPenContentPane().addPropertyChangeListener("connectionPoints",
manager.getEventAdapter());
Modified: trunk/src/ca/sqlpower/architect/swingui/ColumnMappingPanel.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/ColumnMappingPanel.java
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/ColumnMappingPanel.java Wed May
20 07:54:47 2009
@@ -318,7 +318,7 @@
public ColumnMappingPanel(ArchitectSwingSession session,
SQLRelationship r) {
this.session = session;
this.r = r;
- PlayPen pp = new PlayPen(session);
+ PlayPen pp = new PlayPen(session, session.getArchitectFrame());
lhsTable = new TablePane(r.getPkTable(), pp.getContentPane());
rhsTable = new TablePane(r.getFkTable(), pp.getContentPane());
Modified: trunk/src/ca/sqlpower/architect/swingui/MappingReport.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/MappingReport.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/MappingReport.java Wed May 20
07:54:47 2009
@@ -45,7 +45,7 @@
int maxTargetWidth = 0;
public MappingReport(ArchitectSwingSession session,
Collection<SQLTable> targetTables) throws SQLObjectException {
- PlayPen pp = new PlayPen(session);
+ PlayPen pp = new PlayPen(session, session.getArchitectFrame());
mappings = ETLUtils.findTableLevelMappings(targetTables);
for (SQLTable sourceTable : mappings.keySet()) {
if (sourceTable == null) continue;
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 Wed May 20
07:54:47 2009
@@ -33,6 +33,7 @@
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
+import java.awt.Window;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
@@ -313,6 +314,12 @@
* Flag to prevent recursive selections for selectObjects()
*/
private boolean ignoreTreeSelection = false;
+
+ /**
+ * This window can be used as the parent for dialogs that are created
+ * from components in this play pen.
+ */
+ private final Window dialogOwner;
/**
* Creates a play pen with reasonable defaults. If you are creating
@@ -323,7 +330,8 @@
* @param session
* The session this play pen belongs to. Null is not
allowed.
*/
- public PlayPen(ArchitectSwingSession session) {
+ public PlayPen(ArchitectSwingSession session, Window dialogOwner) {
+ this.dialogOwner = dialogOwner;
if (session == null) throw new NullPointerException("A null
session is not allowed here."); //$NON-NLS-1$
this.session = session;
setDatabase(session.getTargetDatabase());
@@ -362,8 +370,8 @@
* be aware that the underlying SQLObjects will be shared between the
two sessions.
* @param pp The playpen to duplicate.
*/
- public PlayPen(ArchitectSwingSession session, PlayPen pp) {
- this(session);
+ public PlayPen(ArchitectSwingSession session, PlayPen pp, Window
dialogOwner) {
+ this(session, dialogOwner);
logger.debug("Copying PlayPen@" + System.identityHashCode(pp) + " into "
+ System.identityHashCode(this));
this.antialiasSetting = pp.antialiasSetting;
@@ -3258,5 +3266,9 @@
for (int i = lifecycleListeners.size() - 1; i >= 0; i--) {
lifecycleListeners.get(i).PlayPenLifeEnding(evt);
}
+ }
+
+ public Window getDialogOwner() {
+ return dialogOwner;
}
}
Modified: trunk/src/ca/sqlpower/architect/swingui/PrintPanel.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/PrintPanel.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/PrintPanel.java Wed May 20
07:54:47 2009
@@ -105,7 +105,7 @@
setOpaque(true);
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
this.session = session;
- this.pp = new PlayPen(session, session.getPlayPen());
+ this.pp = new PlayPen(session, session.getPlayPen(),
session.getPlayPen().getDialogOwner());
// don't need this playpen to be interactive or respond to
SQLObject changes
pp.destroy();
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
Wed May 20 07:54:47 2009
@@ -72,7 +72,7 @@
private static final Logger logger =
Logger.getLogger(RelationalPlayPenFactory.class);
public static PlayPen createPlayPen(ArchitectSwingSession session,
DBTree dbTree) {
- PlayPen pp = new PlayPen(session);
+ PlayPen pp = new PlayPen(session, session.getArchitectFrame());
pp.setPopupFactory(new RelationalPopupFactory(pp, session));
SelectionSynchronizer synchronizer = new
SelectionSynchronizer(dbTree, pp);
pp.addSelectionListener(synchronizer);
Modified:
trunk/src/ca/sqlpower/architect/swingui/action/ExportPlaypenToPDFAction.java
==============================================================================
---
trunk/src/ca/sqlpower/architect/swingui/action/ExportPlaypenToPDFAction.java
(original)
+++
trunk/src/ca/sqlpower/architect/swingui/action/ExportPlaypenToPDFAction.java
Wed May 20 07:54:47 2009
@@ -119,7 +119,7 @@
@Override
public void doStuff(MonitorableImpl monitor, Map<String, Object>
properties) {
logger.debug("Creating PDF of playpen: " + playpen);
- PlayPen pp = new PlayPen(session, playpen);
+ PlayPen pp = new PlayPen(session, playpen,
playpen.getDialogOwner());
// don't need this playpen to be interactive or respond to
SQLObject changes
pp.destroy();
Modified: trunk/src/ca/sqlpower/architect/swingui/olap/CubeEditPanel.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/CubeEditPanel.java
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/CubeEditPanel.java Wed May
20 07:54:47 2009
@@ -44,19 +44,24 @@
import javax.swing.JToolBar;
import javax.swing.tree.TreeModel;
+import org.apache.log4j.Logger;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import ca.sqlpower.architect.olap.OLAPSession;
import ca.sqlpower.architect.olap.OLAPUtil;
import ca.sqlpower.architect.olap.MondrianModel.Cube;
+import ca.sqlpower.architect.olap.MondrianModel.Join;
import ca.sqlpower.architect.olap.MondrianModel.Measure;
+import ca.sqlpower.architect.olap.MondrianModel.Relation;
import ca.sqlpower.architect.olap.MondrianModel.SQL;
import ca.sqlpower.architect.olap.MondrianModel.Table;
import ca.sqlpower.architect.olap.MondrianModel.View;
import ca.sqlpower.architect.swingui.ArchitectSwingSession;
import ca.sqlpower.architect.swingui.DBTree;
+import ca.sqlpower.architect.swingui.PlayPen;
import ca.sqlpower.architect.swingui.dbtree.DBTreeModel;
import ca.sqlpower.sqlobject.SQLDatabase;
+import ca.sqlpower.sqlobject.SQLDatabaseMapping;
import ca.sqlpower.sqlobject.SQLObjectException;
import ca.sqlpower.sqlobject.SQLObjectRoot;
import ca.sqlpower.sqlobject.SQLTable;
@@ -74,6 +79,8 @@
public class CubeEditPanel implements ValidatableDataEntryPanel {
+ private static final Logger logger =
Logger.getLogger(CubeEditPanel.class);
+
/**
* This entry panel will create a view builder based on the
* SQLQueryUIComponents in the library.
@@ -100,7 +107,7 @@
public ViewEntryPanel(ArchitectSwingSession session) {
DefaultFormBuilder builder = new DefaultFormBuilder(new
FormLayout("pref, 5dlu:grow, pref, 3dlu, pref", "pref, fill:pref:grow"));
- SQLDatabase db = OSUtils.getAncestor(CubeEditPanel.this.cube,
OLAPSession.class).getDatabase();
+ SQLDatabase db = getDatabase();
queryComponents = new SQLQueryUIComponents(session,
session.getContext().getPlDotIni(), session, builder.getPanel());
queryComponents.getRowLimitSpinner().setValue(Integer.valueOf(1000));
queryComponents.getDatabaseComboBox().setSelectedItem(db.getDataSource());
@@ -184,6 +191,7 @@
private JTextArea selectStatements;
private JTextField viewAlias;
+ private JTextArea joinXMLString;
/**
* Validation handler for errors in the dialog
@@ -192,13 +200,25 @@
private StatusComponent status = new StatusComponent();
private JRadioButton tableRadioButton;
private JRadioButton viewRadioButton;
+ private final JRadioButton joinRadioButton;
+
+ /**
+ * This will store a Join Mondrian model if it is to be used for a cube
+ * definition.
+ */
+ private Join joinFact;
/**
- * Creates a new property editor for the given OLAP Cube.
+ * Creates a new property editor for the given OLAP Cube.
+ *
+ * TODO remove the dbMapping if it is no longer needed as the session
will
+ * be used from the playpen or remove the session from the view and
join
+ * entry panel constructors and pass a dbMapping as required instead.
*
- * @param cube The data model of the cube to edit
+ * @param cube
+ * The data model of the cube to edit
*/
- public CubeEditPanel(Cube cube, final ArchitectSwingSession session)
throws SQLObjectException {
+ public CubeEditPanel(Cube cube, final PlayPen playPen, final
SQLDatabaseMapping dbMapping) throws SQLObjectException {
this.cube = cube;
List<SQLTable> tables = OLAPUtil.getAvailableTables(cube);
@@ -222,6 +242,23 @@
}
}
+ final JButton viewEditButton = new JButton(new
AbstractAction("Edit...") {
+ public void actionPerformed(ActionEvent e) {
+ logger.debug("The dialog owner is " +
playPen.getDialogOwner());
+ JDialog dialog =
DataEntryPanelBuilder.createDataEntryPanelDialog(new
ViewEntryPanel(playPen.getSession()), playPen.getDialogOwner(), "View
Builder", "OK");
+ dialog.pack();
+ dialog.setVisible(true);
+ }
+ });
+ final JButton joinEditButton = new JButton(new
AbstractAction("Edit...") {
+ public void actionPerformed(ActionEvent e) {
+ JDialog dialog =
DataEntryPanelBuilder.createDataEntryPanelDialog(new
JoinEntryPanel(playPen.getSession(), getDatabase(), CubeEditPanel.this,
joinFact), playPen.getDialogOwner(), "Join Builder", "OK");
+ dialog.pack();
+
+ dialog.setVisible(true);
+ }
+ });
+
builder.appendSeparator("Fact Table");
tableChooser = new JComboBox(new Vector<SQLTable>(tables));
@@ -230,6 +267,8 @@
tableChooser.setEnabled(tableRadioButton.isSelected());
selectStatements.setEnabled(viewRadioButton.isSelected());
viewAlias.setEnabled(viewRadioButton.isSelected());
+ viewEditButton.setEnabled(viewRadioButton.isSelected());
+ joinEditButton.setEnabled(joinRadioButton.isSelected());
}
};
@@ -239,10 +278,14 @@
viewRadioButton = new JRadioButton();
viewRadioButton.setAction(radioButtonsAction);
viewRadioButton.setText("Use View");
+ joinRadioButton = new JRadioButton();
+ joinRadioButton.setAction(radioButtonsAction);
+ joinRadioButton.setText("Use Join");
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(tableRadioButton);
buttonGroup.add(viewRadioButton);
+ buttonGroup.add(joinRadioButton);
builder.append(tableRadioButton, 3);
builder.append(tableChooser, 3);
@@ -250,13 +293,18 @@
builder.append("Alias", viewAlias = new JTextField());
builder.append(new JLabel("SELECT Statements"), 3);
builder.append(new JScrollPane(selectStatements = new
JTextArea("", 4, 30)), 3);
- builder.append(new JButton(new AbstractAction("Edit...") {
- public void actionPerformed(ActionEvent e) {
- JDialog dialog =
DataEntryPanelBuilder.createDataEntryPanelDialog(new
ViewEntryPanel(session), null, "View Builder", "OK");
- dialog.pack();
- dialog.setVisible(true);
- }
- }));
+
+ builder.append(viewEditButton);
+ builder.nextLine();
+ builder.append(joinRadioButton, 3);
+
+ builder.append(new JLabel("Tables in the join"), 3);
+ joinXMLString = new JTextArea("", 4, 30);
+ joinXMLString.setEditable(false);
+ builder.append(new JScrollPane(joinXMLString), 3);
+
+ builder.append(joinEditButton);
+ builder.nextLine();
selectStatements.setLineWrap(true);
selectStatements.setEditable(false);
@@ -294,7 +342,7 @@
selectStatements.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
- JDialog dialog =
DataEntryPanelBuilder.createDataEntryPanelDialog(new
ViewEntryPanel(session), null, "View Builder", "OK");
+ JDialog dialog =
DataEntryPanelBuilder.createDataEntryPanelDialog(new
ViewEntryPanel(playPen.getSession()), playPen.getDialogOwner(), "View
Builder", "OK");
dialog.pack();
dialog.setVisible(true);
}
@@ -322,6 +370,7 @@
view.addSelect(sql);
cube.setFact(view);
}
+
cube.setName(nameField.getText());
if (!(captionField.getText().equals(""))) {
cube.setCaption(captionField.getText());
@@ -350,5 +399,42 @@
public ValidationHandler getValidationHandler() {
return handler;
+ }
+
+ /**
+ * This is the database that is being used in the session. The
+ * cube can be made from tables in this database.
+ */
+ private SQLDatabase getDatabase() {
+ return OSUtils.getAncestor(CubeEditPanel.this.cube,
OLAPSession.class).getDatabase();
+ }
+
+ public void setJoinFact(Join joinFact) {
+ this.joinFact = joinFact;
+ joinXMLString.setText(createJoinString(joinFact));
+ }
+
+ /**
+ * This will recursively create a list of the table names in the join.
+ */
+ private String createJoinString(Join join) {
+ if (join == null) return null;
+
+ String joinString;
+ if (join.getLeft() instanceof Join) {
+ joinString = createJoinString((Join) join.getLeft());
+ } else {
+ joinString = ((Relation) join.getLeft()).getName() + "\n";
+ }
+ if (join.getRight() instanceof Join) {
+ joinString = joinString + createJoinString((Join)
join.getRight());
+ } else {
+ joinString = joinString + ((Relation)
join.getRight()).getName() + "\n";
+ }
+ return joinString;
+ }
+
+ public Join getJoinFact() {
+ return joinFact;
}
}
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 Wed May 20
07:54:47 2009
@@ -93,7 +93,7 @@
DataEntryPanel panel;
// TODO add getName() method to DataEntryPanel.
if (coord.getIndex() == PlayPenCoordinate.ITEM_INDEX_TITLE) {
- panel = new CubeEditPanel(model,
getParent().getOwner().getSession());
+ panel = new CubeEditPanel(model, getPlayPen(),
getPlayPen().getSession());
} else if (coord.getIndex() ==
PlayPenCoordinate.ITEM_INDEX_SECTION_TITLE) {
panel = null;
} else if (coord.getIndex() > PlayPenCoordinate.ITEM_INDEX_TITLE){
Added: trunk/src/ca/sqlpower/architect/swingui/olap/JoinEntryPanel.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/JoinEntryPanel.java Wed
May 20 07:54:47 2009
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * Power*Architect is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Power*Architect is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package ca.sqlpower.architect.swingui.olap;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JToolBar;
+import javax.swing.tree.TreeModel;
+
+import ca.sqlpower.architect.olap.OLAPObject;
+import ca.sqlpower.architect.olap.MondrianModel.Cube;
+import ca.sqlpower.architect.olap.MondrianModel.InlineTable;
+import ca.sqlpower.architect.olap.MondrianModel.Join;
+import ca.sqlpower.architect.olap.MondrianModel.Relation;
+import ca.sqlpower.architect.olap.MondrianModel.RelationOrJoin;
+import ca.sqlpower.architect.olap.MondrianModel.Table;
+import ca.sqlpower.architect.swingui.ArchitectSwingSession;
+import ca.sqlpower.architect.swingui.DBTree;
+import ca.sqlpower.architect.swingui.dbtree.DBTreeModel;
+import ca.sqlpower.query.Container;
+import ca.sqlpower.query.Item;
+import ca.sqlpower.query.ItemContainer;
+import ca.sqlpower.query.QueryData;
+import ca.sqlpower.query.SQLJoin;
+import ca.sqlpower.query.StringItem;
+import ca.sqlpower.query.TableContainer;
+import ca.sqlpower.sqlobject.SQLDatabase;
+import ca.sqlpower.sqlobject.SQLObjectException;
+import ca.sqlpower.sqlobject.SQLObjectRoot;
+import ca.sqlpower.sqlobject.SQLTable;
+import ca.sqlpower.swingui.DataEntryPanel;
+import ca.sqlpower.swingui.action.ForumAction;
+import ca.sqlpower.swingui.querypen.QueryPen;
+
+import com.jgoodies.forms.builder.DefaultFormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+
+/**
+ * This entry panel will be used for editing a {...@link Join} that defines
+ * a {...@link Cube} in the OLAP editor.
+ */
+public class JoinEntryPanel implements DataEntryPanel {
+
+ /**
+ * This compares two SQLJoin objects and orders them by the joins that
contain
+ * the most columns. The first value should have the smallest number
of columns
+ * to the largest number of columns.
+ */
+ private class compareByColumnCount implements Comparator<SQLJoin> {
+
+ public int compare(SQLJoin o1, SQLJoin o2) {
+ int join1ColCount =
Math.max(o1.getLeftColumn().getParent().getItems().size(),
+
o1.getRightColumn().getParent().getItems().size());
+ int Join2ColCount =
Math.max(o2.getLeftColumn().getParent().getItems().size(),
+
o2.getRightColumn().getParent().getItems().size());
+ if (join1ColCount < Join2ColCount) {
+ return -1;
+ } else if (join1ColCount > Join2ColCount) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ }
+
+ private final JPanel panel = new JPanel();
+
+ private final QueryPen pen;
+
+ /**
+ * This action will not execute the query in the query pen. If later we
+ * want to show the results of the joins defined by the user we can
implement
+ * this method. One thing to keep in mind is that a join created on
the playpen
+ * database will not be able to execute.
+ */
+ private final Action noExecutionAction = new AbstractAction() {
+
+ public void actionPerformed(ActionEvent e) {
+ //Do nothing as we are currently not executing this join.
+ }
+ };
+
+ private final QueryData model;
+
+ private final ForumAction forumAction = new ForumAction(new
ImageIcon(JoinEntryPanel.class.getResource("/icons/architect16.png")), "Help
on the forums.");
+
+ private final SQLDatabase db;
+
+ private final ArchitectSwingSession session;
+
+ /**
+ * This panel made the JoinEntryPanel and will have it's join
+ * set when the OK button is pressed.
+ */
+ private final CubeEditPanel editPanel;
+
+ public JoinEntryPanel(ArchitectSwingSession session, SQLDatabase db,
CubeEditPanel editPanel, Join join) {
+ this.session = session;
+ this.db = db;
+ this.editPanel = editPanel;
+ model = new QueryData(session);
+
+ if (join != null) {
+ addSQLJoinsToModel(join);
+ }
+
+ pen = new QueryPen(noExecutionAction , model, forumAction, false);
+ pen.setExecuteIcon(new
ImageIcon(QueryPen.class.getClassLoader().getResource("icons/auto_layout16.png")));
+ buildUI();
+ }
+
+ private List<Container> addSQLJoinsToModel(Join join) {
+
+ List<Container> tablesRight = new ArrayList<Container>();
+ List<Container> tablesLeft = new ArrayList<Container>();
+
+ //Recursively add the tables and their joins to the model
+ if (join.getLeft() instanceof Join) {
+ tablesLeft.addAll(addSQLJoinsToModel((Join) join.getLeft()));
+ }
+ if (join.getRight() instanceof Join) {
+ tablesRight.addAll(addSQLJoinsToModel((Join) join.getRight()));
+ }
+
+ //Base case: add tables to the model if one or both sides of the
join are tables.
+ Container leftContainer =
createContainerForRelation(join.getLeft());
+ if (leftContainer != null) {
+ tablesLeft.add(leftContainer);
+ }
+ Container rightContainer =
createContainerForRelation(join.getRight());
+ if (rightContainer != null) {
+ tablesRight.add(rightContainer);
+ }
+
+ //Add the join the given join defines
+ if (leftContainer == null) {
+ if (join.getLeftAlias() == null ||
join.getLeftAlias().trim().length() == 0) {
+ //XXX This may be a valid case where we would need to
iterate over all of the tables to find the unique key on the one side.
+ throw new IllegalStateException("Expecting 'leftAlias' to
specify which table contains the " + join.getLeftKey() + " key.");
+ }
+ for (Container c : tablesLeft) {
+ if (c.getName().equals(join.getLeftAlias())) {
+ leftContainer = c;
+ break;
+ }
+ }
+ if (leftContainer == null) {
+ throw new IllegalStateException("Could not find the table
for the 'leftAlias' " + join.getLeftAlias());
+ }
+ }
+ if (rightContainer == null) {
+ if (join.getRightAlias() == null ||
join.getRightAlias().trim().length() == 0) {
+ //XXX This may be a valid case where we would need to
iterate over all of the tables to find the unique key on the one side.
+ throw new IllegalStateException("Expecting 'rightAlias' to
specify which table contains the " + join.getRightKey() + " key.");
+ }
+ for (Container c : tablesRight) {
+ if (c.getName().equals(join.getRightAlias())) {
+ rightContainer = c;
+ break;
+ }
+ }
+ if (rightContainer == null) {
+ throw new IllegalStateException("Could not find the table
for the 'rightAlias' " + join.getRightAlias());
+ }
+ }
+
+ Item leftItem = null;
+ for (Item item : leftContainer.getItems()) {
+ if (join.getLeftKey().equals(item.getName())) {
+ leftItem = item;
+ break;
+ }
+ }
+ if (leftItem == null) {
+ throw new IllegalStateException("Could not find
the 'leftKey' " + join.getLeftKey() + " from the table " +
leftContainer.getName());
+ }
+ Item rightItem = null;
+ for (Item item : rightContainer.getItems()) {
+ if (join.getRightKey().equals(item.getName())) {
+ rightItem = item;
+ break;
+ }
+ }
+ if (leftItem == null) {
+ throw new IllegalStateException("Could not find
the 'rightKey' " + join.getRightKey() + " from the table " +
rightContainer.getName());
+ }
+
+ SQLJoin sqlJoin = new SQLJoin(leftItem, rightItem);
+ model.addJoin(sqlJoin);
+
+ tablesRight.addAll(tablesLeft);
+ return tablesRight;
+ }
+
+ /**
+ * This will create a Container with items that will represent the
relation
+ * passed in. The container will be added to the model in this method
and
+ * does not need to be added again. Containers will only be made for
{...@link Relation}
+ * objects, a {...@link Join} should be broken down in the {...@link
#addSQLJoinsToModel(Join)}
+ * method.
+ * <p>
+ * This is a helper method for {...@link #addSQLJoinsToModel(Join)}.
+ */
+ private Container createContainerForRelation(RelationOrJoin relation) {
+ if (relation instanceof Table) {
+ Table table1 = (Table) relation;
+ SQLTable sqlTable;
+ try {
+ sqlTable = db.getTableByName(null, table1.getSchema(),
table1.getName());
+ } catch (SQLObjectException e) {
+ throw new RuntimeException(e);
+ } //XXX Can't get the catalog from the table so we are
currently only looking by name and schema
+ TableContainer container = new TableContainer(model, sqlTable);
+ model.addTable(container);
+ return container;
+ } else if (relation instanceof InlineTable) {
+ InlineTable table = (InlineTable) relation;
+
+ Container inlineContainer = new ItemContainer(table.getName());
+ for (OLAPObject child : table.getChildren()) {
+ Item childItem = new StringItem(child.getName());
+ inlineContainer.addItem(childItem);
+ }
+
+ model.addTable(inlineContainer);
+ return inlineContainer;
+ } else if (relation instanceof Join) {
+ return null;
+ } else { //TODO create a container for View objects.
+ throw new UnsupportedOperationException("Cannot create a
container of the type " + relation.getClass() + " for the object " +
relation);
+ }
+ }
+
+ private void buildUI() {
+ DefaultFormBuilder builder = new DefaultFormBuilder(new
FormLayout("fill:max(500dlu;pref):grow", "pref,
fill:max(300dlu;pref):grow"), panel);
+ JToolBar toolbar = new JToolBar();
+ toolbar.add(pen.getDeleteButton());
+ toolbar.add(pen.getCreateJoinButton());
+ toolbar.addSeparator();
+ toolbar.add(pen.getZoomSliderContainer());
+ builder.append(toolbar);
+ builder.nextLine();
+ JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+ splitPane.add(pen.getScrollPane(), JSplitPane.LEFT);
+
+ SQLObjectRoot root = new SQLObjectRoot();
+ TreeModel treeModel;
+ DBTree tree;
+ try {
+ root.addChild(db);
+ treeModel = new DBTreeModel(root);
+ tree = new DBTree(session);
+ } catch (SQLObjectException e) {
+ throw new RuntimeException(e);
+ }
+ tree.setModel(treeModel);
+ tree.setPopupMenuEnabled(false);
+
+ JPanel treePanel = new JPanel(new BorderLayout());
+ treePanel.add(new JLabel(db.getName()), BorderLayout.NORTH);
+ treePanel.add(new JScrollPane(tree));
+
+ splitPane.add(treePanel, JSplitPane.RIGHT);
+ splitPane.setResizeWeight(0.95);
+
+ builder.append(splitPane);
+ }
+
+ public boolean applyChanges() {
+ List<SQLJoin> joins = new ArrayList<SQLJoin>(model.getJoins());
+
+ Collections.sort(joins, new compareByColumnCount());
+
+ Map<Container, Join> tableToJoinMap = new HashMap<Container,
Join>();
+
+ //Iterate through the SQLJoins slowly building up a larger
Mondrian Join
+ //by either using Tables or other joins made by Tables.
+
+ //This join will contain the last Join added to the map.
+ Join join = null;
+ for (SQLJoin sqlJoin : joins) {
+ join = new Join();
+ //check if the left side is in the map
+ final Container leftContainer =
sqlJoin.getLeftColumn().getContainer();
+ if (tableToJoinMap.containsKey(leftContainer)) {
+ //if so get the join the left side is involved with and
update the joins in the map accordingly
+ Join existingJoin = tableToJoinMap.get(leftContainer);
+ join.setLeftAlias(leftContainer.getName());
+ join.setLeft(existingJoin);
+ join.setLeftKey(sqlJoin.getLeftColumn().getName());
+ for (Map.Entry<Container, Join> entry :
tableToJoinMap.entrySet()) {
+ if (entry.getValue() == existingJoin) {
+ tableToJoinMap.put(leftContainer, join);
+ }
+ }
+ } else {
+ //if not just use the table
+ Table table = new Table();
+ table.setName(leftContainer.getName());
+ join.setLeft(table);
+ join.setLeftKey(sqlJoin.getLeftColumn().getName());
+ tableToJoinMap.put(leftContainer, join);
+ }
+
+ //check if the right side is in the map
+ final Container rightContainer =
sqlJoin.getRightColumn().getContainer();
+ if (tableToJoinMap.containsKey(rightContainer)) {
+ //if so get the join the right side is involved with and
update the joins in the map accordingly
+ Join existingJoin = tableToJoinMap.get(rightContainer);
+ join.setRightAlias(rightContainer.getName());
+ join.setRight(existingJoin);
+ join.setRightKey(sqlJoin.getRightColumn().getName());
+ for (Map.Entry<Container, Join> entry :
tableToJoinMap.entrySet()) {
+ if (entry.getValue() == existingJoin) {
+ tableToJoinMap.put(rightContainer, join);
+ }
+ }
+ } else {
+ //if not just use the table
+ Table table = new Table();
+ table.setName(rightContainer.getName());
+ join.setRight(table);
+ join.setRightKey(sqlJoin.getRightColumn().getName());
+ tableToJoinMap.put(rightContainer, join);
+ }
+
+ }
+
+ if (join != null) {
+ editPanel.setJoinFact(join);
+ }
+ return true;
+ }
+
+ public void discardChanges() {
+ //do-nothing.
+ }
+
+ public JComponent getPanel() {
+ return panel;
+ }
+
+ public boolean hasUnsavedChanges() {
+ return true;
+ }
+
+}
+
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
May 20 07:54:47 2009
@@ -76,7 +76,7 @@
/**
* The frame this edit session lives in.
*/
- private JFrame frame;
+ private final JFrame frame;
/**
* The preferences node for OLAP user settings.
@@ -149,8 +149,6 @@
tree = new OLAPTree(swingSession, this, olapSession.getSchema());
tree.setCellRenderer(new OLAPTreeCellRenderer());
undoManager = new OLAPUndoManager(olapSession);
- pp = OLAPPlayPenFactory.createPlayPen(swingSession, this,
undoManager);
-
undoManager.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
// this can be called before initGUI() has had a chance to
create the frame
@@ -159,13 +157,16 @@
}
}
});
+ frame = new JFrame(generateDialogTitle());
+ pp = OLAPPlayPenFactory.createPlayPen(swingSession, this,
undoManager);
+
swingSession.addSessionLifecycleListener(new
SessionLifecycleListener<ArchitectSwingSession>() {
public void
sessionClosing(SessionLifecycleEvent<ArchitectSwingSession> e) {
close();
}
});
- // Don't create actions here. PlayPen is currently null.
+ initGUI();
}
/**
@@ -173,9 +174,6 @@
* visibility set.
*/
public JFrame getFrame() {
- if (frame == null) {
- initGUI();
- }
return frame;
}
@@ -251,7 +249,6 @@
panel.add(splitPane, BorderLayout.CENTER);
panel.add(toolbar, BorderLayout.EAST);
- frame = new JFrame(generateDialogTitle());
olapSession.getSchema().addPropertyChangeListener(new
PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("name")) {
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
Wed May 20 07:54:47 2009
@@ -81,7 +81,7 @@
throw new NullPointerException("Null oSession");
}
- PlayPen pp = new PlayPen(session);
+ PlayPen pp = new PlayPen(session, oSession.getFrame());
OLAPModelListener ppcl = new OLAPModelListener(pp, oSession);
pp.addPlayPenLifecycleListener(ppcl);
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 Wed
May 20 07:54:47 2009
@@ -112,7 +112,7 @@
CubeUsage cu = (CubeUsage) coord.getItem();
Cube c = OLAPUtil.findReferencedCube(model, cu);
if (c == null) throw new NullPointerException("Couldn't
find cube!");
- panel = new CubeEditPanel(c,
getParent().getOwner().getSession());
+ panel = new CubeEditPanel(c, getPlayPen(),
getPlayPen().getSession());
} else if (coord.getItem() instanceof VirtualCubeDimension) {
VirtualCubeDimension vcd = (VirtualCubeDimension)
coord.getItem();
Dimension d = OLAPUtil.findReferencedDimension(vcd);
Modified:
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateCubeAction.java
==============================================================================
---
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateCubeAction.java
(original)
+++
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateCubeAction.java
Wed May 20 07:54:47 2009
@@ -84,7 +84,7 @@
playpen.addPlayPenComponent(cp, p);
cp.setSelected(true,SelectionEvent.SINGLE_SELECT);
- CubeEditPanel editPanel = new CubeEditPanel(cp.getModel(),
cp.getParent().getOwner().getSession()) {
+ CubeEditPanel editPanel = new CubeEditPanel(cp.getModel(),
cp.getPlayPen(), cp.getPlayPen().getSession()) {
@Override
public void discardChanges() {
schema.removeCube(cp.getModel());
Modified:
trunk/src/ca/sqlpower/architect/swingui/olap/action/EditCubeAction.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/action/EditCubeAction.java
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/action/EditCubeAction.java
Wed May 20 07:54:47 2009
@@ -54,7 +54,7 @@
public void actionPerformed(ActionEvent e) {
try {
- DataEntryPanel panel = new CubeEditPanel(cube, session);
+ DataEntryPanel panel = new CubeEditPanel(cube, playpen,
session);
JDialog dialog =
DataEntryPanelBuilder.createDataEntryPanelDialog(panel, dialogOwner, "Cube
Properties", "OK");
dialog.setLocationRelativeTo(session.getArchitectFrame());
dialog.setVisible(true);