/* * @(#)DrawApplication.java * * Project: JHotdraw - a GUI framework for technical drawings * http://www.jhotdraw.org * http://jhotdraw.sourceforge.net * Copyright: � by the original author(s) and all contributors * License: Lesser GNU Public License (LGPL) * http://www.opensource.org/licenses/lgpl-license.html */ package CH.ifa.draw.application; import CH.ifa.draw.framework.*; import CH.ifa.draw.standard.*; import CH.ifa.draw.figures.*; import CH.ifa.draw.util.*; import javax.swing.*; import javax.swing.event.EventListenerList; import java.awt.*; import java.awt.event.*; import java.util.*; import java.io.*; /** * 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"; private final EventListenerList listenerList = new EventListenerList(); // the image resource path private static final String fgDrawPath = "/CH/ifa/draw/"; 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); setApplicationName(title); winCount++; } /** * 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(createDrawingView(initialDrawing)); } } /** * Opens a new window */ public void open() { open(createInitialDrawingView()); } /** * Opens a new window with a drawing view. */ protected void open(DrawingView newDrawingView) { getVersionControlStrategy().assertCompatibleVersion(); setUndoManager(new UndoManager()); fIconkit = new Iconkit(this); getContentPane().setLayout(new BorderLayout()); // status line must be created before a tool is set fStatusLine = createStatusLine(); getContentPane().add(fStatusLine, BorderLayout.SOUTH); // create dummy tool until the default tool is activated during toolDone() setTool(new NullTool(this), ""); setView(newDrawingView); JComponent contents = createContents(view()); contents.setAlignmentX(LEFT_ALIGNMENT); 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); activePanel.add(contents, 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(); setVisible(true); fStorageFormatManager = createStorageFormatManager(); toolDone(); } /** * Registers the listeners for this window */ protected void addListeners() { addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent event) { exit(); } } ); } /** * 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() { exit(); } }; 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 executable() { this.view().setDisplayUpdate(new SimpleUpdateStrategy()); } }; menu.add(cmd); cmd = new AbstractCommand("Buffered Update", this) { public void executable() { 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", "FillColor")); menu.add(createColorMenu("Pen Color", "FrameColor")); menu.add(createArrowMenu()); menu.addSeparator(); menu.add(createFontMenu()); menu.add(createFontSizeMenu()); menu.add(createFontStyleMenu()); menu.add(createColorMenu("Text Color", "TextColor")); return menu; } /** * Creates the color menu. */ protected JMenu createColorMenu(String title, String 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() { 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[] = Toolkit.getDefaultToolkit().getFontList(); for (int i = 0; i < fonts.length; i++) { menu.add(new UndoableCommand( new ChangeAttributeCommand(fonts[i], "FontName", fonts[i], this))); } return menu; } /** * Creates the font style menu with entries (Plain, Italic, Bold). */ protected JMenu createFontStyleMenu() { 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]), "FontSize", 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) { Tool tool = createSelectionTool(); fDefaultToolButton = createToolButton(IMAGES+"SEL", "Selection Tool", tool); 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); } /** * 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); 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(); } /** * Creates the contents component of the application * frame. By default the DrawingView is returned in * a JScrollPane. */ protected JComponent createContents(DrawingView view) { if (view instanceof Component) { JScrollPane sp = new JScrollPane((Component)view); sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); return sp; } else { return new JPanel(); } } /** * 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()); return storageFormatManager; } /** * Set the StorageFormatManager. The StorageFormatManager is used when storing and * restoring Drawing from the file system. * Should we through IllegalArguementException if it is? */ protected final void setStorageFormatManager(StorageFormatManager storageFormatManager) { fStorageFormatManager = storageFormatManager; } /** * 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; } /** * Handles a user selection in the palette. * @see PaletteListener */ public void paletteUserSelected(PaletteButton button) { ToolButton toolButton = (ToolButton) button; setTool(toolButton.tool(), toolButton.name()); setSelected(toolButton); } /** * Handles when the mouse enters or leaves a palette button. * @see PaletteListener */ public void paletteUserOver(PaletteButton button, boolean inside) { ToolButton toolButton = (ToolButton) button; if (inside) { showStatus(toolButton.name()); } else { 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() { if (fDefaultToolButton != null) { setTool(fDefaultToolButton.tool(), fDefaultToolButton.name()); setSelected(fDefaultToolButton); } } /** * Fired by a view when the figure seleciton changes. Since Commands and * Tools are Actions and they are registered to hear these events, they will * handle themselves. So selection sensitive menuitems will update their * own states. * @see DrawingEditor */ public void figureSelectionChanged(DrawingView view) { JMenuBar mb = getJMenuBar(); CommandMenu editMenu = (CommandMenu)mb.getMenu(EDIT_MENU); // make sure it does exist if (editMenu != null) { editMenu.checkEnabled(); } CommandMenu alignmentMenu = (CommandMenu)mb.getMenu(ALIGNMENT_MENU); // make sure it does exist if (alignmentMenu != null) { alignmentMenu.checkEnabled(); } JMenu attributeMenu = mb.getMenu(ATTRIBUTES_MENU); // make sure it does exist if (attributeMenu != null) { for (int i = 0; i < attributeMenu.getItemCount(); i++) { JMenuItem currentMenu = attributeMenu.getItem(i); if (currentMenu instanceof CommandMenu) { ((CommandMenu)currentMenu).checkEnabled(); } } } } /** * 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) { listenerList.add(ViewChangeListener.class, vsl); } /** * Remove listener */ public void removeViewChangeListener(ViewChangeListener vsl) { listenerList.remove(ViewChangeListener.class, 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) { final Object[] listeners = listenerList.getListenerList(); ViewChangeListener vsl = null; for (int i = listeners.length-2; i>=0 ; i-=2) { if (listeners[i] == ViewChangeListener.class) { vsl = (ViewChangeListener)listeners[i+1]; vsl.viewSelectionChanged(oldView, newView); } } } protected void fireViewCreatedEvent(DrawingView view) { final Object[] listeners = listenerList.getListenerList(); ViewChangeListener vsl = null; for (int i = listeners.length-2; i>=0 ; i-=2) { if (listeners[i] == ViewChangeListener.class) { vsl = (ViewChangeListener)listeners[i+1]; vsl.viewCreated(view); } } } protected void fireViewDestroyingEvent(DrawingView view) { final Object[] listeners = listenerList.getListenerList(); ViewChangeListener vsl = null; for (int i = listeners.length-2; i>=0 ; i-=2) { if (listeners[i] == ViewChangeListener.class) { vsl = (ViewChangeListener)listeners[i+1]; vsl.viewDestroying( view ); } } } /** * Shows a status message. * @see DrawingEditor */ public void showStatus(String string) { fStatusLine.setText(string); } 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(); setVisible(false); // hide the JFrame dispose(); // tell windowing system to free resources winCount--; if (winCount == 0) { System.exit(0); } } /** * 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() { toolDone(); view().setDrawing(createDrawing()); view().drawing().setTitle(getDefaultDrawingTitle()); } /** * 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()); 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() { toolDone(); JFileChooser saveDialog = createSaveFileChooser(); getStorageFormatManager().registerFileFilters(saveDialog); if (saveDialog.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { StorageFormat foundFormat = getStorageFormatManager().findStorageFormat(saveDialog.getFileFilter()); 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.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.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; } protected String getDefaultDrawingTitle() { return fgUntitled; } }