Author: tfmorris
Date: 2008-09-06 14:07:04-0700
New Revision: 15681
Modified:
trunk/src/argouml-app/src/org/argouml/application/events/ArgoEventPump.java
trunk/src/argouml-app/src/org/argouml/kernel/ProjectManager.java
trunk/src/argouml-app/src/org/argouml/ui/ProjectBrowser.java
trunk/src/argouml-app/src/org/argouml/uml/ui/ActionSaveProject.java
Log:
RESOLVED - task 5368: ConcurrentModificationException on Sequence Diagram load
http://argouml.tigris.org/issues/show_bug.cgi?id=5368
Modified: trunk/src/argouml-app/src/org/argouml/application/events/ArgoEventPump.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/application/events/ArgoEventPump.java?view=diff&rev=15681&p1=trunk/src/argouml-app/src/org/argouml/application/events/ArgoEventPump.java&p2=trunk/src/argouml-app/src/org/argouml/application/events/ArgoEventPump.java&r1=15680&r2=15681
==============================================================================
--- trunk/src/argouml-app/src/org/argouml/application/events/ArgoEventPump.java (original)
+++ trunk/src/argouml-app/src/org/argouml/application/events/ArgoEventPump.java 2008-09-06 14:07:04-0700
@@ -27,12 +27,18 @@
import java.util.ArrayList;
import java.util.List;
+import javax.swing.SwingUtilities;
+
import org.apache.log4j.Logger;
import org.argouml.application.api.ArgoEventListener;
/**
- * ArgoEventPump is an eventhandler which handles events regarding
- * the loading and unloading of modules.
+ * ArgoEventPump is an event dispatcher which handles events that are global
+ * in nature for the entire application.
+ * <p>
+ * TODO: DiagramAppearance and Notation events are not application-wide and will
+ * be moved from here to someplace more specific in the future so that they can
+ * be managed on a per-project or per-diagram basis.
*/
public final class ArgoEventPump {
/**
@@ -147,13 +153,32 @@
/**
* Handle firing a notation event.
+ * <p>
+ * TODO: This needs to be managed on a per-diagram or per-project basis.
*
* @param event The event to be fired.
* @param listener The listener.
*/
private void handleFireNotationEvent(
- ArgoNotationEvent event,
- ArgoNotationEventListener listener) {
+ final ArgoNotationEvent event,
+ final ArgoNotationEventListener listener) {
+
+ // Notation events are likely to cause GEF/Swing operations, so we
+ // dispatch them on the Swing event thread as a convenience so that
+ // the receiving notationChanged() methods don't need to deal with it
+ if (SwingUtilities.isEventDispatchThread()) {
+ fireNotationEventInternal(event, listener);
+ } else {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ fireNotationEventInternal(event, listener);
+ }
+ });
+ }
+ }
+
+ private void fireNotationEventInternal(ArgoNotationEvent event,
+ ArgoNotationEventListener listener) {
switch (event.getEventType()) {
case ArgoEventTypes.NOTATION_CHANGED :
listener.notationChanged(event);
@@ -186,13 +211,29 @@
/**
* Handle firing a diagram appearance event.
- *
+ * <p>
+ * TODO: This needs to be managed on a per-diagram or per-project basis.
+ *
* @param event The event to be fired.
* @param listener The listener.
*/
private void handleFireDiagramAppearanceEvent(
- ArgoDiagramAppearanceEvent event,
- ArgoDiagramAppearanceEventListener listener) {
+ final ArgoDiagramAppearanceEvent event,
+ final ArgoDiagramAppearanceEventListener listener) {
+ if (SwingUtilities.isEventDispatchThread()) {
+ fireDiagramAppearanceEventInternal(event, listener);
+ } else {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ fireDiagramAppearanceEventInternal(event, listener);
+ }
+ });
+ }
+ }
+
+ private void fireDiagramAppearanceEventInternal(
+ final ArgoDiagramAppearanceEvent event,
+ final ArgoDiagramAppearanceEventListener listener) {
switch (event.getEventType()) {
case ArgoEventTypes.DIAGRAM_FONT_CHANGED :
listener.diagramFontChanged(event);
Modified: trunk/src/argouml-app/src/org/argouml/kernel/ProjectManager.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/kernel/ProjectManager.java?view=diff&rev=15681&p1=trunk/src/argouml-app/src/org/argouml/kernel/ProjectManager.java&p2=trunk/src/argouml-app/src/org/argouml/kernel/ProjectManager.java&r1=15680&r2=15681
==============================================================================
--- trunk/src/argouml-app/src/org/argouml/kernel/ProjectManager.java (original)
+++ trunk/src/argouml-app/src/org/argouml/kernel/ProjectManager.java 2008-09-06 14:07:04-0700
@@ -215,12 +215,21 @@
}
/**
- * Returns the current project.<p>
- *
- * If there is no project, a new one is created
- * (unless we are busy creating one).
- *
- * @return Project the current project
+ * Returns the current project (ie the project which must recently had the
+ * user focus) or null if there is no current project.
+ * <p>
+ * This should only be used by callers who need to know the global state.
+ * Most things which need a project want the project that contains them,
+ * which they can discover by traversing their containing elements (e.g.
+ * Fig->Diagram->Project).
+ * <p>
+ * <em>NOTE:</em>Callers of this method must be prepared to receive a null
+ * return value. Currently, if there is no project, a new one is created
+ * (unless we are busy creating one), but this behavior is not guaranteed
+ * and will change ArgoUML allows multiple open projects (or no open
+ * projects).
+ *
+ * @return Project the current project or null if none
*/
public Project getCurrentProject() {
if (currentProject == null && !creatingCurrentProject) {
@@ -315,6 +324,8 @@
/**
* @return true is the save action is currently enabled
+ * <p>
+ * TODO: This needs to get the save-enabled status for the current project.
*/
public boolean isSaveActionEnabled() {
return this.saveAction.isEnabled();
@@ -324,7 +335,8 @@
* Notify the gui that the
* current project's save state has changed. There are 2 receivers:
* the SaveProject tool icon and the title bar (for showing a *).
- *
+ * <p>
+ * TODO: This needs to be managed on a per-project basis.
* @param newValue The new state.
*/
public void setSaveEnabled(boolean newValue) {
@@ -353,6 +365,7 @@
* We must add this to the UndoManager.
*
* @param command the command.
+ * @return result of the command, if any
* @see org.argouml.model.ModelCommandCreationObserver#execute(ModelCommand)
*/
public Object execute(final ModelCommand command) {
Modified: trunk/src/argouml-app/src/org/argouml/ui/ProjectBrowser.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/ui/ProjectBrowser.java?view=diff&rev=15681&p1=trunk/src/argouml-app/src/org/argouml/ui/ProjectBrowser.java&p2=trunk/src/argouml-app/src/org/argouml/ui/ProjectBrowser.java&r1=15680&r2=15681
==============================================================================
--- trunk/src/argouml-app/src/org/argouml/ui/ProjectBrowser.java (original)
+++ trunk/src/argouml-app/src/org/argouml/ui/ProjectBrowser.java 2008-09-06 14:07:04-0700
@@ -333,7 +333,9 @@
// rid of this.
Project p =
ProjectManager.getManager().getCurrentProject();
- p.getUndoManager().startInteraction("Focus");
+ if (p != null) {
+ p.getUndoManager().startInteraction("Focus");
+ }
/* This next line is ideal for debugging the taborder
* (focus traversal), see e.g. issue 1849.
*/
@@ -739,7 +741,7 @@
}
/**
* Set the save indicator (the * after the title) to appear depending on
- * the curreny save action enabled status.
+ * the current save action enabled status.
*/
public void showSaveIndicator() {
titleHandler.buildTitle(null, null);
@@ -1574,6 +1576,16 @@
PersistenceManager pm = PersistenceManager.getInstance();
Project oldProject = ProjectManager.getManager().getCurrentProject();
+ if (oldProject != null) {
+ // Remove the old project first. It's wasteful to create a temp
+ // empty project, but too much of ArgoUML depends on having a
+ // current project
+ Project p = ProjectManager.getManager().makeEmptyProject();
+ ProjectManager.getManager().setCurrentProject(p);
+ ProjectManager.getManager().removeProject(oldProject);
+ oldProject = p;
+ }
+
boolean success = false;
// TODO:
@@ -1598,7 +1610,7 @@
// * appearing in title bar and the save enabling as models are
// updated
// TODO: Do we still need this now the save enablement is improved?
- AbstractAction rememberedSaveAction = this.saveAction;
+ final AbstractAction rememberedSaveAction = this.saveAction;
this.saveAction = null;
ProjectManager.getManager().setSaveAction(null);
try {
@@ -1747,11 +1759,17 @@
} finally {
// Make sure save action is always reinstated
this.saveAction = rememberedSaveAction;
- ProjectManager.getManager().setSaveAction(
- rememberedSaveAction);
- if (success) {
- rememberedSaveAction.setEnabled(false);
- }
+
+ // We clear the save-required flag on the Swing event thread
+ // in the hopes that it gets done after any other background
+ // work (listener updates) that is being done there
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ ProjectManager.getManager().setSaveAction(
+ rememberedSaveAction);
+ rememberedSaveAction.setEnabled(false);
+ }
+ });
}
}
}
Modified: trunk/src/argouml-app/src/org/argouml/uml/ui/ActionSaveProject.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/uml/ui/ActionSaveProject.java?view=diff&rev=15681&p1=trunk/src/argouml-app/src/org/argouml/uml/ui/ActionSaveProject.java&p2=trunk/src/argouml-app/src/org/argouml/uml/ui/ActionSaveProject.java&r1=15680&r2=15681
==============================================================================
--- trunk/src/argouml-app/src/org/argouml/uml/ui/ActionSaveProject.java (original)
+++ trunk/src/argouml-app/src/org/argouml/uml/ui/ActionSaveProject.java 2008-09-06 14:07:04-0700
@@ -82,16 +82,28 @@
}
/**
- * Set the enabled state of the save action.
- * When we become enabled inform the user by highlighting the title bar
- * with an asterisk.
- * This method is undoable.
+ * Set the enabled state of the save action. When we become enabled inform
+ * the user by highlighting the title bar with an asterisk. This method is
+ * undoable. This method is synchronized so that it can be used from any
+ * thread without external synchronization.
+ *
* @param isEnabled new state for save command
*/
- public void setEnabled(final boolean isEnabled) {
+ @Override
+ public synchronized void setEnabled(final boolean isEnabled) {
if (isEnabled == this.enabled) {
return;
}
+ if (LOG.isDebugEnabled()) {
+ if (!enabled && isEnabled) {
+ Throwable throwable = new Throwable();
+ throwable.fillInStackTrace();
+ LOG.debug("Save action enabled by ", throwable);
+ } else {
+ LOG.debug("Save state changed from " + enabled + " to "
+ + isEnabled);
+ }
+ }
internalSetEnabled(isEnabled);
}
@@ -104,4 +116,4 @@
ProjectBrowser.getInstance().showSaveIndicator();
}
-} /* end class ActionSaveProject */
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.