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;
+    }
+}

Reply via email to