/* Violet - A program for editing UML diagrams. Copyright (C) 2008 Cay S. Horstmann (http://horstmann.com) Alexandre de Pellegrin (http://alexdp.free.fr); This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.horstmann.violet.application.gui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.Image; import java.awt.Toolkit; import java.awt.geom.Point2D; import java.beans.BeanInfo; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JMenuBar; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import com.horstmann.violet.application.autosave.AutoSave; import com.horstmann.violet.application.help.AboutDialog; import com.horstmann.violet.application.menu.MenuFactory; import com.horstmann.violet.framework.dialog.DialogFactory; import com.horstmann.violet.framework.file.GraphFile; import com.horstmann.violet.framework.file.IFile; import com.horstmann.violet.framework.file.IGraphFile; import com.horstmann.violet.framework.file.chooser.IFileChooserService; import com.horstmann.violet.framework.injection.bean.ManiocFramework.BeanInjector; import com.horstmann.violet.framework.injection.bean.ManiocFramework.InjectedBean; import com.horstmann.violet.framework.injection.resources.ResourceBundleInjector; import com.horstmann.violet.framework.injection.resources.annotation.ResourceBundleBean; import com.horstmann.violet.product.diagram.property.ArrowheadChoiceList; import com.horstmann.violet.framework.theme.ITheme; import com.horstmann.violet.framework.theme.ThemeManager; import com.horstmann.violet.product.diagram.abstracts.IGraph; import com.horstmann.violet.product.diagram.abstracts.node.AbstractNode; import com.horstmann.violet.product.diagram.property.BentStyleChoiceList; import com.horstmann.violet.product.diagram.property.LineStyleChoiceList; import com.horstmann.violet.workspace.IWorkspace; import com.horstmann.violet.workspace.IWorkspaceListener; import com.horstmann.violet.workspace.Workspace; import com.horstmann.violet.workspace.WorkspacePanel; /** * This desktop frame contains panes that show graphs. * * @author Alexandre de Pellegrin */ @ResourceBundleBean(resourceReference = AboutDialog.class) public class MainFrame extends JFrame { /** * Constructs a blank frame with a desktop pane but no graph windows. * */ public MainFrame() { BeanInjector.getInjector().inject(this); ResourceBundleInjector.getInjector().inject(this); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); this.dialogFactory.setDialogOwner(this); decorateFrame(); setInitialSize(); createMenuBar(); getContentPane().add(this.getMainPanel()); startAutoSave(); } /** * Sets initial size on startup */ private void setInitialSize() { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int screenWidth = (int) screenSize.getWidth(); int screenHeight = (int) screenSize.getHeight(); setBounds(screenWidth / 16, screenHeight / 16, screenWidth * 7 / 8, screenHeight * 7 / 8); setLocation(0, 0); // For screenshots only -> setBounds(50, 50, 850, 650); } /** * Decorates the frame (title, icon...) */ private void decorateFrame() { setTitle(this.applicationName); setIconImage(this.applicationIcon); } /** * Creates menu bar */ private void createMenuBar() { JMenuBar menuBar = new JMenuBar(); menuBar.setFont(this.themeManager.getTheme().getMenubarFont()); MenuFactory menuFactory = getMenuFactory(); menuBar.add(menuFactory.getFileMenu(this)); menuBar.add(menuFactory.getEditMenu(this)); menuBar.add(menuFactory.getViewMenu(this)); menuBar.add(menuFactory.getDocumentMenu(this)); menuBar.add(menuFactory.getHelpMenu(this)); setJMenuBar(menuBar); } private void startAutoSave() { new AutoSave(this); } /** * Add a listener to perform action when something happens on this diagram * * @param workspace */ private void listenToWorkspaceEvents(final IWorkspace workspace) { workspace.addListener(new IWorkspaceListener() { public void titleChanged(String newTitle) { setTitle(newTitle); } public void graphCouldBeSaved() { // nothing to do here } public void mustOpenfile(IFile file) { try { IGraphFile graphFile = new GraphFile(file); IWorkspace newWorkspace = new Workspace(graphFile); addWorkspace(newWorkspace); } catch (IOException e) { DialogFactory.getInstance().showErrorDialog(e.getMessage()); } } }); } /** * Removes a diagram panel from this editor frame * * @param diagramPanel */ public void removeWorkspace(IWorkspace workspaceToRemove) { if (!this.workspaceList.contains(workspaceToRemove)) { return; } int pos = this.workspaceList.indexOf(workspaceToRemove); if (pos < 0) { return; } boolean isWorkspaceDisplayed = workspaceToRemove.equals(getActiveWorkspace()); if (!isWorkspaceDisplayed) { // TODO : update window menu here return; } this.workspaceList.remove(workspaceToRemove); if (pos >= this.workspaceList.size()) { pos = this.workspaceList.size() - 1; } if (pos < 0) { Component currentWorkspaceComponent = ((BorderLayout) getMainPanel().getLayout()).getLayoutComponent(BorderLayout.CENTER); getMainPanel().remove(currentWorkspaceComponent); getMainPanel().add(new JPanel(), BorderLayout.CENTER); setTitle(this.applicationName); menuFactory.getDocumentMenu(this).updateMenuItem(); getMainPanel().revalidate(); getMainPanel().repaint(); return; } IWorkspace workspaceToDisplay = this.workspaceList.get(pos); setActiveWorkspace(workspaceToDisplay); } public void addWorkspace(IWorkspace newWorkspace) { this.workspaceList.add(newWorkspace); setActiveWorkspace(newWorkspace); } /** * Looks for an opened diagram from its file path and focus it * * @param diagramFilePath diagram file path */ public void setActiveWorkspace(IFile aGraphFile) { if (aGraphFile == null) return; for (IWorkspace aWorkspace : this.workspaceList) { IFile toCompare = aWorkspace.getGraphFile(); boolean isSameFilename = aGraphFile.getFilename().equals(toCompare.getFilename()); if (isSameFilename) { setActiveWorkspace(aWorkspace); return; } } } public void setActiveWorkspace(IWorkspace activeWorkspace) { if (!this.workspaceList.contains(activeWorkspace)) { return; } WorkspacePanel activeWorkspaceComponent = activeWorkspace.getAWTComponent(); Component currentWorkspaceComponent = ((BorderLayout) getMainPanel().getLayout()).getLayoutComponent(BorderLayout.CENTER); getMainPanel().remove(currentWorkspaceComponent); getMainPanel().add(activeWorkspaceComponent, BorderLayout.CENTER); listenToWorkspaceEvents(activeWorkspace); menuFactory.getDocumentMenu(this).updateMenuItem(); setTitle(activeWorkspace.getTitle()); getMainPanel().revalidate(); getMainPanel().repaint(); } /** * @return true if at least a diagram is displayed */ public boolean isThereAnyDiagramDisplayed() { return !this.workspaceList.isEmpty(); } public List<IWorkspace> getWorkspaceList() { return workspaceList; } /** * @return selected diagram file path (or null if not one is selected; that should never happen) */ public IWorkspace getActiveWorkspace() { Component activeWorkspace = ((BorderLayout) getMainPanel().getLayout()).getLayoutComponent(BorderLayout.CENTER); if (activeWorkspace == null) { return null; } for (IWorkspace aWorkspace : this.workspaceList) { if (activeWorkspace.equals(aWorkspace.getAWTComponent())) { return aWorkspace; } } return null; } private JPanel getMainPanel() { if (this.mainPanel == null) { this.mainPanel = new JPanel(new BorderLayout()); this.mainPanel.setBorder(new EmptyBorder(0, 0, 0, 0)); this.mainPanel.add(new JPanel(), BorderLayout.CENTER); JPanel bottomBorderPanel = new JPanel(); ITheme cLAF = this.themeManager.getTheme(); bottomBorderPanel.setBackground(cLAF.getMenubarBackgroundColor().darker()); bottomBorderPanel.setBorder(new EmptyBorder(0, 0, 0, 0)); bottomBorderPanel.setSize(getContentPane().getWidth(), 8); this.mainPanel.add(bottomBorderPanel, BorderLayout.SOUTH); } return this.mainPanel; } /** * @return the menu factory instance */ public MenuFactory getMenuFactory() { if (this.menuFactory == null) { menuFactory = new MenuFactory(); } return this.menuFactory; } /** * Main panel */ private JPanel mainPanel; /** * Menu factory instance */ private MenuFactory menuFactory; /** * GUI Theme manager */ @InjectedBean private ThemeManager themeManager; /** * Needed to display dialog boxes */ @InjectedBean private DialogFactory dialogFactory; /** * Needed to open files */ @InjectedBean private IFileChooserService fileChooserService; @ResourceBundleBean(key="app.name") private String applicationName; @ResourceBundleBean(key="app.icon") private Image applicationIcon; /** * All disgram workspaces */ private List<IWorkspace> workspaceList = new ArrayList<IWorkspace>(); // workaround for bug #4646747 in J2SE SDK 1.4.0 private static java.util.HashMap<Class<?>, BeanInfo> beanInfos; static { beanInfos = new java.util.HashMap<Class<?>, BeanInfo>(); Class<?>[] cls = new Class<?>[] { Point2D.Double.class, BentStyleChoiceList.class, ArrowheadChoiceList.class, LineStyleChoiceList.class, IGraph.class, AbstractNode.class, }; for (int i = 0; i < cls.length; i++) { try { beanInfos.put(cls[i], java.beans.Introspector.getBeanInfo(cls[i])); } catch (java.beans.IntrospectionException ex) { } } } }