Author: thomasobrien95
Date: Thu Dec 11 07:42:05 2008
New Revision: 2871
Added:
trunk/src/ca/sqlpower/architect/swingui/dbtree/icons/stop16.png
(contents, props changed)
Removed:
trunk/regress/ca/sqlpower/architect/TestSQLExceptionNode.java
trunk/src/ca/sqlpower/architect/SQLExceptionNode.java
Modified:
trunk/regress/ca/sqlpower/architect/ArchitectValueMaker.java
trunk/regress/ca/sqlpower/architect/SQLObjectTest.java
trunk/regress/ca/sqlpower/architect/SQLTestCase.java
trunk/regress/ca/sqlpower/architect/StubSQLObject.java
trunk/regress/ca/sqlpower/architect/swingui/TestSwingUIProject.java
trunk/src/ca/sqlpower/architect/CoreProject.java
trunk/src/ca/sqlpower/architect/SQLCatalog.java
trunk/src/ca/sqlpower/architect/SQLColumn.java
trunk/src/ca/sqlpower/architect/SQLDatabase.java
trunk/src/ca/sqlpower/architect/SQLIndex.java
trunk/src/ca/sqlpower/architect/SQLObject.java
trunk/src/ca/sqlpower/architect/SQLObjectRoot.java
trunk/src/ca/sqlpower/architect/SQLRelationship.java
trunk/src/ca/sqlpower/architect/SQLSchema.java
trunk/src/ca/sqlpower/architect/SQLSequence.java
trunk/src/ca/sqlpower/architect/SQLTable.java
trunk/src/ca/sqlpower/architect/swingui/DBTree.java
trunk/src/ca/sqlpower/architect/swingui/PlayPen.java
trunk/src/ca/sqlpower/architect/swingui/SwingUIProject.java
trunk/src/ca/sqlpower/architect/swingui/dbtree/DBTreeCellRenderer.java
trunk/src/ca/sqlpower/architect/swingui/dbtree/DBTreeModel.java
Log:
Fix for bug 1181. The SQLExceptionNode has been removed and a
childrenInaccessibleReason property now exists on SQLObjects to give the
exception for why the object cannot populate its children. This solves the
problem where populating a SQLObject partially then trying to add an
exception node would throw an exception that child types cannot be mixed.
Modified: trunk/regress/ca/sqlpower/architect/ArchitectValueMaker.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/ArchitectValueMaker.java
(original)
+++ trunk/regress/ca/sqlpower/architect/ArchitectValueMaker.java Thu Dec 11
07:42:05 2008
@@ -38,6 +38,8 @@
newVal = new AlwaysOKUserPrompter();
} else if (valueType == KettleRepositoryDirectoryChooser.class) {
newVal = new RootRepositoryDirectoryChooser();
+ } else if (valueType.isAssignableFrom(Throwable.class)) {
+ newVal = new ArchitectException("Test Exception");
} else {
newVal = super.makeNewValue(valueType, oldVal, propName);
}
Modified: trunk/regress/ca/sqlpower/architect/SQLObjectTest.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/SQLObjectTest.java (original)
+++ trunk/regress/ca/sqlpower/architect/SQLObjectTest.java Thu Dec 11
07:42:05 2008
@@ -47,7 +47,7 @@
this.parent = parent;
}
@Override
- protected void populate() throws ArchitectException {
+ protected void populateImpl() throws ArchitectException {
// System.err.println("Abstract test stub populate()
invoked");
}
@Override
@@ -199,7 +199,7 @@
}
public void testNoMixChildTypes() throws ArchitectException {
- target.addChild(new SQLExceptionNode(null, "everything is ok. don't
panic."));
+ target.addChild(new SQLColumn());
try {
target.addChild(new SQLObjectImpl());
fail("Target didn't throw exception for mixing child
types!");
@@ -258,6 +258,26 @@
target.addSQLObjectListener(listener);
target.putClientProperty(this.getClass(), "testProperty", "test
me");
assertEquals(1, listener.getChangedCount());
+ }
+
+ public void testChildrenInaccessibleReasonSetOnPopulateError() throws
Exception {
+ final RuntimeException e = new RuntimeException();
+ SQLObject o = new SQLObjectImpl() {
+ @Override
+ protected void populateImpl() throws ArchitectException {
+ throw e;
+ }
+ };
+
+ try {
+ o.populate();
+ fail();
+ } catch (Exception ex) {
+ //should get here
+ }
+
+ assertEquals(e, o.getChildrenInaccessibleReason());
+
}
}
Modified: trunk/regress/ca/sqlpower/architect/SQLTestCase.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/SQLTestCase.java (original)
+++ trunk/regress/ca/sqlpower/architect/SQLTestCase.java Thu Dec 11
07:42:05 2008
@@ -177,6 +177,8 @@
} else {
newVal = SQLRelationship.UpdateDeleteRule.CASCADE;
}
+ } else if (property.getPropertyType() == Throwable.class) {
+ newVal = new Throwable();
} else {
throw new RuntimeException("This test case lacks a
value for "+
property.getName()+
@@ -296,7 +298,8 @@
} else {
newVal =
SQLRelationship.Deferrability.INITIALLY_DEFERRED;
}
-
+ } else if (property.getPropertyType() == Throwable.class) {
+ newVal = new Throwable();
} else {
throw new RuntimeException("This test case lacks a
value for "+
property.getName()+
Modified: trunk/regress/ca/sqlpower/architect/StubSQLObject.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/StubSQLObject.java (original)
+++ trunk/regress/ca/sqlpower/architect/StubSQLObject.java Thu Dec 11
07:42:05 2008
@@ -47,7 +47,7 @@
}
@Override
- protected void populate() throws ArchitectException {
+ protected void populateImpl() throws ArchitectException {
populateCount++;
}
Modified:
trunk/regress/ca/sqlpower/architect/swingui/TestSwingUIProject.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/swingui/TestSwingUIProject.java
(original)
+++ trunk/regress/ca/sqlpower/architect/swingui/TestSwingUIProject.java Thu
Dec 11 07:42:05 2008
@@ -410,9 +410,11 @@
Map<String,Object> oldDescription =
TestUtils.setAllInterestingProperties(db,
propertiesToIgnore);
+ System.out.println("Properties set " + oldDescription);
File tmp = File.createTempFile("test", ".architect");
+ System.out.println("File located at " + tmp.getAbsolutePath() + " and is
delete on exit? " + deleteOnExit);
if (deleteOnExit) {
tmp.deleteOnExit();
}
@@ -428,6 +430,8 @@
// grab the second database in the dbtree's model (the first is the play
pen)
db = (SQLDatabase)
session2.getSourceDatabases().getDatabaseList().get(1);
+ System.out.println("DB has child exception " +
db.getChildrenInaccessibleReason());
+
Map<String, Object> newDescription =
TestUtils.getAllInterestingProperties(db,
propertiesToIgnore);
@@ -527,6 +531,7 @@
propertiesToIgnore.add("populated");
propertiesToIgnore.add("secondaryChangeMode");
propertiesToIgnore.add("magicEnabled");
+ propertiesToIgnore.add("childrenInaccessibleReason");
Map<String,Object> oldDescription =
TestUtils.setAllInterestingProperties(target,
propertiesToIgnore);
@@ -581,6 +586,7 @@
propertiesToIgnore.add("columnsFolder");
propertiesToIgnore.add("secondaryChangeMode");
propertiesToIgnore.add("magicEnabled");
+ propertiesToIgnore.add("childrenInaccessibleReason");
Map<String,Object> oldDescription =
TestUtils.setAllInterestingProperties(target,
propertiesToIgnore);
@@ -632,6 +638,7 @@
propertiesToIgnore.add("undoEventListeners");
propertiesToIgnore.add("secondaryChangeMode");
propertiesToIgnore.add("magicEnabled");
+ propertiesToIgnore.add("childrenInaccessibleReason");
Map<String,Object> oldDescription =
TestUtils.setAllInterestingProperties(target,
propertiesToIgnore);
Modified: trunk/src/ca/sqlpower/architect/CoreProject.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/CoreProject.java (original)
+++ trunk/src/ca/sqlpower/architect/CoreProject.java Thu Dec 11 07:42:05
2008
@@ -68,6 +68,17 @@
ConvertUtils.register(new UpdateDeleteRuleConverter(),
UpdateDeleteRule.class);
}
+ /**
+ * This will load the attributes in all SQLObjects that are not loaded
by basic
+ * setters through the digester.
+ */
+ private static void LoadSQLObjectAttributes(SQLObject obj, Attributes
attr) {
+ String message = attr.getValue("sql-exception");
+ if (message != null) {
+ obj.setChildrenInaccessibleReason(new
ArchitectException(message));
+ }
+ }
+
// ---------------- persistent properties -------------------
protected File file;
@@ -369,7 +380,7 @@
SQLExceptionFactory exceptionFactory = new SQLExceptionFactory();
d.addFactoryCreate("*/sql-exception", exceptionFactory);
d.addSetProperties("*/sql-exception");
- d.addSetNext("*/sql-exception", "addChild");
+ d.addSetNext("*/sql-exception", "setChildrenInaccessibleReason");
TargetDBFactory targetDBFactory = new TargetDBFactory();
// target database hierarchy
@@ -491,6 +502,8 @@
if (populated != null && populated.equals("false")) {
db.setPopulated(false);
}
+
+ LoadSQLObjectAttributes(db, attributes);
return db;
}
@@ -512,6 +525,8 @@
} else {
logger.warn("No ID found in database element while loading
project!");
}
+
+ LoadSQLObjectAttributes(schema, attributes);
return schema;
}
@@ -552,6 +567,9 @@
}
currentTable = tab;
+
+ LoadSQLObjectAttributes(tab, attributes);
+
return tab;
}
}
@@ -588,6 +606,9 @@
} catch (ArchitectException ex) {
throw new ArchitectRuntimeException(ex);
}
+
+ LoadSQLObjectAttributes(f, attributes);
+
return f;
}
}
@@ -612,6 +633,8 @@
if (sourceId != null) {
col.setSourceColumn((SQLColumn)
sqlObjectLoadIdMap.get(sourceId));
}
+
+ LoadSQLObjectAttributes(col, attributes);
return col;
}
@@ -619,22 +642,12 @@
/**
* Creates a SQLException instance and adds it to the
- * objectIdMap.
+ * objectIdMap. This ExceptionFactory is still used for loading older
+ * files.
*/
private class SQLExceptionFactory extends
AbstractObjectCreationFactory {
public Object createObject(Attributes attributes) {
- SQLExceptionNode exc = new SQLExceptionNode(null, null);
-
- String id = attributes.getValue("id");
- if (id != null) {
- sqlObjectLoadIdMap.put(id, exc);
- } else {
- logger.warn("No ID found in exception element while
loading project!");
- }
-
- exc.setMessage(attributes.getValue("message"));
-
- return exc;
+ return new Exception(attributes.getValue("message"));
}
}
@@ -670,6 +683,8 @@
JOptionPane.showMessageDialog(null, "Missing pktable or
fktable references for relationship id \""+id+"\"");
}
+ LoadSQLObjectAttributes(rel, attributes);
+
return rel;
}
}
@@ -730,6 +745,9 @@
index.setType(attributes.getValue("index-type"));
currentIndex = index;
+
+ LoadSQLObjectAttributes(index, attributes);
+
return index;
}
}
@@ -761,6 +779,8 @@
if (attributes.getValue("ascendingOrDescending") != null) {
col.setAscendingOrDescending(SQLIndex.AscendDescend.valueOf(attributes.getValue("ascendingOrDescending")));
}
+
+ LoadSQLObjectAttributes(col, attributes);
return col;
}
Modified: trunk/src/ca/sqlpower/architect/SQLCatalog.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLCatalog.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLCatalog.java Thu Dec 11 07:42:05 2008
@@ -122,7 +122,7 @@
return true;
}
- public void populate() throws ArchitectException {
+ public void populateImpl() throws ArchitectException {
if (populated) return;
logger.debug("SQLCatalog: populate starting");
Modified: trunk/src/ca/sqlpower/architect/SQLColumn.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLColumn.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLColumn.java Thu Dec 11 07:42:05 2008
@@ -404,7 +404,7 @@
// ------------------------- SQLObject support -------------------------
- public void populate() throws ArchitectException {
+ public void populateImpl() throws ArchitectException {
// SQLColumn: populate is a no-op
}
Modified: trunk/src/ca/sqlpower/architect/SQLDatabase.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLDatabase.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLDatabase.java Thu Dec 11 07:42:05
2008
@@ -87,7 +87,8 @@
return connectionPool != null;
}
- public synchronized void populate() throws ArchitectException {
+ public synchronized void populateImpl() throws ArchitectException {
+ logger.debug("SQLDatabase: is populated " + populated);
if (populated) return;
int oldSize = children.size();
@@ -545,8 +546,10 @@
getConnectionPool().getNumActive() + 1);
return (Connection)
getConnectionPool().borrowObject();
} catch (Exception e) {
- throw new ArchitectException(
- "Couldn't connect to database:
"+e.getMessage(), e);
+ ArchitectException ex = new ArchitectException(
+ "Couldn't connect to database:
"+e.getMessage(), e);
+ setChildrenInaccessibleReason(ex);
+ throw ex;
}
}
}
Modified: trunk/src/ca/sqlpower/architect/SQLIndex.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLIndex.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLIndex.java Thu Dec 11 07:42:05 2008
@@ -185,7 +185,7 @@
}
@Override
- protected void populate() throws ArchitectException {
+ protected void populateImpl() throws ArchitectException {
// nothing to do
}
@@ -448,7 +448,7 @@
* Indices are populated when first created, so populate is a no-op.
*/
@Override
- protected void populate() throws ArchitectException {
+ protected void populateImpl() throws ArchitectException {
// nothing to do
}
@@ -800,6 +800,7 @@
index.setPrimaryKeyIndex(source.isPrimaryKeyIndex());
index.setPhysicalName(source.getPhysicalName());
index.setClustered(source.isClustered());
+
index.setChildrenInaccessibleReason(source.getChildrenInaccessibleReason());
for (Column column : source.getChildren()) {
Column newColumn;
Modified: trunk/src/ca/sqlpower/architect/SQLObject.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLObject.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLObject.java Thu Dec 11 07:42:05 2008
@@ -98,6 +98,13 @@
* When this counter is > 0, the fireXXX methods will ignore secondary
changes.
*/
protected int magicDisableCount = 0;
+
+ /**
+ * This is the throwable that tells if the children of this component can
be reached
+ * or not. If this is null then the children can be reached. If it is not
null
+ * then there was an exception the last time the children were attempted
to be accessed.
+ */
+ private Throwable childrenInaccessibleReason = null;
public synchronized void setMagicEnabled(boolean enable) {
if (magicDisableCount < 0) {
@@ -181,6 +188,24 @@
* during addChild and removeChild requests.
*/
protected abstract void setParent(SQLObject parent);
+
+ /**
+ * Causes this SQLObject to load its children through populateImpl (if
any exist).
+ * This will do nothing if the object is already populated.
+ */
+ public void populate() throws ArchitectException {
+ if (populated) return;
+ childrenInaccessibleReason = null;
+ try {
+ populateImpl();
+ } catch (ArchitectException e) {
+ childrenInaccessibleReason = e;
+ throw e;
+ } catch (RuntimeException e) {
+ childrenInaccessibleReason = e;
+ throw e;
+ }
+ }
/**
* Causes this SQLObject to load its children (if any exist).
@@ -188,7 +213,7 @@
* not you need to do anything and return right away whenever
* possible.
*/
- protected abstract void populate() throws ArchitectException;
+ protected abstract void populateImpl() throws ArchitectException;
@@ -263,22 +288,10 @@
!
(children.get(0).getClass().isAssignableFrom(newChild.getClass())
|| newChild.getClass().isAssignableFrom(children.get(0).getClass())))
{
- ArchitectException ex;
- if (newChild instanceof SQLExceptionNode) {
-
- // long term, we want to dispose of SQLExceptionNode
altogether. This is a temporary workaround.
- SQLExceptionNode sen = (SQLExceptionNode) newChild;
- ex = new ArchitectException(
- "Can't add exception node here because there are
already other children. " +
- "See exception cause for the original exception.",
- sen.getException());
- } else {
- ex = new ArchitectException(
- "You Can't mix SQL Object Types! You gave: " +
- newChild.getClass().getName() +
- "; I need " + children.get(0).getClass());
- }
- throw ex;
+ throw new ArchitectException(
+ "You Can't mix SQL Object Types! You gave: " +
+ newChild.getClass().getName() +
+ "; I need " + children.get(0).getClass());
}
children.add(index, newChild);
newChild.setParent(this);
@@ -734,5 +747,20 @@
*/
public Set<String> getClientPropertyNames() {
return clientProperties.keySet();
+ }
+
+ public Throwable getChildrenInaccessibleReason() {
+ return childrenInaccessibleReason;
+ }
+
+ /**
+ * This setter will take in either a Throwable to set the inaccessible
reason
+ * to, for things like copy methods, or a string of the exception
message, for
+ * things like loading the exception.
+ */
+ public void setChildrenInaccessibleReason(Throwable message) {
+ Throwable oldVal = this.childrenInaccessibleReason;
+ this.childrenInaccessibleReason = message;
+ fireDbObjectChanged("childrenInaccessibleReason", oldVal,
childrenInaccessibleReason);
}
}
Modified: trunk/src/ca/sqlpower/architect/SQLObjectRoot.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLObjectRoot.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLObjectRoot.java Thu Dec 11 07:42:05
2008
@@ -32,7 +32,7 @@
return true;
}
- public void populate() throws ArchitectException {
+ public void populateImpl() throws ArchitectException {
return;
}
Modified: trunk/src/ca/sqlpower/architect/SQLRelationship.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLRelationship.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLRelationship.java Thu Dec 11
07:42:05 2008
@@ -286,6 +286,7 @@
setUpdateRule(relationshipToCopy.getUpdateRule());
setDeleteRule(relationshipToCopy.getDeleteRule());
setDeferrability(relationshipToCopy.getDeferrability());
+
setChildrenInaccessibleReason(relationshipToCopy.getChildrenInaccessibleReason());
}
/**
@@ -645,7 +646,11 @@
* <p>XXX: should be removed when SQLObject API gets generics
*/
public List<ColumnMapping> getMappings() {
- populate(); // doesn't do anything yet, but better safe than
sorry
+ try {
+ populate(); // doesn't do anything yet, but better safe than
sorry
+ } catch (ArchitectException e) {
+ throw new RuntimeException(e);
+ }
return Collections.unmodifiableList(children);
}
@@ -1030,7 +1035,7 @@
/**
* This class is not a lazy-loading class. This call does nothing.
*/
- public void populate() {
+ public void populateImpl() {
// nothing to do.
}
@@ -1282,7 +1287,7 @@
/**
* This class is not a lazy-loading class. This call does
nothing.
*/
- public void populate() throws ArchitectException {
+ public void populateImpl() throws ArchitectException {
return;
}
Modified: trunk/src/ca/sqlpower/architect/SQLSchema.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLSchema.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLSchema.java Thu Dec 11 07:42:05 2008
@@ -99,7 +99,7 @@
*
* @throws NullPointerException if this schema has no parent database.
*/
- public void populate() throws ArchitectException {
+ public void populateImpl() throws ArchitectException {
if (populated) return;
logger.debug("SQLSchema: populate starting");
Modified: trunk/src/ca/sqlpower/architect/SQLSequence.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLSequence.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLSequence.java Thu Dec 11 07:42:05
2008
@@ -88,7 +88,7 @@
* Does nothing because this type of object is not reverse-engineered.
*/
@Override
- protected void populate() throws ArchitectException {
+ protected void populateImpl() throws ArchitectException {
// no op
}
Modified: trunk/src/ca/sqlpower/architect/SQLTable.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/SQLTable.java (original)
+++ trunk/src/ca/sqlpower/architect/SQLTable.java Thu Dec 11 07:42:05 2008
@@ -155,6 +155,7 @@
SQLTable t = new SQLTable(parent, true);
t.setName(source.getName());
t.remarks = source.remarks;
+
t.setChildrenInaccessibleReason(source.getChildrenInaccessibleReason());
t.setPhysicalName(source.getPhysicalName());
t.physicalPrimaryKeyName = source.getPhysicalPrimaryKeyName();
@@ -842,7 +843,7 @@
* step. The various populate operations (columns, keys, indices) are
triggered
* by visiting the individual folders.
*/
- public void populate() throws ArchitectException {
+ public void populateImpl() throws ArchitectException {
// SQLTable: populate is a no-op
}
@@ -915,7 +916,7 @@
parent = (SQLTable) newParentTable;
}
- public void populate() throws ArchitectException {
+ public void populateImpl() throws ArchitectException {
populate(null);
}
Modified: trunk/src/ca/sqlpower/architect/swingui/DBTree.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/DBTree.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/DBTree.java Thu Dec 11 07:42:05
2008
@@ -33,6 +33,7 @@
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -58,7 +59,6 @@
import ca.sqlpower.architect.SQLCatalog;
import ca.sqlpower.architect.SQLColumn;
import ca.sqlpower.architect.SQLDatabase;
-import ca.sqlpower.architect.SQLExceptionNode;
import ca.sqlpower.architect.SQLIndex;
import ca.sqlpower.architect.SQLObject;
import ca.sqlpower.architect.SQLRelationship;
@@ -109,7 +109,7 @@
// ----------- CONSTRUCTORS ------------
- public DBTree(ArchitectSwingSession session) throws ArchitectException {
+ public DBTree(final ArchitectSwingSession session) throws
ArchitectException {
this.session = session;
setModel(new DBTreeModel(session.getRootObject()));
setUI(new MultiDragTreeUI());
@@ -131,6 +131,29 @@
tcr.addIconFilter(new ProfiledTableIconFilter());
setCellRenderer(tcr);
selectAllChildTablesAction = new SelectAllChildTablesAction();
+ addMouseListener(new MouseListener() {
+ public void mouseReleased(MouseEvent e) {
+ if (getPathForLocation(e.getX(), e.getY()) != null) {
+ Object node = getPathForLocation(e.getX(),
e.getY()).getLastPathComponent();
+ if (e.getClickCount() == 2 && node instanceof
SQLObject && ((SQLObject) node).getChildrenInaccessibleReason() != null) {
+
SPSUtils.showExceptionDialogNoReport(session.getArchitectFrame(),
+
Messages.getString("DBTree.exceptionNodeReport"), ((SQLObject)
node).getChildrenInaccessibleReason()); //$NON-NLS-1$
+ }
+ }
+ }
+ public void mousePressed(MouseEvent e) {
+ //no-op
+ }
+ public void mouseExited(MouseEvent e) {
+ //no-op
+ }
+ public void mouseEntered(MouseEvent e) {
+ //no-op
+ }
+ public void mouseClicked(MouseEvent e) {
+ //no-op
+ }
+ });
}
// ----------- INSTANCE METHODS ------------
@@ -468,7 +491,7 @@
//tree only has one child
if (!tempDB.isCatalogContainer() && !tempDB.isSchemaContainer()
&&
(!(tempDB.getChildCount() == 1) ||
-
!tempDB.getChild(0).getClass().equals(SQLExceptionNode.class)))
+
tempDB.getChildrenInaccessibleReason() == null))
{
//a new action is needed to maintain the
database variable
CompareToCurrentAction compareToCurrentAction = new
CompareToCurrentAction();
@@ -530,42 +553,29 @@
}
// Show exception details (SQLException node can appear anywhere in the
hierarchy)
- if (p != null && p.getLastPathComponent() instanceof
SQLExceptionNode) {
+ if (p != null && p.getLastPathComponent() instanceof SQLObject &&
((SQLObject) p.getLastPathComponent()).getChildrenInaccessibleReason() !=
null) {
newMenu.addSeparator();
- final SQLExceptionNode node = (SQLExceptionNode)
p.getLastPathComponent();
+ final SQLObject node = (SQLObject) p.getLastPathComponent();
newMenu.add(new JMenuItem(new
AbstractAction(Messages.getString("DBTree.showExceptionDetails")) {
//$NON-NLS-1$
public void actionPerformed(ActionEvent e) {
SPSUtils.showExceptionDialogNoReport(session.getArchitectFrame(),
-
Messages.getString("DBTree.exceptionNodeReport"), node.getException());
//$NON-NLS-1$
+
Messages.getString("DBTree.exceptionNodeReport"),
node.getChildrenInaccessibleReason()); //$NON-NLS-1$
}
}));
// If the sole child is an exception node, we offer the user a
way to re-try the operation
- try {
- final SQLObject parent = node.getParent();
- if (parent.getChildCount() == 1) {
- newMenu.add(new JMenuItem(new
AbstractAction(Messages.getString("DBTree.retryActionName")) { //$NON-NLS-1$
- public void actionPerformed(ActionEvent e) {
- parent.removeChild(0);
- parent.setPopulated(false);
- try {
- parent.getChildren(); // forces populate
- } catch (ArchitectException ex) {
- try {
- parent.addChild(new SQLExceptionNode(ex,
Messages.getString("DBTree.exceptionDuringRetry"))); //$NON-NLS-1$
- } catch
(ArchitectException e1) {
- logger.error("Couldn't add SQLExceptionNode to menu:", e1);
//$NON-NLS-1$
-
SPSUtils.showExceptionDialogNoReport(session.getArchitectFrame(),
- Messages.getString("DBTree.failedToAddSQLExceptionNode"),
e1); //$NON-NLS-1$
- }
-
SPSUtils.showExceptionDialogNoReport(session.getArchitectFrame(),
-
Messages.getString("DBTree.exceptionDuringRetry"), ex); //$NON-NLS-1$
- }
+ if (node.getChildrenInaccessibleReason() != null) {
+ newMenu.add(new JMenuItem(new
AbstractAction(Messages.getString("DBTree.retryActionName")) { //$NON-NLS-1$
+ public void actionPerformed(ActionEvent e) {
+ node.setPopulated(false);
+ try {
+ node.getChildren(); // forces populate
+ } catch (ArchitectException ex) {
+
SPSUtils.showExceptionDialogNoReport(session.getArchitectFrame(),
+
Messages.getString("DBTree.exceptionDuringRetry"), ex); //$NON-NLS-1$
}
- }));
- }
- } catch (ArchitectException ex) {
- logger.error("Couldn't count siblings of
SQLExceptionNode", ex); //$NON-NLS-1$
+ }
+ }));
}
}
@@ -732,13 +742,7 @@
@Override
public void cleanup() throws Exception {
if (getDoStuffException() != null) {
- // FIXME: SQLObject should have an "exception" property that's
not a child,
- // and client code shouldn't have to clean up populate
exceptions
- // like this
- mostRecentlyVisited.addChild(
- new SQLExceptionNode(
- getDoStuffException(),
-
Messages.getString("DBTree.errorDuringDbProbe"))); //$NON-NLS-1$
+ throw new RuntimeException(getDoStuffException());
}
}
}
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 Thu Dec 11
07:42:05 2008
@@ -96,7 +96,6 @@
import ca.sqlpower.architect.SQLCatalog;
import ca.sqlpower.architect.SQLColumn;
import ca.sqlpower.architect.SQLDatabase;
-import ca.sqlpower.architect.SQLExceptionNode;
import ca.sqlpower.architect.SQLObject;
import ca.sqlpower.architect.SQLObjectEvent;
import ca.sqlpower.architect.SQLObjectListener;
@@ -1591,7 +1590,6 @@
Iterator it =
sourceSchema.getChildren().iterator();
while (it.hasNext() &&
!isCancelled()) {
Object nextTable = it.next();
- if (nextTable instanceof SQLExceptionNode)
continue;
SQLTable sourceTable =
(SQLTable) nextTable;
message =
ArchitectUtils.truncateString(sourceTable.getName());
TablePane tp =
importTableCopy(sourceTable, preferredLocation);
@@ -1607,7 +1605,6 @@
Iterator it =
sourceSchema.getChildren().iterator();
while (it.hasNext()
&& !isCancelled()) {
Object
nextTable = it.next();
- if (nextTable instanceof
SQLExceptionNode) continue;
SQLTable sourceTable = (SQLTable)
nextTable;
message
= ArchitectUtils.truncateString(sourceTable.getName());
TablePane tp = importTableCopy(sourceTable, preferredLocation);
@@ -1618,7 +1615,6 @@
} else {
while (cit.hasNext() &&
!isCancelled()) {
Object nextTable = cit.next();
- if (nextTable instanceof SQLExceptionNode)
continue;
SQLTable
sourceTable = (SQLTable) nextTable;
message =
ArchitectUtils.truncateString(sourceTable.getName());
TablePane tp =
importTableCopy(sourceTable, preferredLocation);
Modified: trunk/src/ca/sqlpower/architect/swingui/SwingUIProject.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/SwingUIProject.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/SwingUIProject.java Thu Dec 11
07:42:05 2008
@@ -51,7 +51,6 @@
import ca.sqlpower.architect.SQLCatalog;
import ca.sqlpower.architect.SQLColumn;
import ca.sqlpower.architect.SQLDatabase;
-import ca.sqlpower.architect.SQLExceptionNode;
import ca.sqlpower.architect.SQLIndex;
import ca.sqlpower.architect.SQLObject;
import ca.sqlpower.architect.SQLRelationship;
@@ -1171,6 +1170,10 @@
// properties of all SQLObject types
propNames.put("physicalName", o.getPhysicalName()); //$NON-NLS-1$
propNames.put("name", o.getName()); // note: there was no name
attrib for SQLDatabase, SQLRelationship.ColumnMapping, and SQLExceptionNode
//$NON-NLS-1$
+
+ if (o.getChildrenInaccessibleReason() != null) {
+ propNames.put("sql-exception",
o.getChildrenInaccessibleReason().getMessage()); //$NON-NLS-1$
+ }
if (o instanceof SQLDatabase) {
id = "DB"+sqlObjectSaveIdMap.size(); //$NON-NLS-1$
@@ -1233,10 +1236,6 @@
type = "column-mapping"; //$NON-NLS-1$
propNames.put("pk-column-ref",
sqlObjectSaveIdMap.get(((SQLRelationship.ColumnMapping) o).getPkColumn()));
//$NON-NLS-1$
propNames.put("fk-column-ref",
sqlObjectSaveIdMap.get(((SQLRelationship.ColumnMapping) o).getFkColumn()));
//$NON-NLS-1$
- } else if (o instanceof SQLExceptionNode) {
- id = "EXC"+sqlObjectSaveIdMap.size(); //$NON-NLS-1$
- type = "sql-exception"; //$NON-NLS-1$
- propNames.put("message", ((SQLExceptionNode) o).getMessage());
//$NON-NLS-1$
} else if (o instanceof SQLIndex) {
id = "IDX"+sqlObjectSaveIdMap.size(); //$NON-NLS-1$
type = "index"; //$NON-NLS-1$
@@ -1265,7 +1264,7 @@
throw new UnsupportedOperationException("Whoops, the SQLObject
type " //$NON-NLS-1$
+o.getClass().getName()+" is not supported!");
//$NON-NLS-1$
}
-
+
sqlObjectSaveIdMap.put(o, id);
boolean skipChildren = false;
@@ -1273,11 +1272,7 @@
//ioo.print("<"+type+" hashCode=\""+o.hashCode()+"\"
id=\""+id+"\" "); // use this for debugging duplicate object problems
ioo.print(out, "<"+type+" id="+quote(id)+" "); //$NON-NLS-1$
//$NON-NLS-2$ //$NON-NLS-3$
- if (o.allowsChildren() && o.isPopulated() && o.getChildCount() ==
1 && o.getChild(0) instanceof SQLExceptionNode) {
- // if the only child is an exception node, just save the
parent as non-populated
- ioo.niprint(out, "populated=\"false\" "); //$NON-NLS-1$
- skipChildren = true;
- } else if ( (!getSession().isSavingEntireSource()) &&
(!o.isPopulated()) ) {
+ if ( (!getSession().isSavingEntireSource()) && (!o.isPopulated())
) {
ioo.niprint(out, "populated=\"false\" "); //$NON-NLS-1$
} else {
ioo.niprint(out, "populated=\"true\" "); //$NON-NLS-1$
Modified:
trunk/src/ca/sqlpower/architect/swingui/dbtree/DBTreeCellRenderer.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/dbtree/DBTreeCellRenderer.java
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/dbtree/DBTreeCellRenderer.java
Thu Dec 11 07:42:05 2008
@@ -67,6 +67,7 @@
public static final ImageIcon PK_ICON = new
ImageIcon(DBTreeCellRenderer.class.getResource("icons/Index_key16.png"));
public static final ImageIcon UNIQUE_INDEX_ICON = new
ImageIcon(DBTreeCellRenderer.class.getResource("icons/Index_unique16.png"));
public static final ImageIcon COLUMN_ICON = new
ImageIcon(DBTreeCellRenderer.class.getResource("icons/Column16.png"));
+ public static final ImageIcon ERROR_ICON = new
ImageIcon(DBTreeCellRenderer.class.getResource("icons/stop16.png"));
private final List<IconFilter> iconFilterChain = new
ArrayList<IconFilter>();
@@ -82,7 +83,13 @@
int row,
boolean hasFocus) {
setText(value.toString());
- if (value instanceof SQLDatabase) {
+ setToolTipText(getText());
+
+ if (value instanceof SQLObject && ((SQLObject)
value).getChildrenInaccessibleReason() != null) {
+ logger.debug("Children are not accessible from the node " +
((SQLObject) value).getName());
+ setIcon(ERROR_ICON);
+ setToolTipText("Inaccessible: " + ((SQLObject)
value).getChildrenInaccessibleReason());
+ } else if (value instanceof SQLDatabase) {
SQLDatabase db = (SQLDatabase) value;
if (db.isPlayPenDatabase()) {
setIcon(TARGET_DB_ICON);
@@ -155,7 +162,6 @@
setForeground(Color.lightGray);
}
}
- setToolTipText(getText());
if (value instanceof SQLObject || value == null) {
for (IconFilter filter : getIconFilterChain()) {
Modified: trunk/src/ca/sqlpower/architect/swingui/dbtree/DBTreeModel.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/dbtree/DBTreeModel.java
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/dbtree/DBTreeModel.java Thu Dec
11 07:42:05 2008
@@ -35,13 +35,11 @@
import ca.sqlpower.architect.ArchitectException;
import ca.sqlpower.architect.ArchitectRuntimeException;
import ca.sqlpower.architect.ArchitectUtils;
-import ca.sqlpower.architect.SQLExceptionNode;
import ca.sqlpower.architect.SQLObject;
import ca.sqlpower.architect.SQLObjectEvent;
import ca.sqlpower.architect.SQLObjectListener;
import ca.sqlpower.architect.SQLObjectRoot;
import ca.sqlpower.architect.SQLRelationship;
-import ca.sqlpower.swingui.SPSUtils;
public class DBTreeModel implements TreeModel, SQLObjectListener,
java.io.Serializable {
@@ -78,23 +76,23 @@
public Object getChild(Object parent, int index) {
if (logger.isDebugEnabled())
logger.debug("DBTreeModel.getChild("+parent+","+index+")"); //$NON-NLS-1$
//$NON-NLS-2$ //$NON-NLS-3$
+ SQLObject sqlParent = (SQLObject) parent;
try {
- if (logger.isDebugEnabled()) logger.debug("returning "+((SQLObject)
parent).getChild(index)); //$NON-NLS-1$
- return ((SQLObject) parent).getChild(index);
+ if (logger.isDebugEnabled())
logger.debug("returning "+sqlParent.getChild(index)); //$NON-NLS-1$
+ return sqlParent.getChild(index);
} catch (Exception e) {
- SQLExceptionNode fakeChild = putExceptionNodeUnder((SQLObject) parent,
e);
- return fakeChild;
+ throw new RuntimeException(e);
}
}
public int getChildCount(Object parent) {
if (logger.isDebugEnabled())
logger.debug("DBTreeModel.getChildCount("+parent+")"); //$NON-NLS-1$
//$NON-NLS-2$
+ SQLObject sqlParent = (SQLObject) parent;
try {
- if (logger.isDebugEnabled()) logger.debug("returning "+((SQLObject)
parent).getChildCount()); //$NON-NLS-1$
- return ((SQLObject) parent).getChildCount();
+ if (logger.isDebugEnabled())
logger.debug("returning "+sqlParent.getChildCount()); //$NON-NLS-1$
+ return sqlParent.getChildCount();
} catch (Exception e) {
- putExceptionNodeUnder((SQLObject) parent, e);
- return 1; // XXX: could be incorrect if exception was not a populate
problem!
+ throw new RuntimeException(e);
}
}
@@ -254,49 +252,6 @@
return nodePaths;
}
- /**
- * Creates a SQLExceptionNode with the given Throwable and places
- * it under parent.
- *
- * @return the node that has been added to parent.
- */
- protected SQLExceptionNode putExceptionNodeUnder(final SQLObject parent,
Throwable ex) {
- // dig for root cause and message
- logger.info("Adding exception node under "+parent, ex);
//$NON-NLS-1$
- String message = ex.getMessage();
- Throwable cause = ex;
- while (cause.getCause() != null) {
- cause = cause.getCause();
- if (cause.getMessage() != null &&
cause.getMessage().length() > 0) {
- message = cause.getMessage();
- }
- }
-
- if (message == null || message.length() == 0) {
- message = "Check application log for details";
//$NON-NLS-1$
- }
-
- final SQLExceptionNode excNode = new SQLExceptionNode(ex,
message);
- excNode.setParent((SQLObject) parent);
-
- /* This is likely to fail, but it should convince the parent that it is
populated */
- try {
- parent.getChildCount();
- } catch (ArchitectException e) {
- logger.error("Couldn't populate parent node of exception");
//$NON-NLS-1$
- }
-
- try {
- for(int i=0; i< parent.getChildCount(); i++){
- parent.removeChild(0);
- }
- parent.addChild(excNode);
- } catch (ArchitectException e) {
- logger.error("Couldn't add SQLExceptionNode \""+excNode.getName()+"\"
to tree model:", e); //$NON-NLS-1$ //$NON-NLS-2$
- SPSUtils.showExceptionDialogNoReport("Failed to add SQLExceptionNode to
tree model.", e); //$NON-NLS-1$
- }
- return excNode;
- }
// --------------------- SQLObject listener support
-----------------------
public void dbChildrenInserted(SQLObjectEvent e) {
Added: trunk/src/ca/sqlpower/architect/swingui/dbtree/icons/stop16.png
==============================================================================
Binary file. No diff available.