001    /*
002     * Copyright (c) 2005 Einar Pehrson <einar@pehrson.nu>.
003     *
004     * This file is part of
005     * CleanSheets - a spreadsheet application for the Java platform.
006     *
007     * CleanSheets is free software; you can redistribute it and/or modify
008     * it under the terms of the GNU General Public License as published by
009     * the Free Software Foundation; either version 2 of the License, or
010     * (at your option) any later version.
011     *
012     * CleanSheets is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015     * GNU General Public License for more details.
016     *
017     * You should have received a copy of the GNU General Public License
018     * along with CleanSheets; if not, write to the Free Software
019     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
020     */
021    package csheets.ui;
022    
023    import java.awt.BorderLayout;
024    import java.awt.Container;
025    import java.awt.Dimension;
026    import java.awt.EventQueue;
027    import java.awt.FlowLayout;
028    import java.awt.Font;
029    import java.awt.Toolkit;
030    
031    import javax.swing.JComponent;
032    import javax.swing.JFrame;
033    import javax.swing.JPanel;
034    import javax.swing.JSplitPane;
035    import javax.swing.JTabbedPane;
036    import javax.swing.JToolBar;
037    
038    import csheets.CleanSheets;
039    import csheets.core.Workbook;
040    import csheets.ui.ctrl.AboutAction;
041    import csheets.ui.ctrl.ActionManager;
042    import csheets.ui.ctrl.AddSpreadsheetAction;
043    import csheets.ui.ctrl.ClearAction;
044    import csheets.ui.ctrl.CloseAction;
045    import csheets.ui.ctrl.CloseAllAction;
046    import csheets.ui.ctrl.CopyAction;
047    import csheets.ui.ctrl.CutAction;
048    import csheets.ui.ctrl.ExitAction;
049    import csheets.ui.ctrl.HelpAction;
050    import csheets.ui.ctrl.InsertColumnAction;
051    import csheets.ui.ctrl.InsertRowAction;
052    import csheets.ui.ctrl.LicenseAction;
053    import csheets.ui.ctrl.NewAction;
054    import csheets.ui.ctrl.OpenAction;
055    import csheets.ui.ctrl.PasteAction;
056    import csheets.ui.ctrl.PreferencesAction;
057    import csheets.ui.ctrl.PrintAction;
058    import csheets.ui.ctrl.RedoAction;
059    import csheets.ui.ctrl.RemoveColumnAction;
060    import csheets.ui.ctrl.RemoveRowAction;
061    import csheets.ui.ctrl.RemoveSpreadsheetAction;
062    import csheets.ui.ctrl.RenameSpreadsheetAction;
063    import csheets.ui.ctrl.SaveAction;
064    import csheets.ui.ctrl.SaveAsAction;
065    import csheets.ui.ctrl.SearchAction;
066    import csheets.ui.ctrl.SelectAllAction;
067    import csheets.ui.ctrl.SelectionEvent;
068    import csheets.ui.ctrl.SelectionListener;
069    import csheets.ui.ctrl.SortAction;
070    import csheets.ui.ctrl.UIController;
071    import csheets.ui.ctrl.UndoAction;
072    import csheets.ui.ext.UIExtension;
073    import csheets.ui.sheet.AddressBox;
074    import csheets.ui.sheet.CellEditor;
075    import csheets.ui.sheet.WorkbookPane;
076    
077    /**
078     * The main frame of the GUI.
079     * @author Einar Pehrson
080     */
081    @SuppressWarnings("serial")
082    public class Frame extends JFrame implements SelectionListener {
083    
084            /** The base of the window title */
085            public static final String TITLE = "CleanSheets";
086    
087            /** The CleanSheets application */
088            private CleanSheets app;
089    
090            /**
091             * Creates a new frame.
092             * @param app the CleanSheets application
093             */
094            public Frame(CleanSheets app) {
095                    // Stores members and creates controllers
096                    this.app = app;
097                    UIController uiController = new UIController(app);
098    
099                    // Creates action manager
100                    FileChooser chooser = null;
101                    try {
102                            chooser = new FileChooser(this, app.getUserProperties());
103                    } catch (java.security.AccessControlException ace) {}
104                    ActionManager actionManager = new ActionManager(app, uiController, chooser);
105    
106                    // Registers file actions
107                    actionManager.registerAction("new", new NewAction(app));
108                    actionManager.registerAction("open", new OpenAction(app, uiController, chooser));
109                    actionManager.registerAction("close", new CloseAction(app, uiController, chooser));
110                    actionManager.registerAction("closeall", new CloseAllAction(app, uiController, chooser));
111                    actionManager.registerAction("save", new SaveAction(app, uiController, chooser));
112                    actionManager.registerAction("saveas", new SaveAsAction(app, uiController, chooser));
113                    actionManager.registerAction("exit", new ExitAction(app, uiController, chooser));
114                    actionManager.registerAction("print", new PrintAction());
115    
116                    // Registers edit actions
117                    actionManager.registerAction("undo", new UndoAction());
118                    actionManager.registerAction("redo", new RedoAction());
119                    actionManager.registerAction("cut", new CutAction());
120                    actionManager.registerAction("copy", new CopyAction());
121                    actionManager.registerAction("paste", new PasteAction());
122                    actionManager.registerAction("clear", new ClearAction());
123                    actionManager.registerAction("selectall", new SelectAllAction());
124                    actionManager.registerAction("sort", new SortAction());
125                    actionManager.registerAction("search", new SearchAction());
126                    actionManager.registerAction("prefs", new PreferencesAction());
127    
128                    // Registers spreadsheet actions
129                    actionManager.registerAction("addsheet", new AddSpreadsheetAction(uiController));
130                    actionManager.registerAction("removesheet", new RemoveSpreadsheetAction(uiController));
131                    actionManager.registerAction("renamesheet", new RenameSpreadsheetAction(uiController));
132                    actionManager.registerAction("insertcolumn", new InsertColumnAction());
133                    actionManager.registerAction("removecolumn", new RemoveColumnAction());
134                    actionManager.registerAction("insertrow", new InsertRowAction());
135                    actionManager.registerAction("removerow", new RemoveRowAction());
136    
137                    // Registers help actions
138                    actionManager.registerAction("help", new HelpAction());
139                    actionManager.registerAction("license", new LicenseAction());
140                    actionManager.registerAction("about", new AboutAction());
141    
142                    // Creates spreadsheet components
143                    WorkbookPane workbookPane = new WorkbookPane(uiController, actionManager);
144                    CellEditor cellEditor = new CellEditor(uiController);
145                    AddressBox addressBox = new AddressBox(uiController);
146    
147                    // Creates tool bars
148                    JPanel toolBarPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
149                    toolBarPanel.add(new StandardToolBar(actionManager));
150                    for (UIExtension extension : uiController.getExtensions()) {
151                            JToolBar extToolBar = extension.getToolBar();
152                            if (extToolBar != null)
153                                    toolBarPanel.add(extToolBar);
154                    }
155    
156                    // Creates and lays out top panel
157                    JPanel cellPanel = new JPanel(new BorderLayout());
158                    cellPanel.add(addressBox, BorderLayout.WEST);
159                    cellPanel.add(cellEditor, BorderLayout.CENTER);
160                    JPanel topPanel = new JPanel(new BorderLayout());
161                    topPanel.add(toolBarPanel, BorderLayout.NORTH);
162                    topPanel.add(cellPanel, BorderLayout.SOUTH);
163    
164                    // Creates and lays out side bar components
165                    JTabbedPane sideBar = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT);
166                    sideBar.setPreferredSize(new Dimension(170, 480));
167                    Font font = sideBar.getFont();
168                    sideBar.setFont(new Font(font.getFamily(), Font.PLAIN, font.getSize() - 1));
169                    for (UIExtension extension : uiController.getExtensions()) {
170                            JComponent extBar = extension.getSideBar();
171                            if (extBar != null)
172                                    sideBar.insertTab(extension.getExtension().getName(), extension.getIcon(),
173                                            extBar, null, sideBar.getTabCount());
174                    }
175    
176                    // Lays out split pane
177                    workbookPane.setMinimumSize(new Dimension(300, 100));
178                    sideBar.setMinimumSize(new Dimension(140, 100));
179                    JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
180                            workbookPane, sideBar);
181                    splitPane.setOneTouchExpandable(true);
182                    splitPane.setResizeWeight(1.0);
183    
184                    // Configures layout and adds panels
185                    Container pane = getContentPane();
186                    pane.setPreferredSize(new Dimension(640, 480));
187                    pane.setLayout(new BorderLayout());
188                    pane.add(topPanel, BorderLayout.NORTH);
189                    pane.add(splitPane, BorderLayout.CENTER);
190                    setJMenuBar(new MenuBar(app, actionManager, uiController));
191    
192                    // Registers listeners
193                    uiController.addSelectionListener(this);
194                    addWindowListener(new WindowClosingHandler(this,
195                            actionManager.getAction("exit")));
196    
197                    // Configures appearance
198                    setTitle(TITLE);
199                    setIconImage(Toolkit.getDefaultToolkit().getImage(
200                            CleanSheets.class.getResource("res/img/sheet.gif")));
201                    pack();
202                    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
203                    setLocationRelativeTo(null);
204            }
205    
206            /**
207             * Updates the title of the window when a new active workbook is selected.
208             * @param event the selection event that was fired
209             */
210            public void selectionChanged(SelectionEvent event) {
211                    Workbook workbook = event.getWorkbook();
212                    if (workbook != null) {
213                            setVisible(true);
214                            if (app.isWorkbookStored(workbook))
215                                    setTitle(TITLE + " - " + app.getFile(workbook).getName());
216                            else
217                                    setTitle(TITLE + " - Untitled");
218                    } else
219                            setTitle(TITLE);
220            }
221    
222            /**
223             * A utility for creating a Frame on the AWT event dispatching thread.
224             * @author Einar Pehrson
225             */
226            public static class Creator implements Runnable {
227    
228                    /** The component that was created */
229                    private Frame frame;
230    
231                    /** The CleanSheets application */
232                    private CleanSheets app;
233    
234                    /**
235                     * Creates a new frame creator.
236                     * @param app the CleanSheets application
237                     */
238                    public Creator(CleanSheets app) {
239                            this.app = app;
240                    }
241    
242                    /**
243                     * Creates a component on the AWT event dispatching thread.
244                     * @return the component that was created
245                     */
246                    public Frame createAndWait() {
247                            try {
248                                    EventQueue.invokeAndWait(this);
249                            } catch (InterruptedException e) {
250                                    return null;
251                            } catch (java.lang.reflect.InvocationTargetException e) {
252                                    e.printStackTrace();
253                                    return null;
254                            }
255                            return frame;
256                    }
257    
258                    /**
259                     * Asks the event queue to create a component at a later time.
260                     * (Included for conformity.)
261                     */
262                    public void createLater() {
263                            EventQueue.invokeLater(this);
264                    }
265    
266                    public void run() {
267                            frame = new Frame(app);
268                    }
269            }
270    }