Revision: 3352
Author: [email protected]
Date: Thu Mar 4 08:03:38 2010
Log: NEW - bug 2722: Unable to open existing project
http://trillian.sqlpower.ca/bugzilla/show_bug.cgi?id=2722
Added a prompt for users opening a file that was saved with a newer version
of Architect. The user will be asked if they
want to upgrade as well. To make the tests pass successfully the user
prompter is being set to a default prompter
otherwise the tests will pause for user input.
http://code.google.com/p/power-architect/source/detail?r=3352
Added:
/trunk/src/ca/sqlpower/architect/DigesterCancelledException.java
Modified:
/trunk/regress/ca/sqlpower/architect/swingui/ArchitectSwingSessionImplTest.java
/trunk/src/ca/sqlpower/architect/ProjectLoader.java
/trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionImpl.java
=======================================
--- /dev/null
+++ /trunk/src/ca/sqlpower/architect/DigesterCancelledException.java Thu
Mar 4 08:03:38 2010
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2010, 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;
+
+/**
+ * This exception can be thrown from classes in the digester to cause the
+ * digester to stop loading.
+ */
+public class DigesterCancelledException extends RuntimeException {
+
+}
=======================================
---
/trunk/regress/ca/sqlpower/architect/swingui/ArchitectSwingSessionImplTest.java
Mon Jan 25 09:01:33 2010
+++
/trunk/regress/ca/sqlpower/architect/swingui/ArchitectSwingSessionImplTest.java
Thu Mar 4 08:03:38 2010
@@ -37,6 +37,7 @@
import ca.sqlpower.sqlobject.SQLObjectUtils;
import ca.sqlpower.sqlobject.SQLRelationship;
import ca.sqlpower.sqlobject.SQLTable;
+import ca.sqlpower.util.DefaultUserPrompterFactory;
public class ArchitectSwingSessionImplTest extends TestCase {
@@ -167,6 +168,7 @@
ArchitectSwingSessionContext context = new StubContext();
ArchitectSwingSession session = context.createSession(false);
assertTrue(session.isNew());
+ ((ArchitectSwingSessionImpl) session).setUserPrompterFactory(new
DefaultUserPrompterFactory());
ByteArrayInputStream r = new
ByteArrayInputStream(testData.getBytes());
session.getProjectLoader().load(r, new PlDotIni());
@@ -215,6 +217,7 @@
public void testSaveAndLoadRelationshipLineType() throws Exception {
ArchitectSwingSessionContext context = new StubContext();
ArchitectSwingSession session = context.createSession(false);
+ ((ArchitectSwingSessionImpl) session).setUserPrompterFactory(new
DefaultUserPrompterFactory());
session.getProjectLoader().load(new
ByteArrayInputStream(testData.getBytes()), new PlDotIni());
boolean newValueForStraightLines
= !session.getRelationshipLinesDirect();
@@ -224,6 +227,7 @@
session.getProjectLoader().save(out, "utf-8");
ArchitectSwingSession loadedSession = context.createSession(false);
+ ((ArchitectSwingSessionImpl)
loadedSession).setUserPrompterFactory(new DefaultUserPrompterFactory());
loadedSession.getProjectLoader().load(new
ByteArrayInputStream(out.toByteArray()), new PlDotIni());
assertEquals(newValueForStraightLines,
loadedSession.getRelationshipLinesDirect());
=======================================
--- /trunk/src/ca/sqlpower/architect/ProjectLoader.java Thu Feb 25 09:46:15
2010
+++ /trunk/src/ca/sqlpower/architect/ProjectLoader.java Thu Mar 4 08:03:38
2010
@@ -37,6 +37,7 @@
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.digester.AbstractObjectCreationFactory;
import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.Rule;
import org.apache.commons.digester.SetPropertiesRule;
import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
@@ -65,6 +66,12 @@
import ca.sqlpower.sqlobject.SQLIndex.Column;
import ca.sqlpower.sqlobject.SQLRelationship.Deferrability;
import ca.sqlpower.sqlobject.SQLRelationship.UpdateDeleteRule;
+import ca.sqlpower.swingui.SPSUtils;
+import ca.sqlpower.util.BrowserUtil;
+import ca.sqlpower.util.UserPrompter;
+import ca.sqlpower.util.UserPrompter.UserPromptOptions;
+import ca.sqlpower.util.UserPrompter.UserPromptResponse;
+import ca.sqlpower.util.UserPrompterFactory.UserPromptType;
import ca.sqlpower.xml.UnescapingSaxParser;
public class ProjectLoader {
@@ -198,6 +205,11 @@
digester = setupDigester();
digester.parse(uin);
} catch (SAXException ex) {
+ //The digester likes to wrap the cancelled exception in a
SAXException.
+ if (ex.getException() instanceof
DigesterCancelledException) {
+ //Digeseter was cancelled by the user. Do not load
anything.
+ return;
+ }
logger.error("SAX Exception in project file parse!", ex);
String message;
if (digester == null) {
@@ -293,6 +305,42 @@
d.setValidating(false);
d.push(session);
+ //app version number
+ d.addRule("architect-project", new Rule() {
+ @Override
+ public void begin(String namespace, String name, Attributes
attributes) throws Exception {
+ String appVersion = attributes.getValue("appversion");
+ String loadingMessage;
+ try {
+ if (appVersion == null) {
+ loadingMessage = "The version of the file cannot
be found.";
+ } else if (ArchitectVersion.APP_FULL_VERSION.compareTo(
+ new ArchitectVersion(appVersion)) < 0) {
+ loadingMessage = "This file was last saved with a
newer version.\n" +
+ "Loading with an older version may cause data
loss.";
+ } else {
+ return;
+ }
+ } catch (Exception e) {
+ loadingMessage = "The version of the file cannot be
understood.";
+ }
+ UserPrompter loadingWarningPrompt =
session.createUserPrompter(
+ loadingMessage + "\nDo you wish to try and open
the file?",
+ UserPromptType.BOOLEAN,
UserPromptOptions.OK_NOTOK_CANCEL,
+ UserPromptResponse.OK, UserPromptResponse.OK, "Try
loading",
+ "Upgrade...", "Cancel");
+ UserPromptResponse response =
loadingWarningPrompt.promptUser();
+ if (response == UserPromptResponse.OK) {
+ //continue to try loading
+ } else if (response == UserPromptResponse.NOT_OK) {
+ BrowserUtil.launch(SPSUtils.SQLP_ARCHITECT_URL);
+ throw new DigesterCancelledException();
+ } else if (response == UserPromptResponse.CANCEL) {
+ throw new DigesterCancelledException();
+ }
+ }
+ });
+
// project name
d.addCallMethod("architect-project/project-name", "setName", 0);
// argument is element body text
=======================================
--- /trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionImpl.java
Wed Mar 3 12:03:13 2010
+++ /trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionImpl.java
Thu Mar 4 08:03:38 2010
@@ -92,6 +92,7 @@
import ca.sqlpower.util.SQLPowerUtils;
import ca.sqlpower.util.TransactionEvent;
import ca.sqlpower.util.UserPrompter;
+import ca.sqlpower.util.UserPrompterFactory;
import ca.sqlpower.util.UserPrompter.UserPromptOptions;
import ca.sqlpower.util.UserPrompter.UserPromptResponse;
@@ -192,7 +193,7 @@
* This user prompter factory will create all the necessary GUI user
prompts
* for Architect.
*/
- private final SwingUIUserPrompterFactory swinguiUserPrompterFactory;
+ private UserPrompterFactory swinguiUserPrompterFactory;
/**
* A colour chooser used by the {...@link RelationshipEditPanel}, and
possibly
@@ -354,7 +355,9 @@
frame = new ArchitectFrame(this, null);
}
- swinguiUserPrompterFactory.setParentFrame(frame);
+ if (swinguiUserPrompterFactory instanceof
SwingUIUserPrompterFactory) {
+ ((SwingUIUserPrompterFactory)
swinguiUserPrompterFactory).setParentFrame(frame);
+ }
// MUST be called after constructed to set up the actions
frame.init();
@@ -1141,4 +1144,14 @@
public void showPreferenceDialog(Window owner) {
prefsEditor.showPreferencesDialog(owner,
ArchitectSwingSessionImpl.this);
}
-}
+
+ /**
+ * Protected method for setting the user prompter factory delegate to
+ * something other than the UI user prompter factory. This allows
+ * the tests to define a user prompter factory that does not block
+ * waiting for user response.
+ */
+ void setUserPrompterFactory(UserPrompterFactory newUPF) {
+ swinguiUserPrompterFactory = newUPF;
+ }
+}