/* * @(#)MDI_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.contrib; import 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.*; import java.awt.*; import java.util.*; /** * Many applications have the ability to deal with multiple internal windows. * MDI_DrawApplications provides the basic facilities to make use of MDI in * JHotDraw. Its main tasks are to create a content for DrawApplications, which * is embedded in internal frames, to maintain a list with all internal frames * and to manage the switching between them. * * @author Wolfram Kaiser * @version <$CURRENT_VERSION$> */ public class MDI_DrawApplication extends DrawApplication implements InternalFrameListener { /** * Internal frame, which is currently activated. This frame receives all * mouse input and displays the Drawing to be manipulated. */ private MDI_InternalFrame currentFrame; /** * This component acts as a desktop for the content. */ private JComponent desktop; /** * List of listeners which adhere to the InternalFrameListener interface */ private Vector mdiListeners; /** * Constructs a drawing window with a default title. */ public MDI_DrawApplication() { this("JHotDraw"); } /** * Constructs a drawing window with the given title. */ public MDI_DrawApplication(String title) { super(title); setDesktop(new MDIDesktopPane()); getDesktop().setAlignmentX(JComponent.LEFT_ALIGNMENT); mdiListeners = new Vector(); addInternalFrameListener(this); } /** * Factory method which can be overriden by subclasses to * create an instance of their type. * * @return newly created application */ protected DrawApplication createApplication() { return new MDI_DrawApplication(); } /** * 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) { super.createTools(palette); Tool tool = new DragNDropTool( this ); ToolButton tb = createToolButton(IMAGES+"SEL", "Drag N Drop Tool", tool); palette.add( tb ); } /** * Creates the contents component of the application * frame. By default the DrawingView is returned in * a JScrollPane. */ protected JComponent createContents(DrawingView view) { if (view.isInteractive()) { MDI_InternalFrame internalFrame = createInternalFrame(view); JComponent contents = super.createContents(view); internalFrame.getContentPane().add(contents); getDesktop().add(internalFrame); internalFrame.setVisible(true); //unsafe to set visible here since the desktopPane has not been added to desktop yet (and has no peer I don't believe) try { internalFrame.setSelected(true); } catch (java.beans.PropertyVetoException e) { // ignore } } // return container in which the internal frame is embedded return getDesktop(); } /** * Factory method which creates an internal frame. Subclasses may override this * method to provide their own implementations of MDI_InternalFrame */ protected MDI_InternalFrame createInternalFrame(DrawingView view) { String applicationTitle = null; if ((view == null) || (view.drawing() == null) || (view.drawing().getTitle() == null)) { applicationTitle = getApplicationName() + " - " + getDefaultDrawingTitle(); } else { applicationTitle = getApplicationName() + " - " + view.drawing().getTitle(); } MDI_InternalFrame internalFrame = new MDI_InternalFrame(applicationTitle, true, true, true, true); internalFrame.setDrawingView(view); internalFrame.setSize(200, 200); // all registered listeners to the new internal frame Enumeration enum = mdiListeners.elements(); while (enum.hasMoreElements()) { internalFrame.addInternalFrameListener((InternalFrameListener)enum.nextElement()); } fireViewCreatedEvent(view); // frame now has connection all the way to heavyweight component // return container in which the internal frame is embedded return internalFrame; } /** * Resets the drawing to a new empty drawing. If no internal frame * exists then open a new internal frame. */ public void promptNew() { if (hasInternalFrames()) { super.promptNew(); } else { newWindow(createDrawing()); } } /** * Method to create a new internal frame. Applications that want * to create a new internal drawing view should call this method. */ public void newWindow(Drawing newDrawing) { DrawingView newView = createDrawingView(); newView.setDrawing(newDrawing); createContents(newView); toolDone(); } /* protected DrawingView createDrawingView() { Dimension d = getDrawingViewSize(); return new StandardDrawingView(this, d.width, d.height); } */ public void newView() { if (!view().isInteractive()) { return; } String copyTitle = view().drawing().getTitle(); DrawingView fView = createDrawingView(); fView.setDrawing( view().drawing() ); createContents(fView); if(copyTitle != null ) { setDrawingTitle(copyTitle + " (View)"); } else { setDrawingTitle( getDefaultDrawingTitle() + " (View)"); } toolDone(); } /** * Set the component, in which the content is embedded. This component * acts as a desktop for the content. */ protected void setDesktop(JComponent newDesktop) { desktop = newDesktop; } /** * Get the component, in which the content is embedded. This component * acts as a desktop for the content. */ public JComponent getDesktop() { return desktop; } /** * Add a new listener to the applications internal frames. If a new internal * frame is created, all currently registered InternalFrameListeners are * added as listeners to that internal frame as well. * * @param newMDIListener listener to be added */ public void addInternalFrameListener(InternalFrameListener newMDIListener) { mdiListeners.addElement(newMDIListener); } /** * Remove a InternalFrameListeners from the application. * * @param oldMDIListener listener to be removed */ public void removeInternalFrameListener(InternalFrameListener oldMDIListener) { mdiListeners.removeElement(oldMDIListener); } /** * Activate an internal frame upon which the selected tools operate. * The currently activated DrawgingView is backed up for later restorage. */ public void activateFrame(MDI_InternalFrame newFrame) { if (currentFrame != newFrame) { // check, whether drawing has been already initialised if (newFrame.getDrawingView().drawing() != null) { newFrame.getDrawingView().unfreezeView(); } if(currentFrame != null ) { currentFrame.getDrawingView().freezeView(); currentFrame.getDrawingView().clearSelection(); } currentFrame = newFrame; } setView( currentFrame.getDrawingView() ); } /** * If the frame we are deactivating is the current frame, set the * currentFrame to null */ public void deactivateFrame(MDI_InternalFrame frame) { if( currentFrame == frame ) { currentFrame = null; } } /** * Notification method from InternalFrameListener, which is called * if a internal frame gets selected. */ public void internalFrameActivated(InternalFrameEvent e) { activateFrame((MDI_InternalFrame)e.getSource()); } /** * Notification method from InternalFrameListener, which is called * if a internal frame is opend. */ public void internalFrameOpened(InternalFrameEvent e) { } /** * Notification method from InternalFrameListener, which is called * before a internal frame is closed. */ public void internalFrameClosing(InternalFrameEvent e) { MDI_InternalFrame mdf = (MDI_InternalFrame)e.getSource(); DrawingView dv = mdf.getDrawingView(); fireViewDestroyingEvent( dv ); if( mdf == currentFrame) { currentFrame = null; setView(NullDrawingView.getManagedDrawingView(this)); } } /** * Notification method from InternalFrameListener, which is called * if a internal frame is closed. */ public void internalFrameClosed(InternalFrameEvent e) { } /** * Notification method from InternalFrameListener, which is called * if a internal frame gets iconified. */ public void internalFrameIconified(InternalFrameEvent e) { } /** * Notification method from InternalFrameListener, which is called * if a internal frame gets deiconified. */ public void internalFrameDeiconified(InternalFrameEvent e) { //activateFrame((MDI_InternalFrame)e.getSource()); } /** * Notification method from InternalFrameListener, which is called * if a internal frame gets deactivated. */ public void internalFrameDeactivated(InternalFrameEvent e) { deactivateFrame((MDI_InternalFrame)e.getSource()); } /** * Set the title for the drawing. The title also appears in the * internal frame title bar. A name is assigned when a drawing * saved or a saved drawing is loaded. The file name is the * drawing title. If the drawing has not been saved before then * the drawing title is "untitled". */ protected void setDrawingTitle(String newDrawingTitle) { currentFrame.setTitle( getApplicationName() + " - " + newDrawingTitle ); } /** * Get the title for the drawing. */ protected String getDrawingTitle() { return currentFrame.getDrawing().getTitle(); } public boolean hasInternalFrames() { return ((JDesktopPane)getDesktop()).getAllFrames().length > 0; } /** * Returns all the views in the application */ public DrawingView[] views() { DrawingView[] views; ArrayList frames = new ArrayList(); JInternalFrame[] ifs = ((JDesktopPane)getDesktop()).getAllFrames(); for(int x=0; x < ifs.length ; x++) { /* Can not use class.isInstance() here since DrawingView is an interface */ /* Can not use instanceof here since DrawingView is interface */ if( MDI_InternalFrame.class.isInstance( ifs[x] ) ) { DrawingView dv = ((MDI_InternalFrame)ifs[x]).getDrawingView(); if( DrawingView.class.isInstance( dv ) ) { frames.add( dv ); } } } views = new DrawingView[ frames.size() ]; frames.toArray( views ); return views; } }