/* * @(#)DrawApplication.java * * Project: JHotdraw - a GUI framework for technical drawings * http://www.jhotdraw.org * http://jhotdraw.sourceforge.net * Copyright: (c) by the original author(s) and all contributors * License: Lesser GNU Public License (LGPL) * http://www.opensource.org/licenses/lgpl-license.html */ package org.jhotdraw.application; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.util.ListIterator; import javax.swing.*; import org.jhotdraw.contrib.*; import org.jhotdraw.figures.*; import org.jhotdraw.framework.*; import org.jhotdraw.standard.*; import org.jhotdraw.util.*; import org.jhotdraw.contrib.Desktop; // avoid collision with java.awt.Desktop /** * DrawApplication defines a standard presentation for * standalone drawing editors. The presentation is * customized in subclasses. * The application is started as follows: * <pre> * public static void main(String[] args) { * MayDrawApp window = new MyDrawApp(); * window.open(); * } * </pre> * * @version <$CURRENT_VERSION$> */ public class DrawApplication extends JFrame implements DrawingEditor, PaletteListener, VersionRequester { private Tool fTool; private Iconkit fIconkit; private JTextField fStatusLine; private DrawingView fView; private ToolButton fDefaultToolButton; private ToolButton fSelectedToolButton; private String fApplicationName; private StorageFormatManager fStorageFormatManager; private UndoManager myUndoManager; protected static String fgUntitled = "untitled"; /** * List is not thread safe, but should not need to be. If it does we can * safely synchronize the few methods that use this by synchronizing on * the List object itself. */ private java.util.List listeners; private DesktopListener fDesktopListener; /** * This component acts as a desktop for the content. */ private Desktop fDesktop; // the image resource path private static final String fgDrawPath = "/org/jhotdraw/"; public static final String IMAGES = fgDrawPath + "images/"; protected static int winCount = 0; /** * The index of the file menu in the menu bar. */ public static final int FILE_MENU = 0; /** * The index of the edit menu in the menu bar. */ public static final int EDIT_MENU = 1; /** * The index of the alignment menu in the menu bar. */ public static final int ALIGNMENT_MENU = 2; /** * The index of the attributes menu in the menu bar. */ public static final int ATTRIBUTES_MENU = 3; /** * Constructs a drawing window with a default title. */ public DrawApplication() { this("JHotDraw"); } /** * Constructs a drawing window with the given title. */ public DrawApplication(String title) { super(title); listeners = CollectionsFactory.current().createList(); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); setApplicationName(title); } /** * Factory method which can be overriden by subclasses to * create an instance of their type. * * @return newly created application */ protected DrawApplication createApplication() { return new DrawApplication(); } /** * Open a new view for this application containing a * view of the drawing of the currently activated window. */ public void newView() { if (view() == null) { return; } DrawApplication window = createApplication(); window.open(view()); if (view().drawing().getTitle() != null ) { window.setDrawingTitle(view().drawing().getTitle() + " (View)"); } else { window.setDrawingTitle(getDefaultDrawingTitle() + " (View)"); } } /** * Open a new window for this application containing the passed in drawing, * or a new drawing if the passed in drawing is null. */ public void newWindow(Drawing initialDrawing) { DrawApplication window = createApplication(); if (initialDrawing == null) { window.open(); } else { window.open(window.createDrawingView(initialDrawing)); } } public final void newWindow() { newWindow(createDrawing()); } /** * Opens a new window */ public void open() { open(createInitialDrawingView()); } /** * Opens a new window with a drawing view. */ protected void open(final DrawingView newDrawingView) { getVersionControlStrategy().assertCompatibleVersion(); setUndoManager(new UndoManager()); setIconkit(createIconkit()); getContentPane().setLayout(new BorderLayout()); // status line must be created before a tool is set setStatusLine(createStatusLine()); getContentPane().add(getStatusLine(), BorderLayout.SOUTH); // create dummy tool until the default tool is activated during toolDone() setTool(new NullTool(this), ""); setView(newDrawingView); JToolBar tools = createToolPalette(); createTools(tools); JPanel activePanel = new JPanel(); activePanel.setAlignmentX(LEFT_ALIGNMENT); activePanel.setAlignmentY(TOP_ALIGNMENT); activePanel.setLayout(new BorderLayout()); activePanel.add(tools, BorderLayout.NORTH); setDesktopListener(createDesktopListener()); setDesktop(createDesktop()); activePanel.add((Component)getDesktop(), BorderLayout.CENTER); getContentPane().add(activePanel, BorderLayout.CENTER); JMenuBar mb = new JMenuBar(); createMenus(mb); setJMenuBar(mb); Dimension d = defaultSize(); if (d.width > mb.getPreferredSize().width) { setSize(d.width, d.height); } else { setSize(mb.getPreferredSize().width, d.height); } addListeners(); setStorageFormatManager(createStorageFormatManager()); //no work allowed to be done on GUI outside of AWT thread once //setVislble(true) must be called before drawing added to desktop, else //DND will fail. on drawing added before with a NPE. note however that //a nulldrawingView will not fail because it is never really added to the desltop setVisible(true); Runnable r = new Runnable() { public void run() { if (newDrawingView.isInteractive()) { getDesktop().addToDesktop(newDrawingView , Desktop.PRIMARY); } toolDone(); } }; if (java.awt.EventQueue.isDispatchThread() == false) { try { java.awt.EventQueue.invokeAndWait(r); } catch(java.lang.InterruptedException ie) { System.err.println(ie.getMessage()); exit(); } catch(java.lang.reflect.InvocationTargetException ite) { System.err.println(ite.getMessage()); exit(); } } else { r.run(); } toolDone(); } /** * Registers the listeners for this window */ protected void addListeners() { addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent event) { endApp(); } public void windowOpened(WindowEvent event) { winCount++; } public void windowClosed(WindowEvent event) { if (--winCount == 0) { System.exit(0); } } } ); } /** * Creates the standard menus. Clients override this * method to add additional menus. */ protected void createMenus(JMenuBar mb) { addMenuIfPossible(mb, createFileMenu()); addMenuIfPossible(mb, createEditMenu()); addMenuIfPossible(mb, createAlignmentMenu()); addMenuIfPossible(mb, createAttributesMenu()); addMenuIfPossible(mb, createDebugMenu()); } protected void addMenuIfPossible(JMenuBar mb, JMenu newMenu) { if (newMenu != null) { mb.add(newMenu); } } /** * Creates the file menu. Clients override this * method to add additional menu items. */ protected JMenu createFileMenu() { CommandMenu menu = new CommandMenu("File"); Command cmd = new AbstractCommand("New", this, false) { public void execute() { promptNew(); } }; menu.add(cmd, new MenuShortcut('n')); cmd = new AbstractCommand("Open...", this, false) { public void execute() { promptOpen(); } }; menu.add(cmd, new MenuShortcut('o')); cmd = new AbstractCommand("Save As...", this, true) { public void execute() { promptSaveAs(); } }; menu.add(cmd, new MenuShortcut('s')); menu.addSeparator(); cmd = new AbstractCommand("Print...", this, true) { public void execute() { print(); } }; menu.add(cmd, new MenuShortcut('p')); menu.addSeparator(); cmd = new AbstractCommand("Exit", this, true) { public void execute() { endApp(); } }; menu.add(cmd); return menu; } /** * Creates the edit menu. Clients override this * method to add additional menu items. */ protected JMenu createEditMenu() { CommandMenu menu = new CommandMenu("Edit"); menu.add(new UndoableCommand( new SelectAllCommand("Select All", this)), new MenuShortcut('a')); menu.addSeparator(); menu.add(new UndoableCommand( new CutCommand("Cut", this)), new MenuShortcut('x')); menu.add(new CopyCommand("Copy", this), new MenuShortcut('c')); menu.add(new UndoableCommand( new PasteCommand("Paste", this)), new MenuShortcut('v')); menu.addSeparator(); menu.add(new UndoableCommand( new DuplicateCommand("Duplicate", this)), new MenuShortcut('d')); menu.add(new UndoableCommand(new DeleteCommand("Delete", this))); menu.addSeparator(); menu.add(new UndoableCommand(new GroupCommand("Group", this))); menu.add(new UndoableCommand(new UngroupCommand("Ungroup", this))); menu.addSeparator(); menu.add(new UndoableCommand(new SendToBackCommand("Send to Back", this))); menu.add(new UndoableCommand(new BringToFrontCommand("Bring to Front", this))); menu.addSeparator(); menu.add(new UndoCommand("Undo Command", this)); menu.add(new RedoCommand("Redo Command", this)); return menu; } /** * Creates the alignment menu. Clients override this * method to add additional menu items. */ protected JMenu createAlignmentMenu() { CommandMenu menu = new CommandMenu("Align"); menu.addCheckItem(new ToggleGridCommand("Toggle Snap to Grid", this, new Point(4,4))); menu.addSeparator(); menu.add(new UndoableCommand( new AlignCommand(AlignCommand.Alignment.LEFTS, this))); menu.add(new UndoableCommand( new AlignCommand(AlignCommand.Alignment.CENTERS, this))); menu.add(new UndoableCommand( new AlignCommand(AlignCommand.Alignment.RIGHTS, this))); menu.addSeparator(); menu.add(new UndoableCommand( new AlignCommand(AlignCommand.Alignment.TOPS, this))); menu.add(new UndoableCommand( new AlignCommand(AlignCommand.Alignment.MIDDLES, this))); menu.add(new UndoableCommand( new AlignCommand(AlignCommand.Alignment.BOTTOMS, this))); return menu; } /** * Creates the debug menu. Clients override this * method to add additional menu items. */ protected JMenu createDebugMenu() { CommandMenu menu = new CommandMenu("Debug"); Command cmd = new AbstractCommand("Simple Update", this) { public void execute() { this.view().setDisplayUpdate(new SimpleUpdateStrategy()); } }; menu.add(cmd); cmd = new AbstractCommand("Buffered Update", this) { public void execute() { this.view().setDisplayUpdate(new BufferedUpdateStrategy()); } }; menu.add(cmd); return menu; } /** * Creates the attributes menu and its submenus. Clients override this * method to add additional menu items. */ protected JMenu createAttributesMenu() { JMenu menu = new JMenu("Attributes"); menu.add(createColorMenu("Fill Color", FigureAttributeConstant.FILL_COLOR)); menu.add(createColorMenu("Pen Color", FigureAttributeConstant.FRAME_COLOR)); menu.add(createArrowMenu()); menu.addSeparator(); menu.add(createFontMenu()); menu.add(createFontSizeMenu()); menu.add(createFontStyleMenu()); menu.add(createColorMenu("Text Color", FigureAttributeConstant.TEXT_COLOR)); return menu; } /** * Creates the color menu. */ protected JMenu createColorMenu(String title, FigureAttributeConstant attribute) { CommandMenu menu = new CommandMenu(title); for (int i=0; i<ColorMap.size(); i++) menu.add( new UndoableCommand( new ChangeAttributeCommand( ColorMap.name(i), attribute, ColorMap.color(i), this ) ) ); return menu; } /** * Creates the arrows menu. */ protected JMenu createArrowMenu() { FigureAttributeConstant arrowMode = FigureAttributeConstant.ARROW_MODE; CommandMenu menu = new CommandMenu("Arrow"); menu.add(new UndoableCommand( new ChangeAttributeCommand("none", arrowMode, new Integer(PolyLineFigure.ARROW_TIP_NONE), this))); menu.add(new UndoableCommand( new ChangeAttributeCommand("at Start", arrowMode, new Integer(PolyLineFigure.ARROW_TIP_START), this))); menu.add(new UndoableCommand( new ChangeAttributeCommand("at End", arrowMode, new Integer(PolyLineFigure.ARROW_TIP_END), this))); menu.add(new UndoableCommand( new ChangeAttributeCommand("at Both", arrowMode, new Integer(PolyLineFigure.ARROW_TIP_BOTH), this))); return menu; } /** * Creates the fonts menus. It installs all available fonts * supported by the toolkit implementation. */ protected JMenu createFontMenu() { CommandMenu menu = new CommandMenu("Font"); String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); for (int i = 0; i < fonts.length; i++) { menu.add(new UndoableCommand( new ChangeAttributeCommand(fonts[i], FigureAttributeConstant.FONT_NAME, fonts[i], this))); } return menu; } /** * Creates the font style menu with entries (Plain, Italic, Bold). */ protected JMenu createFontStyleMenu() { FigureAttributeConstant fontStyle = FigureAttributeConstant.FONT_STYLE; CommandMenu menu = new CommandMenu("Font Style"); menu.add(new UndoableCommand( new ChangeAttributeCommand("Plain", fontStyle, new Integer(Font.PLAIN), this))); menu.add(new UndoableCommand( new ChangeAttributeCommand("Italic", fontStyle, new Integer(Font.ITALIC), this))); menu.add(new UndoableCommand( new ChangeAttributeCommand("Bold", fontStyle, new Integer(Font.BOLD), this))); return menu; } /** * Creates the font size menu. */ protected JMenu createFontSizeMenu() { CommandMenu menu = new CommandMenu("Font Size"); int sizes[] = { 9, 10, 12, 14, 18, 24, 36, 48, 72 }; for (int i = 0; i < sizes.length; i++) { menu.add( new UndoableCommand( new ChangeAttributeCommand( Integer.toString(sizes[i]), FigureAttributeConstant.FONT_SIZE, new Integer(sizes[i]), this ) ) ); } return menu; } /** * Create a menu which allows the user to select a different look and feel at runtime. */ public JMenu createLookAndFeelMenu() { CommandMenu menu = new CommandMenu("Look'n'Feel"); UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); for (int i = 0; i < lafs.length; i++) { final String lnfClassName = lafs[i].getClassName(); Command cmd = new AbstractCommand(lafs[i].getName(), this) { public void execute() { newLookAndFeel(lnfClassName); } }; menu.add(cmd); } return menu; } /** * Creates the tool palette. */ protected JToolBar createToolPalette() { JToolBar palette = new JToolBar(); palette.setBackground(Color.lightGray); // use standard FlowLayout for JToolBar // palette.setLayout(new PaletteLayout(2,new Point(2,2))); return palette; } /** * Creates the tools. By default only the selection tool is added. * Override this method to add additional tools. * Call the inherited method to include the selection tool. * @param palette the palette where the tools are added. */ protected void createTools(JToolBar palette) { setDefaultTool(createDefaultTool()); palette.add(fDefaultToolButton); } /** * Creates the selection tool used in this editor. Override to use * a custom selection tool. */ protected Tool createSelectionTool() { return new SelectionTool(this); } protected Tool createDefaultTool() { return createSelectionTool(); } protected void setDefaultTool(Tool newDefaultTool) { if (newDefaultTool != null) { fDefaultToolButton = createToolButton(IMAGES+"SEL", "Selection Tool", newDefaultTool); } else { fDefaultToolButton = null; } } public Tool getDefaultTool() { if (fDefaultToolButton != null) { return fDefaultToolButton.tool(); } else { return null; } } /** * Creates a tool button with the given image, tool, and text */ protected ToolButton createToolButton(String iconName, String toolName, Tool tool) { return new ToolButton(this, iconName, toolName, tool); } /** * Creates the drawing view used in this application. * You need to override this method to use a DrawingView * subclass in your application. By default a standard * DrawingView is returned. */ protected DrawingView createDrawingView() { DrawingView createdDrawingView = createDrawingView(createDrawing()); createdDrawingView.drawing().setTitle(getDefaultDrawingTitle()); return createdDrawingView; } protected DrawingView createDrawingView(Drawing newDrawing) { Dimension d = getDrawingViewSize(); DrawingView newDrawingView = new StandardDrawingView(this, d.width, d.height); newDrawingView.setDrawing(newDrawing); // notify listeners about created view when the view is added to the desktop //fireViewCreatedEvent(newDrawingView); return newDrawingView; } /** * Create the DrawingView that is active when the application is started. * This initial DrawingView might be different from DrawingView created * by the application, so subclasses can override this method to provide * a special drawing view for application startup time, e.g. a NullDrawingView * which does not display an internal frame in a multiple document interface * (MDI) application. * * @return drawing view that is active at application startup time */ protected DrawingView createInitialDrawingView() { return createDrawingView(); } /** * Override to define the dimensions of the drawing view. */ protected Dimension getDrawingViewSize() { return new Dimension(800, 800); } /** * Creates the drawing used in this application. * You need to override this method to use a Drawing * subclass in your application. By default a standard * Drawing is returned. */ protected Drawing createDrawing() { return new StandardDrawing(); } protected Desktop createDesktop() { return new JPanelDesktop(this); // return new JScrollPaneDesktop(); } protected void setDesktop(Desktop newDesktop) { newDesktop.addDesktopListener(getDesktopListener()); fDesktop = newDesktop; } /** * Get the component, in which the content is embedded. This component * acts as a desktop for the content. */ public Desktop getDesktop() { return fDesktop; } /** * Factory method to create a StorageFormatManager for supported storage formats. * Different applications might want to use different storage formats and can return * their own format manager by overriding this method. */ public StorageFormatManager createStorageFormatManager() { StorageFormatManager storageFormatManager = new StorageFormatManager(); storageFormatManager.setDefaultStorageFormat(new StandardStorageFormat()); storageFormatManager.addStorageFormat(storageFormatManager.getDefaultStorageFormat()); storageFormatManager.addStorageFormat(new SerializationStorageFormat()); // storageFormatManager.addStorageFormat(new JDOStorageFormat()); return storageFormatManager; } /** * Set the StorageFormatManager. The StorageFormatManager is used when storing and * restoring Drawing from the file system. */ protected final void setStorageFormatManager(StorageFormatManager newStorageFormatManager) { fStorageFormatManager = newStorageFormatManager; } /** * Return the StorageFormatManager for this application.The StorageFormatManager is * used when storing and restoring Drawing from the file system. */ public StorageFormatManager getStorageFormatManager() { return fStorageFormatManager; } /** * Gets the default size of the window. */ protected Dimension defaultSize() { return new Dimension(600,450); } /** * Creates the status line. */ protected JTextField createStatusLine() { JTextField field = new JTextField("No Tool", 40); field.setBackground(Color.white); field.setEditable(false); return field; } protected void setStatusLine(JTextField newStatusLine) { fStatusLine = newStatusLine; } protected JTextField getStatusLine() { return fStatusLine; } /** * Handles a user selection in the palette. * @see PaletteListener */ public void paletteUserSelected(PaletteButton paletteButton) { ToolButton toolButton = (ToolButton)paletteButton; setTool(toolButton.tool(), toolButton.name()); setSelected(toolButton); } /** * Handles when the mouse enters or leaves a palette button. * @see PaletteListener */ public void paletteUserOver(PaletteButton paletteButton, boolean inside) { ToolButton toolButton = (ToolButton)paletteButton; if (inside) { showStatus(toolButton.name()); } else if (fSelectedToolButton != null) { showStatus(fSelectedToolButton.name()); } } /** * Gets the current tool. * @see DrawingEditor */ public Tool tool() { return fTool; } /** * Retrieve the active view from the window * Gets the current drawing view. * @see DrawingEditor */ public DrawingView view() { return fView; } protected void setView(DrawingView newView) { DrawingView oldView = fView; fView = newView; fireViewSelectionChangedEvent(oldView, view()); } public DrawingView[] views() { return new DrawingView[] { view() }; } /** * Sets the default tool of the editor. * @see DrawingEditor */ public void toolDone() { // TODO: toolDone() seemed to be called twice/too often if (fDefaultToolButton != null) { setTool(fDefaultToolButton.tool(), fDefaultToolButton.name()); setSelected(fDefaultToolButton); } } /** * Fired by a view when the figure selection changes. Since Commands and * Tools may depend on the figure selection they are registered to be notified * about these events. * Any selection sensitive GUI component should update its * own state if the selection has changed, e.g. selection sensitive menuitems * will update their own states. * @see DrawingEditor */ public void figureSelectionChanged(DrawingView view) { checkCommandMenus(); } protected void checkCommandMenus() { JMenuBar mb = getJMenuBar(); for (int x = 0; x < mb.getMenuCount(); x++) { JMenu jm = mb.getMenu(x); if (CommandMenu.class.isInstance(jm)) { checkCommandMenu((CommandMenu)jm); } } } protected void checkCommandMenu(CommandMenu cm) { cm.checkEnabled(); for (int y = 0; y < cm.getItemCount();y++) { JMenuItem jmi = cm.getItem(y); if (CommandMenu.class.isInstance(jmi)) { checkCommandMenu((CommandMenu)jmi); } } } /** * Register to hear when the active view is changed. For Single document * interface, this will happen when a new drawing is created. */ public void addViewChangeListener(ViewChangeListener vsl) { listeners.add(vsl); } /** * Remove listener */ public void removeViewChangeListener(ViewChangeListener vsl) { listeners.remove(vsl); } /** * An appropriate event is triggered and all registered observers * are notified if the drawing view has been changed, e.g. by * switching between several internal frames. This method is * usually not needed in SDI environments. */ protected void fireViewSelectionChangedEvent(DrawingView oldView, DrawingView newView) { ListIterator li= listeners.listIterator(listeners.size()); while (li.hasPrevious()) { ViewChangeListener vsl = (ViewChangeListener)li.previous(); vsl.viewSelectionChanged(oldView, newView); } } protected void fireViewCreatedEvent(DrawingView view) { ListIterator li= listeners.listIterator(listeners.size()); while (li.hasPrevious()) { ViewChangeListener vsl = (ViewChangeListener)li.previous(); vsl.viewCreated(view); } } protected void fireViewDestroyingEvent(DrawingView view) { ListIterator li= listeners.listIterator(listeners.size()); while (li.hasPrevious()) { ViewChangeListener vsl = (ViewChangeListener)li.previous(); vsl.viewDestroying( view ); } } /** * Shows a status message. * @see DrawingEditor */ public void showStatus(String string) { getStatusLine().setText(string); } /** * Note: it is inconsistent to directly assign a variable but when using it * use it from a method. (assignment: fTool = t, usage: tool()) dnoyeB-4/8/02 * Note: should we check that the tool is inactive before we activate it? * this would be consistent with how we do deactivate. I think we should do * this now and not wait till a bug pops up. even if their is no bug, its * consistent and adds understandability to the code. dnoyeB-4/8/02 */ public void setTool(Tool t, String name) { // SF bug-tracker id: #490665 // deactivate only those tools that have been activated before if ((tool() != null) && (tool().isActive())) { tool().deactivate(); } fTool = t; if (tool() != null) { showStatus(name); tool().activate(); } } private void setSelected(ToolButton button) { if (fSelectedToolButton != null) { fSelectedToolButton.reset(); } fSelectedToolButton = button; if (fSelectedToolButton != null) { fSelectedToolButton.select(); } } /** * Exits the application. You should never override this method */ public void exit() { destroy(); // tell windowing system to free resources dispose(); } protected boolean closeQuery(){ return true; } protected void endApp(){ if(closeQuery() == true) { exit(); } } /** * Handles additional clean up operations. Override to destroy * or release drawing editor resources. */ protected void destroy() { } /** * Resets the drawing to a new empty drawing. */ public void promptNew() { newWindow(createDrawing()); //toolDone(); //view().setDrawing(createDrawing()); } /** * Shows a file dialog and opens a drawing. */ public void promptOpen() { toolDone(); JFileChooser openDialog = createOpenFileChooser(); getStorageFormatManager().registerFileFilters(openDialog); if (openDialog.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { StorageFormat foundFormat = getStorageFormatManager().findStorageFormat(openDialog.getFileFilter()); // ricardo_padilha: if there is no format associated, // try to find one that supports the file if (foundFormat == null) { foundFormat = getStorageFormatManager().findStorageFormat(openDialog.getSelectedFile()); } if (foundFormat != null) { loadDrawing(foundFormat, openDialog.getSelectedFile().getAbsolutePath()); } else { showStatus("Not a valid file format: " + openDialog.getFileFilter().getDescription()); } } } /** * Shows a file dialog and saves drawing. */ public void promptSaveAs() { if (view() != null) { toolDone(); JFileChooser saveDialog = createSaveFileChooser(); getStorageFormatManager().registerFileFilters(saveDialog); if (saveDialog.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { StorageFormat foundFormat = getStorageFormatManager().findStorageFormat(saveDialog.getFileFilter()); // ricardo_padilha: if there is no format associated, // try to find one that supports the file if (foundFormat == null) { foundFormat = getStorageFormatManager().findStorageFormat(saveDialog.getSelectedFile()); } if (foundFormat != null) { saveDrawing(foundFormat, saveDialog.getSelectedFile().getAbsolutePath()); } else { showStatus("Not a valid file format: " + saveDialog.getFileFilter().getDescription()); } } } } /** * Create a file chooser for the open file dialog. Subclasses may override this * method in order to customize the open file dialog. */ protected JFileChooser createOpenFileChooser() { JFileChooser openDialog = new JFileChooser(); openDialog.setDialogType(JFileChooser.OPEN_DIALOG); openDialog.setDialogTitle("Open File..."); return openDialog; } /** * Create a file chooser for the save file dialog. Subclasses may override this * method in order to customize the save file dialog. */ protected JFileChooser createSaveFileChooser() { JFileChooser saveDialog = new JFileChooser(); saveDialog.setDialogType(JFileChooser.SAVE_DIALOG); saveDialog.setDialogTitle("Save File..."); return saveDialog; } /** * Prints the drawing. */ public void print() { tool().deactivate(); PrintJob printJob = getToolkit().getPrintJob(this, "Print Drawing", null); if (printJob != null) { Graphics pg = printJob.getGraphics(); if (pg != null) { ((StandardDrawingView)view()).printAll(pg); pg.dispose(); // flush page } printJob.end(); } tool().activate(); } /** * Save a Drawing in a file */ protected void saveDrawing(StorageFormat storeFormat, String file) { // Need a better alert than this. if (view() == null) { return; } try { String name = storeFormat.store(file, view().drawing()); view().drawing().setTitle(name); setDrawingTitle(name); } catch (IOException e) { showStatus(e.toString()); } } /** * Load a Drawing from a file */ protected void loadDrawing(StorageFormat restoreFormat, String file) { try { Drawing restoredDrawing = restoreFormat.restore(file); if (restoredDrawing != null) { restoredDrawing.setTitle(file); newWindow(restoredDrawing); } else { showStatus("Unknown file type: could not open file '" + file + "'"); } } catch (IOException e) { showStatus("Error: " + e); } } /** * Switch to a new Look&Feel */ private void newLookAndFeel(String landf) { try { UIManager.setLookAndFeel(landf); SwingUtilities.updateComponentTreeUI(this); } catch (Exception e) { System.err.println(e); } } /** * Set the title of the currently selected drawing */ protected void setDrawingTitle(String drawingTitle) { if (getDefaultDrawingTitle().equals(drawingTitle)) { setTitle(getApplicationName()); } else { setTitle(getApplicationName() + " - " + drawingTitle); } } /** * Return the title of the currently selected drawing */ protected String getDrawingTitle() { return view().drawing().getTitle(); } /** * Set the name of the application build from this skeleton application */ public void setApplicationName(String applicationName) { fApplicationName = applicationName; } /** * Return the name of the application build from this skeleton application */ public String getApplicationName() { return fApplicationName; } protected void setUndoManager(UndoManager newUndoManager) { myUndoManager = newUndoManager; } public UndoManager getUndoManager() { return myUndoManager; } protected VersionControlStrategy getVersionControlStrategy() { return new StandardVersionControlStrategy(this); } /** * Subclasses should override this method to specify to which versions of * JHotDraw they are compatible. A string array is returned so it is possible * to specify several version numbers of JHotDraw to which the application * is compatible with. * * @return all versions number of JHotDraw the application is compatible with. */ public String[] getRequiredVersions() { String[] requiredVersions = new String[1]; // return the version of the package we are in requiredVersions[0] = VersionManagement.getPackageVersion(DrawApplication.class.getPackage()); return requiredVersions; } public String getDefaultDrawingTitle() { return fgUntitled; } protected DesktopListener getDesktopListener() { return fDesktopListener; } protected void setDesktopListener(DesktopListener desktopPaneListener) { fDesktopListener = desktopPaneListener; } protected DesktopListener createDesktopListener() { return new DesktopListener() { public void drawingViewAdded(DesktopEvent dpe) { DrawingView dv = dpe.getDrawingView(); fireViewCreatedEvent(dv); } public void drawingViewRemoved(DesktopEvent dpe) { DrawingView dv = dpe.getDrawingView(); // remove undo/redo activities which operate on this DrawingView getUndoManager().clearUndos(dv); getUndoManager().clearRedos(dv); fireViewDestroyingEvent(dv); checkCommandMenus(); } public void drawingViewSelected(DesktopEvent dpe) { DrawingView dv = dpe.getDrawingView(); //get the current selection and freeze it. if (dv != null) { if (dv.drawing() != null) dv.unfreezeView(); } setView(dv); } }; } protected Iconkit createIconkit() { return new Iconkit(this); } protected void setIconkit(Iconkit newIconkit) { fIconkit = newIconkit; } protected Iconkit getIconkit() { return fIconkit; } }