Coverage Report - org.argouml.ui.ProjectBrowser
 
Classes in this File Line Coverage Branch Coverage Complexity
ProjectBrowser
40%
205/511
25%
54/214
3.065
ProjectBrowser$1
100%
7/7
75%
6/8
3.065
ProjectBrowser$2
40%
8/20
21%
3/14
3.065
ProjectBrowser$3
0%
0/2
N/A
3.065
ProjectBrowser$4
0%
0/4
N/A
3.065
ProjectBrowser$5
0%
0/4
N/A
3.065
ProjectBrowser$6
0%
0/4
N/A
3.065
ProjectBrowser$7
0%
0/4
N/A
3.065
ProjectBrowser$Position
100%
3/3
N/A
3.065
ProjectBrowser$TitleHandler
88%
22/25
72%
16/22
3.065
ProjectBrowser$TitleHandler$1
100%
3/3
N/A
3.065
ProjectBrowser$WindowCloser
40%
2/5
N/A
3.065
 
 1  
 /* $Id: ProjectBrowser.java 18816 2010-10-27 15:51:09Z tfmorris $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    euluis
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2009 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.ui;
 40  
 
 41  
 import java.awt.BorderLayout;
 42  
 import java.awt.Component;
 43  
 import java.awt.Dimension;
 44  
 import java.awt.Font;
 45  
 import java.awt.Image;
 46  
 import java.awt.KeyboardFocusManager;
 47  
 import java.awt.Window;
 48  
 import java.awt.event.ComponentAdapter;
 49  
 import java.awt.event.ComponentEvent;
 50  
 import java.awt.event.WindowAdapter;
 51  
 import java.awt.event.WindowEvent;
 52  
 import java.beans.PropertyChangeEvent;
 53  
 import java.beans.PropertyChangeListener;
 54  
 import java.io.File;
 55  
 import java.io.IOException;
 56  
 import java.io.PrintWriter;
 57  
 import java.io.StringWriter;
 58  
 import java.lang.reflect.InvocationTargetException;
 59  
 import java.lang.reflect.Method;
 60  
 import java.net.URI;
 61  
 import java.text.MessageFormat;
 62  
 import java.util.ArrayList;
 63  
 import java.util.Collection;
 64  
 import java.util.HashMap;
 65  
 import java.util.Iterator;
 66  
 import java.util.List;
 67  
 import java.util.Locale;
 68  
 import java.util.Map;
 69  
 
 70  
 import javax.swing.AbstractAction;
 71  
 import javax.swing.ImageIcon;
 72  
 import javax.swing.JDialog;
 73  
 import javax.swing.JFileChooser;
 74  
 import javax.swing.JFrame;
 75  
 import javax.swing.JMenuBar;
 76  
 import javax.swing.JOptionPane;
 77  
 import javax.swing.JPanel;
 78  
 import javax.swing.JToolBar;
 79  
 import javax.swing.SwingUtilities;
 80  
 
 81  
 import org.apache.log4j.Logger;
 82  
 import org.argouml.application.api.AbstractArgoJPanel;
 83  
 import org.argouml.application.api.Argo;
 84  
 import org.argouml.application.events.ArgoEventPump;
 85  
 import org.argouml.application.events.ArgoEventTypes;
 86  
 import org.argouml.application.events.ArgoStatusEvent;
 87  
 import org.argouml.application.helpers.ResourceLoaderWrapper;
 88  
 import org.argouml.cognitive.Designer;
 89  
 import org.argouml.configuration.Configuration;
 90  
 import org.argouml.configuration.ConfigurationKey;
 91  
 import org.argouml.i18n.Translator;
 92  
 import org.argouml.kernel.Command;
 93  
 import org.argouml.kernel.NonUndoableCommand;
 94  
 import org.argouml.kernel.Project;
 95  
 import org.argouml.kernel.ProjectManager;
 96  
 import org.argouml.model.Model;
 97  
 import org.argouml.model.XmiReferenceException;
 98  
 import org.argouml.model.XmiReferenceRuntimeException;
 99  
 import org.argouml.persistence.AbstractFilePersister;
 100  
 import org.argouml.persistence.OpenException;
 101  
 import org.argouml.persistence.PersistenceManager;
 102  
 import org.argouml.persistence.ProjectFilePersister;
 103  
 import org.argouml.persistence.ProjectFileView;
 104  
 import org.argouml.persistence.UmlVersionException;
 105  
 import org.argouml.persistence.VersionException;
 106  
 import org.argouml.persistence.XmiFormatException;
 107  
 import org.argouml.taskmgmt.ProgressMonitor;
 108  
 import org.argouml.ui.cmd.GenericArgoMenuBar;
 109  
 import org.argouml.ui.targetmanager.TargetEvent;
 110  
 import org.argouml.ui.targetmanager.TargetListener;
 111  
 import org.argouml.ui.targetmanager.TargetManager;
 112  
 import org.argouml.uml.diagram.ArgoDiagram;
 113  
 import org.argouml.uml.diagram.DiagramUtils;
 114  
 import org.argouml.uml.diagram.UMLMutableGraphSupport;
 115  
 import org.argouml.uml.diagram.ui.ActionRemoveFromDiagram;
 116  
 import org.argouml.uml.ui.ActionSaveProject;
 117  
 import org.argouml.util.ArgoFrame;
 118  
 import org.argouml.util.JavaRuntimeUtility;
 119  
 import org.argouml.util.ThreadUtils;
 120  
 import org.tigris.gef.base.Editor;
 121  
 import org.tigris.gef.base.Globals;
 122  
 import org.tigris.gef.base.Layer;
 123  
 import org.tigris.gef.graph.GraphModel;
 124  
 import org.tigris.gef.presentation.Fig;
 125  
 import org.tigris.gef.util.Util;
 126  
 import org.tigris.swidgets.BorderSplitPane;
 127  
 import org.tigris.swidgets.Horizontal;
 128  
 import org.tigris.swidgets.Orientation;
 129  
 import org.tigris.swidgets.Vertical;
 130  
 import org.tigris.toolbar.layouts.DockBorderLayout;
 131  
 
 132  
 /**
 133  
  * The main window of the ArgoUML application.
 134  
  *
 135  
  * @stereotype singleton
 136  
  */
 137  11388
 public final class ProjectBrowser
 138  
     extends JFrame
 139  
     implements PropertyChangeListener, TargetListener {
 140  
 
 141  
     /**
 142  
      * Default width.
 143  
      */
 144  
     public static final int DEFAULT_COMPONENTWIDTH = 400;
 145  
 
 146  
     /**
 147  
      * Default height.
 148  
      */
 149  
     public static final int DEFAULT_COMPONENTHEIGHT = 350;
 150  
 
 151  
     /**
 152  
      * Logger.
 153  
      */
 154  900
     private static final Logger LOG =
 155  
         Logger.getLogger(ProjectBrowser.class);
 156  
 
 157  
 
 158  
     /**
 159  
      * Position of pane in overall browser window.
 160  
      */
 161  9000
     public enum Position {
 162  900
         Center, North, South, East, West,
 163  900
         NorthEast, SouthEast, SouthWest, NorthWest
 164  
     }
 165  
     
 166  
     // Make sure the correspondence that we depend on doesn't change
 167  
     static {
 168  900
         assert Position.Center.toString().equals(BorderSplitPane.CENTER);
 169  900
         assert Position.North.toString().equals(BorderSplitPane.NORTH); 
 170  900
         assert Position.NorthEast.toString().equals(BorderSplitPane.NORTHEAST); 
 171  900
         assert Position.South.toString().equals(BorderSplitPane.SOUTH); 
 172  900
     }
 173  
     
 174  
     /**
 175  
      * Flag to indicate if we are the main application
 176  
      * or being integrated in another top level application such
 177  
      * as Eclipse (via the ArgoEclipse plugin).
 178  
      * TODO: This is a temporary measure until ProjectBrowser
 179  
      * can be refactored more appropriately. - tfm
 180  
      */
 181  
     private static boolean isMainApplication;
 182  
 
 183  
 
 184  
     /**
 185  
      * Member attribute to contain the singleton.
 186  
      */
 187  
     private static ProjectBrowser theInstance;
 188  
 
 189  
 
 190  900
     private String appName = "ProjectBrowser";
 191  
 
 192  
     private MultiEditorPane editorPane;
 193  
 
 194  
     /*
 195  
      * TODO: Work in progress here to allow multiple details panes with
 196  
      * different contents - Bob Tarling
 197  
      */
 198  
     private DetailsPane northEastPane;
 199  
     private DetailsPane northPane;
 200  
     private DetailsPane northWestPane;
 201  
     private DetailsPane eastPane;
 202  
     private DetailsPane southEastPane;
 203  
     private DetailsPane southPane;
 204  
 
 205  900
     private Map<Position, DetailsPane> detailsPanesByCompassPoint = 
 206  
         new HashMap<Position, DetailsPane>();
 207  
 
 208  
     private GenericArgoMenuBar menuBar;
 209  
 
 210  
     /**
 211  
      * Partially implemented. Needs work to display
 212  
      * import of source and saving of zargo.
 213  
      */
 214  900
     private StatusBar statusBar = new ArgoStatusBar();
 215  
 
 216  
     /**
 217  
      * TODO: this needs work so that users can set the font
 218  
      * size through a gui preference window.
 219  
      */
 220  900
     private Font defaultFont = new Font("Dialog", Font.PLAIN, 10);
 221  
 
 222  
     private BorderSplitPane workAreaPane;
 223  
 
 224  
     /**
 225  
      * The explorer (formerly called navigator) pane
 226  
      * containing the modelstructure.
 227  
      */
 228  
     private NavigatorPane explorerPane;
 229  
 
 230  
     /**
 231  
      * The todopane (lower left corner of screen). This may actually be a blank
 232  
      * JPanel if the ProjectBrowser was lazily initialized via
 233  
      * {@link #getInstance()}.
 234  
      */
 235  
     private JPanel todoPane;
 236  
 
 237  
     /**
 238  
      * A class that handles the title of this frame, 
 239  
      * e.g. to indicate save status.
 240  
      */
 241  900
     private TitleHandler titleHandler = new TitleHandler();
 242  
 
 243  
     /**
 244  
      * The action to save the current project.
 245  
      */
 246  
     private AbstractAction saveAction;
 247  
 
 248  
     /**
 249  
      * The action to remove the current selected Figs from the diagram.
 250  
      */
 251  900
     private final ActionRemoveFromDiagram removeFromDiagram =
 252  
         new ActionRemoveFromDiagram(
 253  
                 Translator.localize("action.remove-from-diagram"));
 254  
 
 255  
     /**
 256  
      * For testing purposes. In tests this constructor can be called so
 257  
      * TheInstance is filled.
 258  
      */
 259  
     private ProjectBrowser() {
 260  0
         this("ArgoUML", null, true, null);
 261  0
     }
 262  
 
 263  
     /**
 264  
      * The constructor.
 265  
      * 
 266  
      * @param applicationName
 267  
      *            the title of the frame
 268  
      * @param splash
 269  
      *            the splash screen to show at startup
 270  
      * @param mainApplication
 271  
      *            flag indicating whether we are the top level application.
 272  
      *            False if we are providing components to another top level app.
 273  
      * @param leftBottomPane 
 274  
      *            the panel to fit in the left bottom corner
 275  
      */
 276  
     private ProjectBrowser(String applicationName, SplashScreen splash, 
 277  
              boolean mainApplication, JPanel leftBottomPane) {
 278  900
         super(applicationName);
 279  900
         theInstance = this;
 280  900
         isMainApplication = mainApplication;
 281  
         
 282  900
         getContentPane().setFont(defaultFont);
 283  
         
 284  
         // TODO: This causes a cyclic depencency with ActionSaveProject
 285  900
         saveAction = new ActionSaveProject();
 286  900
         ProjectManager.getManager().setSaveAction(saveAction);
 287  
 
 288  900
         createPanels(splash, leftBottomPane);
 289  
 
 290  900
         if (isMainApplication) {
 291  900
             menuBar = MenuBarFactory.createApplicationMenuBar();
 292  900
             getContentPane().setLayout(new BorderLayout());
 293  900
             this.setJMenuBar(menuBar);
 294  
             //getContentPane().add(_menuBar, BorderLayout.NORTH);
 295  900
             getContentPane().add(assemblePanels(), BorderLayout.CENTER);
 296  
 
 297  900
             JPanel bottom = new JPanel();
 298  900
             bottom.setLayout(new BorderLayout());
 299  900
             bottom.add(statusBar, BorderLayout.CENTER);
 300  900
             bottom.add(new HeapMonitor(), BorderLayout.EAST);
 301  900
             getContentPane().add(bottom, BorderLayout.SOUTH);
 302  
 
 303  900
             setAppName(applicationName);
 304  
 
 305  
             // allows me to ask "Do you want to save first?"
 306  900
             setDefaultCloseOperation(ProjectBrowser.DO_NOTHING_ON_CLOSE);
 307  900
             addWindowListener(new WindowCloser());
 308  
             
 309  900
             setApplicationIcon();
 310  
 
 311  
             // Add listener for project changes
 312  900
             ProjectManager.getManager().addPropertyChangeListener(this);
 313  
 
 314  
             // add listener to get notified when active diagram changes
 315  900
             TargetManager.getInstance().addTargetListener(this);
 316  
 
 317  
             // Add a listener to focus changes.
 318  
             // Rationale: reset the undo manager to start a new chain.
 319  900
             addKeyboardFocusListener();
 320  
         }
 321  900
     }
 322  
 
 323  
     private void addKeyboardFocusListener() {
 324  900
         KeyboardFocusManager kfm =
 325  
             KeyboardFocusManager.getCurrentKeyboardFocusManager();
 326  900
         kfm.addPropertyChangeListener(new PropertyChangeListener() {
 327  
             private Object obj;
 328  
 
 329  
             /*
 330  
              * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
 331  
              */
 332  
             public void propertyChange(PropertyChangeEvent evt) {
 333  11937
                 if ("focusOwner".equals(evt.getPropertyName())
 334  
                         && (evt.getNewValue() != null)
 335  
                     /* We get many many events (why?), so let's filter: */
 336  
                         && (obj != evt.getNewValue())) {
 337  2346
                     obj = evt.getNewValue();
 338  
                     // TODO: Bob says -
 339  
                     // We're looking at focus change to
 340  
                     // flag the start of an interaction. This
 341  
                     // is to detect when focus is gained in a prop
 342  
                     // panel field on the assumption editing of that
 343  
                     // field is about to start.
 344  
                     // Not a good assumption. We Need to see if we can get
 345  
                     // rid of this.
 346  2346
                     Project p = 
 347  
                         ProjectManager.getManager().getCurrentProject();
 348  2346
                     if (p != null) {
 349  2346
                         p.getUndoManager().startInteraction("Focus");
 350  
                     }
 351  
                     /* This next line is ideal for debugging the taborder
 352  
                      * (focus traversal), see e.g. issue 1849.
 353  
                      */
 354  
 //                      System.out.println("Focus changed " + obj);
 355  
                 }
 356  11937
             }
 357  
         });
 358  900
     }
 359  
 
 360  
     private void setApplicationIcon() {
 361  900
         final ImageIcon argoImage16x16 =
 362  
             ResourceLoaderWrapper.lookupIconResource("ArgoIcon16x16");
 363  
         
 364  
         // JREs pre 1.6.0 cannot handle multiple images using 
 365  
         // setIconImages(), so use reflection to conditionally make the 
 366  
         // call to this.setIconImages().
 367  
         // TODO: We can remove all of this reflection code when we go to 
 368  
         // Java 1.6 as a minimum JRE version, see issue 4989.
 369  900
         if (JavaRuntimeUtility.isJre5()) {
 370  
             // With JRE < 1.6.0, do it the old way using 
 371  
             // javax.swing.JFrame.setIconImage, and accept the blurry icon 
 372  0
             setIconImage(argoImage16x16.getImage());
 373  
         } else {
 374  900
             final ImageIcon argoImage32x32 =
 375  
                 ResourceLoaderWrapper.lookupIconResource("ArgoIcon32x32");
 376  900
             final List<Image> argoImages = new ArrayList<Image>(2);
 377  900
             argoImages.add(argoImage16x16.getImage());
 378  900
             argoImages.add(argoImage32x32.getImage());
 379  
             try {
 380  
                 // java.awt.Window.setIconImages is new in Java 6.
 381  
                 // check for it using reflection on current instance
 382  900
                 final Method m = 
 383  
                     getClass().getMethod("setIconImages", List.class);
 384  900
                 m.invoke(this, argoImages);
 385  0
             } catch (InvocationTargetException e) {
 386  0
                 LOG.error("Exception", e);
 387  0
             } catch (NoSuchMethodException e) {
 388  0
                 LOG.error("Exception", e);
 389  0
             } catch (IllegalArgumentException e) {
 390  0
                 LOG.error("Exception", e);
 391  0
             } catch (IllegalAccessException e) {
 392  0
                 LOG.error("Exception", e);
 393  900
             }
 394  
         }
 395  900
     }
 396  
 
 397  
     /**
 398  
      * Singleton retrieval method for the projectbrowser.
 399  
      * Do not use this before makeInstance is called!
 400  
      *  
 401  
      * @return the singleton instance of the projectbrowser
 402  
      */
 403  
     public static synchronized ProjectBrowser getInstance() {
 404  13302
         assert theInstance != null;
 405  13302
         return theInstance;
 406  
     }
 407  
 
 408  
     /**
 409  
      * Creator method for the ProjectBrowser which optionally allows all
 410  
      * components to be created without making a top level application window
 411  
      * visible.
 412  
      * 
 413  
      * @param splash
 414  
      *            true if we are allowed to show a splash screen
 415  
      * @param mainApplication
 416  
      *            true to create a top level application, false if integrated
 417  
      *            with something else.
 418  
      * @param leftBottomPane panel to place in the bottom left corner of the GUI
 419  
      * 
 420  
      * @return the singleton instance of the projectbrowser
 421  
      */
 422  
     public static ProjectBrowser makeInstance(SplashScreen splash,
 423  
             boolean mainApplication, JPanel leftBottomPane) {
 424  900
         return new ProjectBrowser("ArgoUML", splash, 
 425  
                 mainApplication, leftBottomPane);
 426  
     }
 427  
 
 428  
     /*
 429  
      * @see java.awt.Component#getLocale()
 430  
      */
 431  
     @Override
 432  
     public Locale getLocale() {
 433  4104
         return Locale.getDefault();
 434  
     }
 435  
 
 436  
 
 437  
     /**
 438  
      * Creates the panels in the working area.
 439  
      *
 440  
      * @param splash true if we show  the splashscreen during startup
 441  
      * @param leftBottomPane panel to be placed in the bottom left (southwest)
 442  
      *                corner of the UI.
 443  
      */
 444  
     protected void createPanels(SplashScreen splash, JPanel leftBottomPane) {
 445  
 
 446  900
         if (splash != null) {
 447  0
             splash.getStatusBar().showStatus(
 448  
                 Translator.localize("statusmsg.bar.making-project-browser"));
 449  0
             splash.getStatusBar().showProgress(10);
 450  0
             splash.setVisible(true);
 451  
         }
 452  
         
 453  900
         editorPane = new MultiEditorPane();
 454  900
         if (splash != null) {
 455  0
             splash.getStatusBar().showStatus(
 456  
                     Translator.localize(
 457  
                             "statusmsg.bar.making-project-browser-explorer"));
 458  0
             splash.getStatusBar().incProgress(5);
 459  
         }
 460  900
         explorerPane = new NavigatorPane(splash);
 461  
 
 462  
         // The workarea is all the visible space except the menu,
 463  
         // toolbar and status bar.  Workarea is laid out as a
 464  
         // BorderSplitPane where the various components that make up
 465  
         // the argo application can be positioned.
 466  900
         workAreaPane = new BorderSplitPane();
 467  
 
 468  
         // create the todopane
 469  900
         if (splash != null) {
 470  0
             splash.getStatusBar().showStatus(Translator.localize(
 471  
                     "statusmsg.bar.making-project-browser-to-do-pane"));
 472  0
             splash.getStatusBar().incProgress(5);
 473  
         }
 474  900
         todoPane = leftBottomPane;
 475  900
         createDetailsPanes();
 476  900
         restorePanelSizes();
 477  900
     }
 478  
 
 479  
     private Component assemblePanels() {
 480  900
         addPanel(editorPane, Position.Center);
 481  900
         addPanel(explorerPane, Position.West);
 482  900
         addPanel(todoPane, Position.SouthWest);
 483  
 
 484  
         // There are various details panes all of which could hold
 485  
         // different tabs pages according to users settings.
 486  
         // Place each pane in the required border area.
 487  
         for (Map.Entry<Position, DetailsPane> entry 
 488  900
                 : detailsPanesByCompassPoint.entrySet()) {
 489  900
             Position position = entry.getKey();
 490  900
             addPanel(entry.getValue(), position);
 491  900
         }
 492  
         
 493  
         // Toolbar boundary is the area between the menu and the status
 494  
         // bar. It contains the workarea at centre and the toolbar
 495  
         // position north, south, east or west.
 496  900
         final JPanel toolbarBoundary = new JPanel();
 497  900
         toolbarBoundary.setLayout(new DockBorderLayout());
 498  
         // TODO: - should save and restore the last positions of the toolbars
 499  900
         final String toolbarPosition = BorderLayout.NORTH;
 500  900
         toolbarBoundary.add(menuBar.getFileToolbar(), toolbarPosition);
 501  900
         toolbarBoundary.add(menuBar.getEditToolbar(), toolbarPosition);
 502  900
         toolbarBoundary.add(menuBar.getViewToolbar(), toolbarPosition);
 503  900
         toolbarBoundary.add(menuBar.getCreateDiagramToolbar(),
 504  
                         toolbarPosition);
 505  900
         toolbarBoundary.add(workAreaPane, BorderLayout.CENTER);
 506  
 
 507  
 
 508  
         /**
 509  
          * Registers all toolbars and enables north panel hiding when all
 510  
          * toolbars are hidden.
 511  
          */
 512  900
         ArgoToolbarManager.getInstance().registerToolbar(
 513  
                 menuBar.getFileToolbar(), menuBar.getFileToolbar(), 0);
 514  900
         ArgoToolbarManager.getInstance().registerToolbar(
 515  
                 menuBar.getEditToolbar(), menuBar.getEditToolbar(), 1);
 516  900
         ArgoToolbarManager.getInstance().registerToolbar(
 517  
                 menuBar.getViewToolbar(), menuBar.getViewToolbar(), 2);
 518  900
         ArgoToolbarManager.getInstance().registerToolbar(
 519  
                 menuBar.getCreateDiagramToolbar(),
 520  
                 menuBar.getCreateDiagramToolbar(), 3);
 521  
 
 522  900
         final JToolBar[] toolbars = new JToolBar[] {menuBar.getFileToolbar(),
 523  
                 menuBar.getEditToolbar(), menuBar.getViewToolbar(),
 524  
                 menuBar.getCreateDiagramToolbar() };
 525  4500
         for (JToolBar toolbar : toolbars) {
 526  3600
             toolbar.addComponentListener(new ComponentAdapter() {
 527  
                 public void componentHidden(ComponentEvent e) {
 528  20
                     boolean allHidden = true;
 529  20
                     for (JToolBar bar : toolbars) {
 530  20
                         if (bar.isVisible()) {
 531  20
                             allHidden = false;
 532  20
                             break;
 533  
                         }
 534  
                     }
 535  
 
 536  20
                     if (allHidden) {
 537  0
                         for (JToolBar bar : toolbars) {
 538  0
                             toolbarBoundary.getLayout().removeLayoutComponent(
 539  
                                     bar);
 540  
                         }
 541  0
                         toolbarBoundary.getLayout().layoutContainer(
 542  
                                 toolbarBoundary);
 543  
                     }
 544  20
                 }
 545  
 
 546  
                 public void componentShown(ComponentEvent e) {
 547  0
                     JToolBar oneVisible = null;
 548  0
                     for (JToolBar bar : toolbars) {
 549  0
                         if (bar.isVisible()) {
 550  0
                             oneVisible = bar;
 551  0
                             break;
 552  
                         }
 553  
                     }
 554  
 
 555  0
                     if (oneVisible != null) {
 556  0
                         toolbarBoundary.add(oneVisible, toolbarPosition);
 557  0
                         toolbarBoundary.getLayout().layoutContainer(
 558  
                                 toolbarBoundary);
 559  
                     }
 560  0
                 }
 561  
             });
 562  
         }
 563  
         /**
 564  
          * END registering toolbar
 565  
          */
 566  
 
 567  900
         return toolbarBoundary;
 568  
     }
 569  
 
 570  
     private void createDetailsPanes() {
 571  
         /*
 572  
          * Work in progress here to allow multiple details panes with different
 573  
          * contents - Bob Tarling
 574  
          */
 575  900
         eastPane  =
 576  
             makeDetailsPane(BorderSplitPane.EAST,  Vertical.getInstance());
 577  900
         southPane =
 578  
             makeDetailsPane(BorderSplitPane.SOUTH, Horizontal.getInstance());
 579  900
         southEastPane =
 580  
             makeDetailsPane(BorderSplitPane.SOUTHEAST,
 581  
                     Horizontal.getInstance());
 582  900
         northWestPane =
 583  
             makeDetailsPane(BorderSplitPane.NORTHWEST,
 584  
                     Horizontal.getInstance());
 585  900
         northPane =
 586  
             makeDetailsPane(BorderSplitPane.NORTH, Horizontal.getInstance());
 587  900
         northEastPane =
 588  
             makeDetailsPane(BorderSplitPane.NORTHEAST,
 589  
                     Horizontal.getInstance());
 590  
 
 591  900
         if (southPane != null) {
 592  900
             detailsPanesByCompassPoint.put(Position.South, southPane);
 593  
         }
 594  900
         if (southEastPane != null) {
 595  0
             detailsPanesByCompassPoint.put(Position.SouthEast,
 596  
                     southEastPane);
 597  
         }
 598  900
         if (eastPane != null) {
 599  0
             detailsPanesByCompassPoint.put(Position.East, eastPane);
 600  
         }
 601  900
         if (northWestPane != null) {
 602  0
             detailsPanesByCompassPoint.put(Position.NorthWest,
 603  
                     northWestPane);
 604  
         }
 605  900
         if (northPane != null) {
 606  0
             detailsPanesByCompassPoint.put(Position.North, northPane);
 607  
         }
 608  900
         if (northEastPane != null) {
 609  0
             detailsPanesByCompassPoint.put(Position.NorthEast,
 610  
                     northEastPane);
 611  
         }
 612  
 
 613  
         // Add target listeners for details panes
 614  900
         Iterator it = detailsPanesByCompassPoint.entrySet().iterator();
 615  1800
         while (it.hasNext()) {
 616  900
             TargetManager.getInstance().addTargetListener(
 617  
                     (DetailsPane) ((Map.Entry) it.next()).getValue());
 618  
         }
 619  900
     }
 620  
 
 621  
     
 622  
     /**
 623  
      * Add a panel to a split pane area.
 624  
      *
 625  
      * @param comp the panel to add
 626  
      * @param position the position where the panel should be added
 627  
      */
 628  
     public void addPanel(Component comp, Position position) {
 629  3600
         workAreaPane.add(comp, position.toString());
 630  3600
     }
 631  
 
 632  
     /**
 633  
      * Remove a panel from a split pane area.
 634  
      *
 635  
      * @param comp the panel to remove
 636  
      */
 637  
     public void removePanel(Component comp) {
 638  0
         workAreaPane.remove(comp);
 639  0
         workAreaPane.validate();
 640  0
         workAreaPane.repaint();
 641  0
     }
 642  
 
 643  
     /**
 644  
      * Set the size of each panel to that last saved in the configuration file.
 645  
      */
 646  
     private void restorePanelSizes() {
 647  900
         if (northPane != null) {
 648  0
             northPane.setPreferredSize(new Dimension(
 649  
                     0, getSavedHeight(Argo.KEY_SCREEN_NORTH_HEIGHT)));
 650  
         }
 651  900
         if (southPane != null) {
 652  900
             southPane.setPreferredSize(new Dimension(
 653  
                     0, getSavedHeight(Argo.KEY_SCREEN_SOUTH_HEIGHT)));
 654  
         }
 655  900
         if (eastPane != null) {
 656  0
             eastPane.setPreferredSize(new Dimension(
 657  
                     getSavedWidth(Argo.KEY_SCREEN_EAST_WIDTH), 0));
 658  
         }
 659  900
         if (explorerPane != null) {
 660  900
             explorerPane.setPreferredSize(new Dimension(
 661  
                     getSavedWidth(Argo.KEY_SCREEN_WEST_WIDTH), 0));
 662  
         }
 663  900
         if (northWestPane != null) {
 664  0
             northWestPane.setPreferredSize(getSavedDimensions(
 665  
                     Argo.KEY_SCREEN_NORTHWEST_WIDTH,
 666  
                     Argo.KEY_SCREEN_NORTH_HEIGHT));
 667  
         }
 668  900
         if (todoPane != null) {
 669  900
             todoPane.setPreferredSize(getSavedDimensions(
 670  
                     Argo.KEY_SCREEN_SOUTHWEST_WIDTH,
 671  
                     Argo.KEY_SCREEN_SOUTH_HEIGHT));
 672  
         }
 673  900
         if (northEastPane != null) {
 674  0
             northEastPane.setPreferredSize(getSavedDimensions(
 675  
                     Argo.KEY_SCREEN_NORTHEAST_WIDTH,
 676  
                     Argo.KEY_SCREEN_NORTH_HEIGHT));
 677  
         }
 678  900
         if (southEastPane != null) {
 679  0
             southEastPane.setPreferredSize(getSavedDimensions(
 680  
                     Argo.KEY_SCREEN_SOUTHEAST_WIDTH,
 681  
                     Argo.KEY_SCREEN_SOUTH_HEIGHT));
 682  
         }
 683  900
     }
 684  
 
 685  
     // Convenience methods to return saved width and height values
 686  
     private Dimension getSavedDimensions(ConfigurationKey width,
 687  
             ConfigurationKey height) {
 688  900
         return new Dimension(getSavedWidth(width), getSavedHeight(height));
 689  
     }
 690  
     private int getSavedWidth(ConfigurationKey width) {
 691  1800
         return Configuration.getInteger(width, DEFAULT_COMPONENTWIDTH);
 692  
     }
 693  
     private int getSavedHeight(ConfigurationKey height) {
 694  1800
         return Configuration.getInteger(height, DEFAULT_COMPONENTHEIGHT);
 695  
     }
 696  
     
 697  
     /**
 698  
      * Handle the title-bar of the window.
 699  
      * 
 700  
      * @author michiel
 701  
      */
 702  1800
     private class TitleHandler implements PropertyChangeListener {
 703  
         
 704  900
         private ArgoDiagram monitoredDiagram = null;
 705  
 
 706  
         /**
 707  
          * Create a title for the main window's title.
 708  
          *
 709  
          * @param projectFileName the project-file name
 710  
          * @param activeDiagram the (new) current diagram
 711  
          */
 712  
         protected void buildTitle(String projectFileName, 
 713  
                 ArgoDiagram activeDiagram) {
 714  5244
             if (projectFileName == null || "".equals(projectFileName)) {
 715  3376
                 if (ProjectManager.getManager().getCurrentProject() != null) {
 716  2476
                     projectFileName = ProjectManager.getManager()
 717  
                         .getCurrentProject().getName();
 718  
                 }
 719  
             }
 720  
             // TODO: Why would this be null?
 721  5244
             if (activeDiagram == null) {
 722  4043
                 activeDiagram = DiagramUtils.getActiveDiagram();
 723  
             }
 724  5244
             String changeIndicator = "";
 725  5244
             if (saveAction != null && saveAction.isEnabled()) {
 726  3340
                 changeIndicator = " *";
 727  
             }
 728  5244
             if (activeDiagram != null) {
 729  1648
                 if (monitoredDiagram != null) {
 730  748
                     monitoredDiagram.removePropertyChangeListener("name", this);
 731  
                 }
 732  1648
                 activeDiagram.addPropertyChangeListener("name", this);
 733  1648
                 monitoredDiagram = activeDiagram;
 734  1648
                 setTitleInternal(projectFileName + " - "
 735  
                         + activeDiagram.getName() + " - " + getAppName()
 736  
                         + changeIndicator);
 737  
             } else {
 738  3596
                 setTitleInternal(projectFileName + " - " + getAppName() 
 739  
                         + changeIndicator);
 740  
             }
 741  5244
         }
 742  
         
 743  
         private void setTitleInternal(final String title) {
 744  5244
             if (SwingUtilities.isEventDispatchThread()) {
 745  744
                 setTitle(title);
 746  
             } else {
 747  4500
                 SwingUtilities.invokeLater(new Runnable() {
 748  
                     public void run() {
 749  4500
                         setTitle(title);
 750  4500
                     }
 751  
                 });
 752  
             }
 753  5244
         }
 754  
         
 755  
         /*
 756  
          * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
 757  
          */
 758  
         public void propertyChange(PropertyChangeEvent evt) {
 759  0
             if (evt.getPropertyName().equals("name")
 760  
                     && evt.getSource() instanceof ArgoDiagram) {
 761  0
                 buildTitle(
 762  
                     ProjectManager.getManager().getCurrentProject().getName(), 
 763  
                     (ArgoDiagram) evt.getSource());
 764  
             }            
 765  0
         }
 766  
     }
 767  
     /**
 768  
      * Set the save indicator (the * after the title) to appear depending on
 769  
      * the current save action enabled status.
 770  
      */
 771  
     public void showSaveIndicator() {
 772  2175
         titleHandler.buildTitle(null, null);
 773  2175
     }
 774  
 
 775  
     /**
 776  
      * @return the application name ("ArgoUML") as shown in the titlebar
 777  
      */
 778  
     public String getAppName() {
 779  5244
         return appName;
 780  
     }
 781  
 
 782  
     /**
 783  
      * @param n the application name ("ArgoUML") as shown in the titlebar
 784  
      */
 785  
     public void setAppName(String n) {
 786  900
         appName = n;
 787  900
     }
 788  
 
 789  
     /**
 790  
      * The method used by the NavigatorPane, MultiEditor and DetailsPane
 791  
      * to set the target of the application.<p>
 792  
      *
 793  
      * the target is either a Model Element (usually selected in
 794  
      * the Navigation pane or Properties panel) or a Fig (selected in
 795  
      * a diagram).<p>
 796  
      *
 797  
      * The concept of a selection transaction is used to prevent a change
 798  
      * of target in one view creating a call back to this method, which
 799  
      * would then change the target in all views again...<p>
 800  
      *
 801  
      * @param o the target
 802  
      */
 803  
     private void setTarget(Object o) {
 804  0
         TargetManager.getInstance().setTarget(o);
 805  0
     }
 806  
 
 807  
     /**
 808  
      * Select the tab page containing the todo item.
 809  
      * 
 810  
      * @param o the todo item to select
 811  
      * @deprecated for 0.25.5 by tfmorris. Send an event that the
 812  
      *             DetailsPane/TabToDo will be listening for.
 813  
      */
 814  
     @Deprecated
 815  
     public void setToDoItem(Object o) {
 816  0
         Iterator it = detailsPanesByCompassPoint.values().iterator();
 817  0
         while (it.hasNext()) {
 818  0
             DetailsPane detailsPane = (DetailsPane) it.next();
 819  0
             if (detailsPane.setToDoItem(o)) {
 820  0
                 return;
 821  
             }
 822  0
         }
 823  0
     }
 824  
 
 825  
 
 826  
     /**
 827  
      * Get the tab page instance of the given class.
 828  
      * 
 829  
      * @param tabClass the given class
 830  
      * @return the tabpage
 831  
      * @deprecated by for 0.25.5 by tfmorris. Tabs should register themselves
 832  
      *             with whoever they need to communicate with in a distributed
 833  
      *             fashion rather than relying on a central registry. Currently
 834  
      *             the only place this is used is to communicate between WizStep
 835  
      *             and TabToDo in the Cognitive subsystem.
 836  
      */
 837  
     @Deprecated
 838  
     public AbstractArgoJPanel getTab(Class tabClass) {
 839  
         // In theory there can be multiple details pane (work in
 840  
         // progress). It must first be determined which details
 841  
         // page contains the properties tab. Bob Tarling 7 Dec 2002
 842  0
         for (DetailsPane detailsPane : detailsPanesByCompassPoint.values())  {
 843  0
             AbstractArgoJPanel tab = detailsPane.getTab(tabClass);
 844  0
             if (tab != null) {
 845  0
                 return tab;
 846  
             }
 847  0
         }
 848  0
         throw new IllegalStateException("No " + tabClass.getName()
 849  
                                         + " tab found");
 850  
     }
 851  
 
 852  
     /**
 853  
      * @return the status bar
 854  
      */
 855  
     public StatusBar getStatusBar() {
 856  900
         return statusBar;
 857  
     }
 858  
 
 859  
     /*
 860  
      * @see javax.swing.JFrame#getJMenuBar()
 861  
      */
 862  
     @Override
 863  
     public JMenuBar getJMenuBar() {
 864  0
         return menuBar;
 865  
     }
 866  
 
 867  
     /**
 868  
      * @return the editor pane
 869  
      */
 870  
     public MultiEditorPane getEditorPane() {
 871  0
         return editorPane;
 872  
     }
 873  
 
 874  
     /**
 875  
      * @return the explorer pane
 876  
      */
 877  
     public NavigatorPane getExplorerPane() {
 878  0
         return explorerPane;
 879  
     }
 880  
     
 881  
     /**
 882  
      * @return the details pane
 883  
      */
 884  
     public JPanel getDetailsPane() {
 885  8100
         return southPane;
 886  
     }
 887  
 
 888  
 
 889  
     /*
 890  
      * @see java.awt.Component#setVisible(boolean)
 891  
      */
 892  
     @Override
 893  
     public void setVisible(boolean b) {
 894  900
         super.setVisible(b);
 895  900
         if (b) {
 896  900
             Globals.setStatusBar(getStatusBar());
 897  
         }
 898  900
     }
 899  
 
 900  
     private void updateStatus(String status) {
 901  0
         ArgoEventPump.fireEvent(new ArgoStatusEvent(ArgoEventTypes.STATUS_TEXT,
 902  
                 this, status));
 903  0
     }
 904  
 
 905  
     /**
 906  
      * Save the positions of the screen splitters, sizes and postion
 907  
      * of main window in the properties file.
 908  
      */
 909  
     private void saveScreenConfiguration() {
 910  0
         if (explorerPane != null) {
 911  0
             Configuration.setInteger(Argo.KEY_SCREEN_WEST_WIDTH,
 912  
                                      explorerPane.getWidth());
 913  
         }
 914  0
         if (eastPane != null) {
 915  0
             Configuration.setInteger(Argo.KEY_SCREEN_EAST_WIDTH,
 916  
                                      eastPane.getWidth());
 917  
         }
 918  0
         if (northPane != null) {
 919  0
             Configuration.setInteger(Argo.KEY_SCREEN_NORTH_HEIGHT,
 920  
                                      northPane.getHeight());
 921  
         }
 922  0
         if (southPane != null) {
 923  0
             Configuration.setInteger(Argo.KEY_SCREEN_SOUTH_HEIGHT,
 924  
                                      southPane.getHeight());
 925  
         }
 926  0
         if (todoPane != null) {
 927  0
             Configuration.setInteger(Argo.KEY_SCREEN_SOUTHWEST_WIDTH,
 928  
                     todoPane.getWidth());
 929  
         }
 930  0
         if (southEastPane != null) {
 931  0
             Configuration.setInteger(Argo.KEY_SCREEN_SOUTHEAST_WIDTH,
 932  
                     southEastPane.getWidth());
 933  
         }
 934  0
         if (northWestPane != null) {
 935  0
             Configuration.setInteger(Argo.KEY_SCREEN_NORTHWEST_WIDTH,
 936  
                     northWestPane.getWidth());
 937  
         }
 938  0
         if (northEastPane != null) {
 939  0
             Configuration.setInteger(Argo.KEY_SCREEN_NORTHEAST_WIDTH,
 940  
                     northEastPane.getWidth());
 941  
         }
 942  
 
 943  0
         boolean maximized = getExtendedState() == MAXIMIZED_BOTH;
 944  0
         if (!maximized) {
 945  0
             Configuration.setInteger(Argo.KEY_SCREEN_WIDTH, getWidth());
 946  0
             Configuration.setInteger(Argo.KEY_SCREEN_HEIGHT, getHeight());
 947  0
             Configuration.setInteger(Argo.KEY_SCREEN_LEFT_X, getX());
 948  0
             Configuration.setInteger(Argo.KEY_SCREEN_TOP_Y, getY());
 949  
         }
 950  0
         Configuration.setBoolean(Argo.KEY_SCREEN_MAXIMIZED, 
 951  
                 maximized);
 952  0
     }
 953  
 
 954  
     /**
 955  
      * Build a new details pane for the given compass point.
 956  
      *
 957  
      * @param compassPoint the position for which to build the pane
 958  
      * @param orientation the required orientation of the pane.
 959  
      * @return the details pane or null if none is required for the given
 960  
      *         compass point.
 961  
      */
 962  
     private DetailsPane makeDetailsPane(String compassPoint,
 963  
                                         Orientation orientation) {
 964  5400
         DetailsPane detailsPane =
 965  
             new DetailsPane(compassPoint.toLowerCase(), orientation);
 966  5400
         if (!detailsPane.hasTabs()) {
 967  4500
             return null;
 968  
         }
 969  900
         return detailsPane;
 970  
     }
 971  
 
 972  
     /**
 973  
      * Exit the application if no save is required.
 974  
      * If a save is required then prompt the user if they wish to,
 975  
      * save and exit, exit without saving or cancel the exit operation.
 976  
      */
 977  
     public boolean tryExit() {
 978  0
         LOG.info("Trying to exit the application");
 979  0
         if (saveAction != null && saveAction.isEnabled()) {
 980  0
             LOG.info("A save is needed - prompting the user");
 981  0
             Project p = ProjectManager.getManager().getCurrentProject();
 982  
 
 983  0
             String t =
 984  
                 MessageFormat.format(Translator.localize(
 985  
                         "optionpane.exit-save-changes-to"),
 986  
                     new Object[] {p.getName()});
 987  0
             int response =
 988  
                 JOptionPane.showConfirmDialog(
 989  
                     this, t, t, JOptionPane.YES_NO_CANCEL_OPTION);
 990  
 
 991  0
             if (response == JOptionPane.YES_OPTION) {
 992  
                 // The trySave method results in the save taking place in another thread.
 993  
                 // If that completes without error the ProjectBrowser.exit() method will
 994  
                 // be called which will actually exist the system.
 995  0
                 LOG.info("The user chose to exit and save");
 996  0
                 trySave(ProjectManager.getManager().getCurrentProject() != null
 997  
                         && ProjectManager.getManager().getCurrentProject()
 998  
                                 .getURI() != null,
 999  
                                 false, true);
 1000  0
                 return false;
 1001  0
             } else if (response == JOptionPane.CANCEL_OPTION) {
 1002  0
                 LOG.info("The user cancelled the save dialog");
 1003  0
                 return false;
 1004  
             }
 1005  
         }
 1006  0
         LOG.info("We will now exit");
 1007  0
         exit();
 1008  0
         return true;
 1009  
     }
 1010  
     
 1011  
     
 1012  
     /**
 1013  
      * Exit the application saving the current user settings.
 1014  
      */
 1015  
     public void exit() {
 1016  0
         saveScreenConfiguration();
 1017  0
         Configuration.save();
 1018  0
         System.exit(0);
 1019  0
     }
 1020  
 
 1021  
     /*
 1022  
      * @see java.awt.Window#dispose()
 1023  
      */
 1024  
     public void dispose() {
 1025  
 
 1026  0
     }
 1027  
 
 1028  
     /**
 1029  
      * Receives window events.
 1030  
      */
 1031  
     class WindowCloser extends WindowAdapter {
 1032  
         /**
 1033  
          * Constructor.
 1034  
          */
 1035  900
         public WindowCloser() {
 1036  900
         }
 1037  
 
 1038  
         /*
 1039  
          * @see java.awt.event.WindowListener#windowClosing(java.awt.event.WindowEvent)
 1040  
          */
 1041  
         public void windowClosing(WindowEvent e) {
 1042  0
             LOG.info("Detected attempt to close application - checking if save needed");
 1043  0
             tryExit();
 1044  0
         }
 1045  
     } /* end class WindowCloser */
 1046  
 
 1047  
     /*
 1048  
      * @see java.beans.PropertyChangeListener#propertyChange(
 1049  
      *         java.beans.PropertyChangeEvent)
 1050  
      */
 1051  
     public void propertyChange(PropertyChangeEvent evt) {
 1052  
         // the project changed
 1053  3774
         if (evt.getPropertyName()
 1054  
             .equals(ProjectManager.CURRENT_PROJECT_PROPERTY_NAME)) {
 1055  1868
             Project p = (Project) evt.getNewValue();
 1056  1868
             if (p != null) {
 1057  1868
                 titleHandler.buildTitle(p.getName(), null);
 1058  
                 //Designer.TheDesigner.getToDoList().removeAllElements();
 1059  1868
                 Designer.setCritiquingRoot(p);
 1060  
                 // update all panes
 1061  1868
                 TargetManager.getInstance().setTarget(p.getInitialTarget());
 1062  
             }
 1063  
             // TODO: Do we want to use the Project here instead of just its name?
 1064  1868
             ArgoEventPump.fireEvent(new ArgoStatusEvent(
 1065  
                     ArgoEventTypes.STATUS_PROJECT_LOADED, this, p.getName()));
 1066  
         }
 1067  3774
     }
 1068  
 
 1069  
     /////////////////////////////////////////////////////////////////////////
 1070  
     // TargetListener methods implemented so notified when selected
 1071  
     // diagram changes. Used to update the window title.
 1072  
 
 1073  
     /*
 1074  
      * @see org.argouml.ui.targetmanager.TargetListener#targetAdded(org.argouml.ui.targetmanager.TargetEvent)
 1075  
      */
 1076  
     public void targetAdded(TargetEvent e) {
 1077  0
             targetChanged(e.getNewTarget());
 1078  0
     }
 1079  
 
 1080  
     /*
 1081  
      * @see org.argouml.ui.targetmanager.TargetListener#targetRemoved(org.argouml.ui.targetmanager.TargetEvent)
 1082  
      */
 1083  
     public void targetRemoved(TargetEvent e) {
 1084  88
             targetChanged(e.getNewTarget());
 1085  88
     }
 1086  
 
 1087  
     /*
 1088  
      * @see org.argouml.ui.targetmanager.TargetListener#targetSet(org.argouml.ui.targetmanager.TargetEvent)
 1089  
      */
 1090  
     public void targetSet(TargetEvent e) {
 1091  1239
             targetChanged(e.getNewTarget());
 1092  1239
     }
 1093  
     
 1094  
     /**
 1095  
      * Called to update the current namespace and active diagram after
 1096  
      * the target has changed.
 1097  
      *
 1098  
      * @param target the new target
 1099  
      */
 1100  
     private void targetChanged(Object target) {
 1101  1327
         if (target instanceof ArgoDiagram) {
 1102  1201
             titleHandler.buildTitle(null, (ArgoDiagram) target);
 1103  
         }
 1104  1327
         determineRemoveEnabled();
 1105  
         
 1106  1327
         Project p = ProjectManager.getManager().getCurrentProject();
 1107  
         
 1108  1327
         Object theCurrentNamespace = null;
 1109  1327
         target = TargetManager.getInstance().getTarget();
 1110  1327
         if (target instanceof ArgoDiagram) {
 1111  1201
             theCurrentNamespace = ((ArgoDiagram) target).getNamespace();
 1112  126
         } else if (Model.getFacade().isANamespace(target)) {
 1113  0
             theCurrentNamespace = target;
 1114  126
         } else if (Model.getFacade().isAModelElement(target)) {
 1115  0
             theCurrentNamespace = Model.getFacade().getNamespace(target);
 1116  
         } else {
 1117  126
             theCurrentNamespace = p.getRoot();
 1118  
         }
 1119  1327
         p.setCurrentNamespace(theCurrentNamespace);
 1120  
 
 1121  1327
         if (target instanceof ArgoDiagram) {
 1122  1201
             p.setActiveDiagram((ArgoDiagram) target);
 1123  
         }
 1124  1327
     }
 1125  
 
 1126  
     /**
 1127  
      * Enabled the remove action if an item is selected in anything other then
 1128  
      * the activity or state diagrams.
 1129  
      */
 1130  
     private void determineRemoveEnabled() {
 1131  1327
         Editor editor = Globals.curEditor();
 1132  1327
         Collection figs = editor.getSelectionManager().getFigs();
 1133  1327
         boolean removeEnabled = !figs.isEmpty();
 1134  1327
         GraphModel gm = editor.getGraphModel();
 1135  1327
         if (gm instanceof UMLMutableGraphSupport) {
 1136  427
             removeEnabled =
 1137  
                 ((UMLMutableGraphSupport) gm).isRemoveFromDiagramAllowed(figs);
 1138  
         }
 1139  1327
         removeFromDiagram.setEnabled(removeEnabled);
 1140  1327
     }
 1141  
 
 1142  
     /**
 1143  
      * Returns the todopane.
 1144  
      * @return ToDoPane
 1145  
      */
 1146  
     public JPanel getTodoPane() {
 1147  0
         return todoPane;
 1148  
     }
 1149  
 
 1150  
     /**
 1151  
      * @return Returns the defaultFont.
 1152  
      */
 1153  
     public Font getDefaultFont() {
 1154  0
         return defaultFont;
 1155  
     }
 1156  
     
 1157  
     /**
 1158  
      * Try to save the project, possibly not creating a new file
 1159  
      * @param overwrite if true, then we overwrite without asking
 1160  
      */
 1161  
     public void trySave(boolean overwrite) {
 1162  5
         this.trySave(overwrite, false);
 1163  0
     }
 1164  
     
 1165  
     /**
 1166  
      * Try to save the project.
 1167  
      * @param overwrite if true, then we overwrite without asking
 1168  
      * @param saveNewFile if true, we'll ask for a new file even if
 1169  
      *                    the current project already had one  
 1170  
      */        
 1171  
     public void trySave(boolean overwrite, boolean saveNewFile) {
 1172  5
         trySave(overwrite, saveNewFile, false);
 1173  0
     }
 1174  
     
 1175  
     /**
 1176  
      * Try to save the project.
 1177  
      * @param overwrite if true, then we overwrite without asking
 1178  
      * @param saveNewFile if true, we'll ask for a new file even if
 1179  
      *                    the current project already had one
 1180  
      * @param exitAfterSave The application will exit when the save has
 1181  
      * completed successfully
 1182  
      */        
 1183  
     public void trySave(
 1184  
             final boolean overwrite,
 1185  
             boolean saveNewFile,
 1186  
             final boolean exitAfterSave) {
 1187  5
         URI uri = ProjectManager.getManager().getCurrentProject().getURI();
 1188  
 
 1189  5
         File file = null;
 1190  
 
 1191  
         // this method is invoked from several places, so we have to check
 1192  
         // whether if the project uri is set or not
 1193  5
         if (uri != null && !saveNewFile) {
 1194  0
             file = new File(uri);
 1195  
 
 1196  
             // does the file really exists?
 1197  0
             if (!file.exists()) {
 1198  
                 // project file doesn't exist. let's pop up a message dialog..
 1199  0
                 int response = JOptionPane.showConfirmDialog(
 1200  
                         this,
 1201  
                         Translator.localize(
 1202  
                                 "optionpane.save-project-file-not-found"),
 1203  
                         Translator.localize(
 1204  
                                 "optionpane.save-project-file-not-found-title"),
 1205  
                         JOptionPane.YES_NO_OPTION);
 1206  
 
 1207  
                 // ..and let's ask the user whether he wants to save the actual
 1208  
                 // project into a new file or not
 1209  0
                 if (response == JOptionPane.YES_OPTION) {
 1210  0
                     saveNewFile = true;
 1211  
                 } else {
 1212  
                     // save action has been cancelled
 1213  0
                     return;
 1214  
                 }
 1215  0
             }
 1216  
         } else {
 1217  
             // Attempt to save this project under a new name.
 1218  5
             saveNewFile = true;
 1219  
         }
 1220  
 
 1221  
         // Prompt the user for the new name.
 1222  5
         if (saveNewFile) {
 1223  5
             file = getNewFile();
 1224  
 
 1225  
             // if the user cancelled the operation,
 1226  
             // we don't have to save anything
 1227  0
             if (file == null) {
 1228  0
                 return;
 1229  
             }
 1230  
         }
 1231  
 
 1232  
         // let's call the real save method
 1233  0
         trySaveWithProgressMonitor(overwrite, file, exitAfterSave);
 1234  0
     }
 1235  
     
 1236  
     /**
 1237  
      * Checks if the given file is writable or read-only
 1238  
      * @param file the file to be checked
 1239  
      * @return true if the given file is read-only
 1240  
      */
 1241  
     private boolean isFileReadonly(File file) {
 1242  
         try {
 1243  0
             return (file == null) 
 1244  
                 || (file.exists() && !file.canWrite()) 
 1245  
                 || (!file.exists() && !file.createNewFile());
 1246  
         
 1247  0
         } catch (IOException ioExc) {
 1248  0
             return true;
 1249  
         }
 1250  
     }
 1251  
     
 1252  
     /**
 1253  
      * Loads a project displaying a nice ProgressMonitor
 1254  
      * 
 1255  
      * @param overwrite if true, the file is going to be overwritten
 1256  
      * @param file      the target file
 1257  
      * 
 1258  
      * TODO: Separate this into a Swing specific class - tfm
 1259  
      */
 1260  
     public void trySaveWithProgressMonitor(
 1261  
             final boolean overwrite,
 1262  
             final File file,
 1263  
             final boolean exit) {
 1264  0
         if (!PersistenceManager.getInstance().confirmOverwrite(
 1265  
                 ArgoFrame.getFrame(), overwrite, file)) {
 1266  0
             return;
 1267  
         }
 1268  0
         if (this.isFileReadonly(file)) {
 1269  0
             JOptionPane.showMessageDialog(this, 
 1270  
                     Translator.localize(
 1271  
                             "optionpane.save-project-read-only"),
 1272  
                     Translator.localize(
 1273  
                             "optionpane.save-project-read-only-title"),
 1274  
                           JOptionPane.INFORMATION_MESSAGE);
 1275  0
             return;
 1276  
         }
 1277  
 
 1278  0
         SaveSwingWorker worker = new SaveSwingWorker(
 1279  
                 ProjectManager.getManager().getCurrentProject(),
 1280  
                 file,
 1281  
                 exit);
 1282  0
         LOG.info("Starting save thread");
 1283  0
         worker.start();
 1284  0
     }
 1285  
     
 1286  
     /**
 1287  
      * Rebuild the title using the name of the current project.
 1288  
      *
 1289  
      */
 1290  
     public void buildTitleWithCurrentProjectName() {
 1291  0
         titleHandler.buildTitle(
 1292  
                 ProjectManager.getManager().getCurrentProject().getName(), 
 1293  
                 null);
 1294  0
     }
 1295  
     
 1296  
     /**
 1297  
      * Try to save the project.
 1298  
      * @param overwrite if true, then we overwrite without asking
 1299  
      * @param file the File to save to
 1300  
      * @param pmw       the ProgressMonitor to be updated;  
 1301  
      * @return true if successful
 1302  
      * 
 1303  
      * TODO: Separate this into a Swing specific class - tfm
 1304  
      * @deprecated in 0.29.1 by Bob Tarling use trySaveWithProgressMonitor
 1305  
      */
 1306  
     @Deprecated
 1307  
     public boolean trySave(boolean overwrite, 
 1308  
             File file, 
 1309  
             ProgressMonitor pmw) {
 1310  0
         LOG.info("Saving the project");
 1311  
         
 1312  0
         if (!PersistenceManager.getInstance().confirmOverwrite(
 1313  
                 ArgoFrame.getFrame(), overwrite, file)) {
 1314  0
             return false;
 1315  
         }
 1316  
         
 1317  0
         if (this.isFileReadonly(file)) {
 1318  0
             JOptionPane.showMessageDialog(this, 
 1319  
                     Translator.localize(
 1320  
                             "optionpane.save-project-read-only"),
 1321  
                     Translator.localize(
 1322  
                             "optionpane.save-project-read-only-title"),
 1323  
                           JOptionPane.INFORMATION_MESSAGE);
 1324  0
             return false;
 1325  
         }
 1326  
 
 1327  0
         Project project = ProjectManager.getManager().getCurrentProject();
 1328  0
         return trySave(file, pmw, project);
 1329  
     }
 1330  
 
 1331  
     /**
 1332  
      * Save the project.
 1333  
      * @param file the File to save to
 1334  
      * @param pmw       the ProgressMonitor to be updated;  
 1335  
      * @return true if successful
 1336  
      * 
 1337  
      * TODO: Separate this into a Swing specific class - tfm
 1338  
      */
 1339  
     boolean trySave(
 1340  
             final File file, 
 1341  
             final ProgressMonitor pmw,
 1342  
             final Project project) {
 1343  0
         LOG.info("Saving the project");
 1344  0
         PersistenceManager pm = PersistenceManager.getInstance();
 1345  0
         ProjectFilePersister persister = null;
 1346  
 
 1347  
         try {
 1348  0
             String sStatus =
 1349  
                 MessageFormat.format(Translator.localize(
 1350  
                     "statusmsg.bar.save-project-status-writing"),
 1351  
                          new Object[] {file});
 1352  0
             updateStatus (sStatus);
 1353  
 
 1354  0
             persister = pm.getSavePersister();
 1355  0
             pm.setSavePersister(null);
 1356  0
             if (persister == null) {
 1357  0
                 persister = pm.getPersisterFromFileName(file.getName());
 1358  
             }
 1359  0
             if (persister == null) {
 1360  0
                 throw new IllegalStateException("Filename " + project.getName()
 1361  
                             + " is not of a known file type");
 1362  
             }
 1363  
 
 1364  0
             testSimulateErrors();
 1365  
 
 1366  
             // Repair any errors in the project
 1367  0
             String report = project.repair();
 1368  0
             if (report.length() > 0) {
 1369  
                 // TODO: i18n
 1370  0
                 report = 
 1371  
                     "An inconsistency has been detected when saving the model."
 1372  
                         + "These have been repaired and are reported below. "
 1373  
                         + "The save will continue with the model having been "
 1374  
                         + "amended as described.\n" + report;
 1375  0
                 reportError(
 1376  
                         pmw, 
 1377  
                         Translator.localize("dialog.repair") + report, true);
 1378  
             }
 1379  
             
 1380  0
             if (pmw != null) {
 1381  0
                 pmw.updateProgress(25);
 1382  0
                 persister.addProgressListener(pmw);
 1383  
             }
 1384  
             
 1385  0
             project.preSave();
 1386  0
             persister.save(project, file);
 1387  0
             project.postSave();
 1388  
 
 1389  0
             ArgoEventPump.fireEvent(new ArgoStatusEvent(
 1390  
                     ArgoEventTypes.STATUS_PROJECT_SAVED, this, 
 1391  
                     file.getAbsolutePath()));
 1392  0
             LOG.debug ("setting most recent project file to "
 1393  
                    + file.getCanonicalPath());
 1394  
 
 1395  
             /*
 1396  
              * notification of menu bar
 1397  
              */
 1398  0
             saveAction.setEnabled(false);
 1399  0
             addFileSaved(file);
 1400  
 
 1401  0
             Configuration.setString(Argo.KEY_MOST_RECENT_PROJECT_FILE,
 1402  
                         file.getCanonicalPath());
 1403  
 
 1404  0
             return true;
 1405  0
         } catch (Exception ex) {
 1406  0
             String sMessage =
 1407  
                 MessageFormat.format(Translator.localize(
 1408  
                     "optionpane.save-project-general-exception"),
 1409  
                          new Object[] {ex.getMessage()});
 1410  
 
 1411  0
             JOptionPane.showMessageDialog(this, sMessage,
 1412  
                     Translator.localize(
 1413  
                     "optionpane.save-project-general-exception-title"),
 1414  
                           JOptionPane.ERROR_MESSAGE);
 1415  
 
 1416  0
             reportError(
 1417  
                     pmw,
 1418  
                     Translator.localize(
 1419  
                             "dialog.error.save.error",
 1420  
                             new Object[] {file.getName()}),
 1421  
                     true, ex);
 1422  
 
 1423  0
             LOG.error(sMessage, ex);
 1424  
         }
 1425  
 
 1426  0
         return false;
 1427  
     }
 1428  
 
 1429  
     /*
 1430  
      * Simulate some errors to repair.
 1431  
      * Replace with junits - Bob
 1432  
      */
 1433  
     private void testSimulateErrors() {
 1434  
         // Change to true to enable testing
 1435  
         if (false) {
 1436  
             Layer lay =
 1437  
                 Globals.curEditor().getLayerManager().getActiveLayer();
 1438  
             List figs = lay.getContentsNoEdges();
 1439  
             // A Fig with a null owner
 1440  
             if (figs.size() > 0) {
 1441  
                 Fig fig = (Fig) figs.get(0);
 1442  
                 LOG.error("Setting owner of " 
 1443  
                         + fig.getClass().getName() + " to null");
 1444  
                 fig.setOwner(null);
 1445  
             }
 1446  
             // A Fig with a null layer
 1447  
             if (figs.size() > 1) {
 1448  
                 Fig fig = (Fig) figs.get(1);
 1449  
                 fig.setLayer(null);
 1450  
             }
 1451  
             // A Fig with a removed model element
 1452  
             if (figs.size() > 2) {
 1453  
                 Fig fig = (Fig) figs.get(2);
 1454  
                 Object owner = fig.getOwner();
 1455  
                 Model.getUmlFactory().delete(owner);
 1456  
             }
 1457  
         }
 1458  0
     }
 1459  
 
 1460  
     /**
 1461  
      * Register a new file saved.
 1462  
      *
 1463  
      * @param file The file.
 1464  
      * @throws IOException if we cannot get the file name from the file.
 1465  
      */
 1466  
     public void addFileSaved(File file) throws IOException {
 1467  
         // TODO: This should listen for file save events - tfm
 1468  0
         GenericArgoMenuBar menu = (GenericArgoMenuBar) getJMenuBar();
 1469  0
         if (menu != null) {
 1470  0
             menu.addFileSaved(file.getCanonicalPath());
 1471  
         }
 1472  0
     }
 1473  
 
 1474  
     /**
 1475  
      * If the current project is dirty (needs saving) then this function will
 1476  
      * ask confirmation from the user.
 1477  
      * If the user indicates that saving is needed, then saving is attempted.
 1478  
      * See ActionExit.actionPerformed() for a very similar procedure!
 1479  
      *
 1480  
      * @return true if we can continue with opening
 1481  
      */
 1482  
     public boolean askConfirmationAndSave() {
 1483  123
         ProjectBrowser pb = ProjectBrowser.getInstance();
 1484  123
         Project p = ProjectManager.getManager().getCurrentProject();
 1485  
 
 1486  
 
 1487  123
         if (p != null && saveAction.isEnabled()) {
 1488  15
             String t =
 1489  
                 MessageFormat.format(Translator.localize(
 1490  
                         "optionpane.open-project-save-changes-to"),
 1491  
                         new Object[] {p.getName()});
 1492  
 
 1493  15
             int response =
 1494  
                 JOptionPane.showConfirmDialog(pb, t, t,
 1495  
                     JOptionPane.YES_NO_CANCEL_OPTION);
 1496  
 
 1497  0
             if (response == JOptionPane.CANCEL_OPTION
 1498  
                     || response == JOptionPane.CLOSED_OPTION) {
 1499  0
                 return false;
 1500  
             }
 1501  0
             if (response == JOptionPane.YES_OPTION) {
 1502  
 
 1503  0
                 trySave(ProjectManager.getManager().getCurrentProject() != null
 1504  
                         && ProjectManager.getManager().getCurrentProject()
 1505  
                                 .getURI() != null);
 1506  0
                 if (saveAction.isEnabled()) {
 1507  0
                     return false;
 1508  
                 }
 1509  
             }
 1510  
         }
 1511  108
         return true;
 1512  
     }
 1513  
 
 1514  
     /**
 1515  
      * Loads a project displaying a nice ProgressMonitor
 1516  
      * 
 1517  
      * @param file      the project to be opened
 1518  
      * @param showUI    whether to show the GUI or not
 1519  
      * 
 1520  
      * TODO: This needs to be refactored to be GUI independent - tfm
 1521  
      */
 1522  
     public void loadProjectWithProgressMonitor(File file, boolean showUI) {
 1523  0
         LoadSwingWorker worker = new LoadSwingWorker(file, showUI);
 1524  0
         worker.start();
 1525  0
     }
 1526  
 
 1527  
     /**
 1528  
      * Loads the project file and opens all kinds of error message windows
 1529  
      * if it doesn't work for some reason. In those cases it preserves
 1530  
      * the old project.
 1531  
      *
 1532  
      * @param file the file to open.
 1533  
      * @param showUI true if an error message may be shown to the user,
 1534  
      *               false if run in commandline mode
 1535  
      * @param pmw       the ProgressMonitor to be updated;  
 1536  
      *                          if not needed, use null 
 1537  
      * @return true if the file was successfully opened
 1538  
      * 
 1539  
      * TODO: Separate this into a Swing specific class - tfm
 1540  
      */
 1541  
     public boolean loadProject(File file, boolean showUI, 
 1542  
             ProgressMonitor pmw) {
 1543  0
         return (loadProject2(file, showUI, pmw) != null);
 1544  
     }
 1545  
     
 1546  
     /**
 1547  
      * Loads the project file and opens all kinds of error message windows
 1548  
      * if it doesn't work for some reason. In those cases it preserves
 1549  
      * the old project.
 1550  
      *
 1551  
      * @param file the file to open.
 1552  
      * @param showUI true if an error message may be shown to the user,
 1553  
      *               false if run in commandline mode
 1554  
      * @param pmw         the ProgressMonitor to be updated;  
 1555  
      *                                 if not needed, use null 
 1556  
      * @return true if the file was successfully opened
 1557  
      * 
 1558  
      * TODO: Separate this into a Swing specific class - tfm
 1559  
      */
 1560  
     public Project loadProject2(File file, boolean showUI, 
 1561  
             ProgressMonitor pmw) {
 1562  0
         LOG.info("Loading project.");
 1563  
 
 1564  0
         PersistenceManager pm = PersistenceManager.getInstance();
 1565  0
         Project oldProject = ProjectManager.getManager().getCurrentProject();
 1566  0
         if (oldProject != null) {
 1567  
             // Remove the old project first.  It's wasteful to create a temp
 1568  
             // empty project, but too much of ArgoUML depends on having a
 1569  
             // current project
 1570  0
             Project p = ProjectManager.getManager().makeEmptyProject();
 1571  0
             ProjectManager.getManager().setCurrentProject(p);
 1572  0
             ProjectManager.getManager().removeProject(oldProject);
 1573  0
             oldProject = p;
 1574  
         }
 1575  
         
 1576  0
         boolean success = false;
 1577  
 
 1578  
         // TODO:
 1579  
         // This is actually a hack! Some diagram types
 1580  
         // (like the statechart diagrams) access the current
 1581  
         // diagram to get some info. This might cause
 1582  
         // problems if there's another statechart diagram
 1583  
         // active, so I remove the current project, before
 1584  
         // loading the new one.
 1585  
 
 1586  0
         Designer.disableCritiquing();
 1587  0
         Designer.clearCritiquing();
 1588  0
         clearDialogs();
 1589  0
         Project project = null;
 1590  
 
 1591  0
         if (!(file.canRead())) {
 1592  0
             reportError(pmw, "File not found " + file + ".", showUI);
 1593  0
             Designer.enableCritiquing();
 1594  0
             success = false;
 1595  
         } else {
 1596  
             // Hide save action during load. Otherwise we get the
 1597  
             // * appearing in title bar and the save enabling as models are
 1598  
             // updated
 1599  
             // TODO: Do we still need this now the save enablement is improved?
 1600  0
             final AbstractAction rememberedSaveAction = this.saveAction;
 1601  0
             this.saveAction = null;
 1602  0
             ProjectManager.getManager().setSaveAction(null);
 1603  
             try {
 1604  0
                 ProjectFilePersister persister =
 1605  
                     pm.getPersisterFromFileName(file.getName());
 1606  0
                 if (persister == null) {
 1607  0
                     throw new IllegalStateException("Filename "
 1608  
                             + file.getName()
 1609  
                             + " is not of a known file type");
 1610  
                 }
 1611  
 
 1612  0
                 if (pmw != null) {
 1613  0
                     persister.addProgressListener(pmw);
 1614  
                 }
 1615  
                 
 1616  
 
 1617  0
                 project = persister.doLoad(file);
 1618  
 
 1619  0
                 if (pmw != null) {
 1620  0
                     persister.removeProgressListener(pmw);
 1621  
                 }
 1622  0
                 ThreadUtils.checkIfInterrupted();
 1623  
                 
 1624  
 //                if (Model.getDiagramInterchangeModel() != null) {
 1625  
                 // TODO: This assumes no more than one project at a time
 1626  
                 // will be loaded.  If it is ever reinstituted, this needs to
 1627  
                 // be fixed
 1628  
 //                    Collection diagrams =
 1629  
 //                        DiagramFactory.getInstance().getDiagram();
 1630  
 //                    Iterator diag = diagrams.iterator();
 1631  
 //                    while (diag.hasNext()) {
 1632  
 //                        project.addMember(diag.next());
 1633  
 //                    }
 1634  
 //                    if (!diagrams.isEmpty()) {
 1635  
 //                        project.setActiveDiagram(
 1636  
 //                                (ArgoDiagram) diagrams.iterator().next());
 1637  
 //                    }
 1638  
 //                }
 1639  
 
 1640  
                 // Let's save this project in the mru list
 1641  0
                 this.addFileSaved(file);
 1642  
                 // Let's save this project as the last used one
 1643  
                 // in the configuration file
 1644  0
                 Configuration.setString(Argo.KEY_MOST_RECENT_PROJECT_FILE,
 1645  
                         file.getCanonicalPath());
 1646  
                 
 1647  0
                 updateStatus(
 1648  
                         Translator.localize(
 1649  
                                 "statusmsg.bar.open-project-status-read",
 1650  
                                 new Object[] {file.getName(), }));
 1651  0
                 success = true;
 1652  0
             } catch (VersionException ex) {
 1653  0
                 reportError(
 1654  
                         pmw,
 1655  
                         Translator.localize(
 1656  
                                 "dialog.error.file.version.error",
 1657  
                                 new Object[] {ex.getMessage()}),
 1658  
                         showUI);
 1659  0
             } catch (OutOfMemoryError ex) {
 1660  0
                 LOG.error("Out of memory while loading project", ex);
 1661  0
                 reportError(
 1662  
                         pmw,
 1663  
                         Translator.localize("dialog.error.memory.limit"),
 1664  
                         showUI);
 1665  0
             } catch (java.lang.InterruptedException ex) {
 1666  0
                 LOG.error("Project loading interrupted by user");
 1667  0
             } catch (UmlVersionException ex) {
 1668  0
                 reportError(
 1669  
                         pmw,
 1670  
                         Translator.localize(
 1671  
                                 "dialog.error.file.version.error",
 1672  
                                 new Object[] {ex.getMessage()}),
 1673  
                         showUI, ex);
 1674  0
             } catch (XmiFormatException ex) {
 1675  0
                 if (ex.getCause() instanceof XmiReferenceException) {
 1676  
                     // an error that can be corrected by the user, so no stack
 1677  
                     // trace, but instead an explanation and a hint how to fix
 1678  0
                     String reference = 
 1679  
                         ((XmiReferenceException) ex.getCause()).getReference();
 1680  0
                     reportError(
 1681  
                             pmw,
 1682  
                             Translator.localize(
 1683  
                                     "dialog.error.xmi.reference.error",
 1684  
                                     new Object[] {reference, ex.getMessage()}),
 1685  
                             ex.toString(),
 1686  
                             showUI);
 1687  0
                 } else {
 1688  0
                     reportError(
 1689  
                             pmw,
 1690  
                             Translator.localize(
 1691  
                                     "dialog.error.xmi.format.error",
 1692  
                                     new Object[] {ex.getMessage()}),
 1693  
                                     showUI, ex);
 1694  
                 }
 1695  0
             } catch (IOException ex) {
 1696  0
                 LOG.error("Exception while loading project", ex);
 1697  0
                 reportError(
 1698  
                         pmw,
 1699  
                         Translator.localize(
 1700  
                                 "dialog.error.open.error",
 1701  
                                 new Object[] {file.getName()}),
 1702  
                         showUI, ex);
 1703  0
             } catch (OpenException ex) {
 1704  0
                 LOG.error("Exception while loading project", ex);
 1705  0
                 reportError(
 1706  
                         pmw,
 1707  
                         Translator.localize(
 1708  
                                 "dialog.error.open.error",
 1709  
                                 new Object[] {file.getName()}),
 1710  
                         showUI, ex);
 1711  0
             } catch (XmiReferenceRuntimeException ex) {
 1712  
                 // an error that can be corrected by the user, so no stack
 1713  
                 // trace, but instead an explanation and a hint how to fix
 1714  0
                 reportError(pmw,
 1715  
                     Translator.localize("dialog.error.xmi.reference.error",
 1716  
                         new Object[] {ex.getReference(), ex.getMessage()}),
 1717  
                     ex.toString(), showUI);
 1718  0
             } catch (RuntimeException ex) {
 1719  0
                 LOG.error("Exception while loading project", ex);
 1720  0
                 reportError(
 1721  
                         pmw,
 1722  
                         Translator.localize(
 1723  
                                 "dialog.error.open.error",
 1724  
                                 new Object[] {file.getName()}),
 1725  
                         showUI, ex);
 1726  0
             } finally {
 1727  
 
 1728  0
                 try {
 1729  0
                     if (!success) {
 1730  0
                         project = 
 1731  
                             ProjectManager.getManager().makeEmptyProject();
 1732  
                     }
 1733  0
                     ProjectManager.getManager().setCurrentProject(project);
 1734  0
                     if (oldProject != null) {
 1735  0
                         ProjectManager.getManager().removeProject(oldProject);
 1736  
                     }
 1737  
                     
 1738  0
                     project.getProjectSettings().init();
 1739  
                     
 1740  0
                     Command cmd = new NonUndoableCommand() {
 1741  
                         public Object execute() {
 1742  
                             // This is temporary. Load project
 1743  
                             // should create a new project
 1744  
                             // with its own UndoManager and so
 1745  
                             // there should be no Command
 1746  0
                             return null;
 1747  
                         }
 1748  
                     };
 1749  0
                     project.getUndoManager().addCommand(cmd);
 1750  
 
 1751  0
                     LOG.info("There are " + project.getDiagramList().size()
 1752  
                             + " diagrams in the current project");
 1753  
 
 1754  0
                     Designer.enableCritiquing();
 1755  0
                 } finally {
 1756  
                     // Make sure save action is always reinstated
 1757  0
                     this.saveAction = rememberedSaveAction;
 1758  
                     
 1759  
                     // We clear the save-required flag on the Swing event thread
 1760  
                     // in the hopes that it gets done after any other background
 1761  
                     // work (listener updates) that is being done there
 1762  0
                     SwingUtilities.invokeLater(new Runnable() {
 1763  
                         public void run() {
 1764  0
                             ProjectManager.getManager().setSaveAction(
 1765  
                                     rememberedSaveAction);
 1766  0
                             rememberedSaveAction.setEnabled(false);
 1767  0
                         }
 1768  
                     });
 1769  0
                 }
 1770  0
             }
 1771  
         }
 1772  0
         if (!success) {
 1773  0
             return null;
 1774  
         }
 1775  0
         return project;
 1776  
     }
 1777  
 
 1778  
     /**
 1779  
      * Open a Message Dialog with an error message.
 1780  
      *
 1781  
      * @param message the message to display.
 1782  
      * @param showUI true if an error message may be shown to the user,
 1783  
      *               false if run in commandline mode
 1784  
      */
 1785  
     private void reportError(ProgressMonitor monitor, final String message,
 1786  
             boolean showUI) {
 1787  0
         if (showUI) {
 1788  0
             if (monitor != null) {
 1789  0
                 monitor.notifyMessage(
 1790  
                         Translator.localize("dialog.error.title"), 
 1791  
                         Translator.localize("dialog.error.open.save.error"),
 1792  
                         message);
 1793  
             } else {
 1794  0
                 SwingUtilities.invokeLater(new Runnable() {
 1795  
                     public void run() {
 1796  0
                         JDialog dialog =
 1797  
                             new ExceptionDialog(
 1798  
                                     ArgoFrame.getFrame(),
 1799  
                                     Translator.localize("dialog.error.title"),
 1800  
                                     Translator.localize(
 1801  
                                             "dialog.error.open.save.error"),
 1802  
                                     message);
 1803  0
                         dialog.setVisible(true);
 1804  0
                     }
 1805  
                 });
 1806  
             }
 1807  
         } else {
 1808  0
             System.err.print(message);
 1809  
         }
 1810  0
     }
 1811  
 
 1812  
     /**
 1813  
      * Open a Message Dialog with an error message.
 1814  
      *
 1815  
      * @param message the message to display.
 1816  
      * @param showUI true if an error message may be shown to the user,
 1817  
      *               false if run in commandline mode
 1818  
      * @param ex The exception that was thrown.
 1819  
      */
 1820  
     private void reportError(ProgressMonitor monitor, final String message,
 1821  
             boolean showUI, final Throwable ex) {
 1822  0
         if (showUI) {
 1823  0
             if (monitor != null) {
 1824  0
                 monitor.notifyMessage(
 1825  
                         Translator.localize("dialog.error.title"),
 1826  
                         message, 
 1827  
                         ExceptionDialog.formatException(
 1828  
                                 message, ex, ex instanceof OpenException));
 1829  
             } else {
 1830  0
                 SwingUtilities.invokeLater(new Runnable() {
 1831  
                     public void run() {
 1832  0
                         JDialog dialog =
 1833  
                             new ExceptionDialog(
 1834  
                                     ArgoFrame.getFrame(),
 1835  
                                     Translator.localize("dialog.error.title"),
 1836  
                                     message, 
 1837  
                                     ExceptionDialog.formatException(
 1838  
                                                 message, ex,
 1839  
                                                 ex instanceof OpenException));
 1840  0
                         dialog.setVisible(true);
 1841  0
                     }
 1842  
                 });
 1843  
             }
 1844  
         } else {
 1845  0
             StringWriter sw = new StringWriter();
 1846  0
             PrintWriter pw = new PrintWriter(sw);
 1847  0
             ex.printStackTrace(pw);
 1848  0
             String exception = sw.toString();
 1849  
             // TODO:  Does anyone use command line?
 1850  
             // If so, localization is needed - tfm
 1851  0
             reportError(monitor, "Please report the error below to the ArgoUML"
 1852  
                     + "development team at http://argouml.tigris.org.\n"
 1853  
                     + message + "\n\n" + exception, showUI);
 1854  
         }
 1855  0
     }
 1856  
 
 1857  
     /**
 1858  
      * Open a Message Dialog with an error message and an explanation. No
 1859  
      * stack trace, since it's not an application error, but a user issue.
 1860  
      *
 1861  
      * @param message the message to display.
 1862  
      * @param explanation the explanation to display.
 1863  
      * @param showUI true if an error message may be shown to the user,
 1864  
      *               false if run in commandline mode
 1865  
      */
 1866  
     private void reportError(ProgressMonitor monitor, final String message,
 1867  
             final String explanation, boolean showUI) {
 1868  0
         if (showUI) {
 1869  0
             if (monitor != null) {
 1870  0
                 monitor.notifyMessage(
 1871  
                         Translator.localize("dialog.error.title"),
 1872  
                         explanation,
 1873  
                         message);
 1874  
             } else {
 1875  0
                 SwingUtilities.invokeLater(new Runnable() {
 1876  
                     public void run() {
 1877  0
                         JDialog dialog =
 1878  
                             new ExceptionDialog(
 1879  
                                     ArgoFrame.getFrame(),
 1880  
                                     Translator.localize("dialog.error.title"),
 1881  
                                     explanation,
 1882  
                                     message);
 1883  0
                         dialog.setVisible(true);
 1884  0
                     }
 1885  
                 });
 1886  
             }
 1887  
         } else {
 1888  0
             reportError(monitor, message + "\n" + explanation + "\n\n",
 1889  
                     showUI);
 1890  
         }
 1891  0
     }
 1892  
 
 1893  
     /**
 1894  
      * We should remove all open dialogs. They have as parent the
 1895  
      * ProjectBrowser. This is needed for the non-modal dialogs
 1896  
      * such as Find and Goto.
 1897  
      */
 1898  
     public void clearDialogs() {
 1899  68
         Window[] windows = getOwnedWindows();
 1900  76
         for (int i = 0; i < windows.length; i++) {
 1901  8
             if (!(windows[i] instanceof FindDialog)) {
 1902  6
                 windows[i].dispose();
 1903  
             }
 1904  
         }
 1905  68
         FindDialog.getInstance().reset();
 1906  68
     }
 1907  
 
 1908  
     /**
 1909  
      * Get the action that can save the current project.
 1910  
      * @return the save action.
 1911  
      */
 1912  
     public AbstractAction getSaveAction() {
 1913  2700
         return saveAction;
 1914  
     }
 1915  
 
 1916  
     /**
 1917  
      * Get the action that removes selected figs from the diagram.
 1918  
      * @return the remove from diagram action.
 1919  
      */
 1920  
     public AbstractAction getRemoveFromDiagramAction() {
 1921  0
         return removeFromDiagram;
 1922  
     }
 1923  
 
 1924  
     /**
 1925  
      * @return the File to save to
 1926  
      */
 1927  
     protected File getNewFile() {
 1928  5
         ProjectBrowser pb = ProjectBrowser.getInstance();
 1929  5
         Project p = ProjectManager.getManager().getCurrentProject();
 1930  
 
 1931  5
         JFileChooser chooser = null;
 1932  5
         URI uri = p.getURI();
 1933  
         
 1934  5
         if (uri != null) {
 1935  0
             File projectFile = new File(uri);
 1936  0
             if (projectFile.length() > 0) {
 1937  0
                 chooser = new JFileChooser(projectFile);
 1938  
             } else {
 1939  0
                 chooser = new JFileChooser();
 1940  
             }
 1941  0
             chooser.setSelectedFile(projectFile);
 1942  0
         } else {
 1943  5
             chooser = new JFileChooser();
 1944  
         }
 1945  
 
 1946  5
         String sChooserTitle =
 1947  
             Translator.localize("filechooser.save-as-project");
 1948  5
         chooser.setDialogTitle(sChooserTitle + " " + p.getName());
 1949  
 
 1950  
         // adding project files icon
 1951  5
         chooser.setFileView(ProjectFileView.getInstance());
 1952  
 
 1953  5
         chooser.setAcceptAllFileFilterUsed(false);
 1954  
 
 1955  5
         PersistenceManager.getInstance().setSaveFileChooserFilters(
 1956  
                 chooser, 
 1957  
                 uri != null ? Util.URIToFilename(uri.toString()) : null);
 1958  
 
 1959  5
         int retval = chooser.showSaveDialog(pb);
 1960  0
         if (retval == JFileChooser.APPROVE_OPTION) {
 1961  0
             File theFile = chooser.getSelectedFile();
 1962  0
             AbstractFilePersister filter =
 1963  
                 (AbstractFilePersister) chooser.getFileFilter();
 1964  0
             if (theFile != null) {
 1965  0
                 Configuration.setString(
 1966  
                         PersistenceManager.KEY_PROJECT_NAME_PATH,
 1967  
                         PersistenceManager.getInstance().getBaseName(
 1968  
                                 theFile.getPath()));
 1969  0
                 String name = theFile.getName();
 1970  0
                 if (!name.endsWith("." + filter.getExtension())) {
 1971  0
                     theFile =
 1972  
                         new File(
 1973  
                             theFile.getParent(),
 1974  
                             name + "." + filter.getExtension());
 1975  
                 }
 1976  
             }
 1977  0
             PersistenceManager.getInstance().setSavePersister(filter);
 1978  0
             return theFile;
 1979  
         }
 1980  0
         return null;
 1981  
     }
 1982  
     
 1983  
     /**
 1984  
      * The UID.
 1985  
      */
 1986  
     private static final long serialVersionUID = 6974246679451284917L;
 1987  
 } /* end class ProjectBrowser */