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 */
021package csheets.ui;
022
023import java.awt.BorderLayout;
024import java.awt.Container;
025import java.awt.Dimension;
026import java.awt.EventQueue;
027import java.awt.FlowLayout;
028import java.awt.Font;
029import java.awt.Toolkit;
030
031import javax.swing.JComponent;
032import javax.swing.JFrame;
033import javax.swing.JPanel;
034import javax.swing.JSplitPane;
035import javax.swing.JTabbedPane;
036import javax.swing.JToolBar;
037
038import csheets.CleanSheets;
039import csheets.core.Workbook;
040import csheets.ui.ctrl.AboutAction;
041import csheets.ui.ctrl.ActionManager;
042import csheets.ui.ctrl.AddSpreadsheetAction;
043import csheets.ui.ctrl.ClearAction;
044import csheets.ui.ctrl.CloseAction;
045import csheets.ui.ctrl.CloseAllAction;
046import csheets.ui.ctrl.CopyAction;
047import csheets.ui.ctrl.CutAction;
048import csheets.ui.ctrl.ExitAction;
049import csheets.ui.ctrl.HelpAction;
050import csheets.ui.ctrl.InsertColumnAction;
051import csheets.ui.ctrl.InsertRowAction;
052import csheets.ui.ctrl.LicenseAction;
053import csheets.ui.ctrl.NewAction;
054import csheets.ui.ctrl.OpenAction;
055import csheets.ui.ctrl.PasteAction;
056import csheets.ui.ctrl.PreferencesAction;
057import csheets.ui.ctrl.PrintAction;
058import csheets.ui.ctrl.RedoAction;
059import csheets.ui.ctrl.RemoveColumnAction;
060import csheets.ui.ctrl.RemoveRowAction;
061import csheets.ui.ctrl.RemoveSpreadsheetAction;
062import csheets.ui.ctrl.RenameSpreadsheetAction;
063import csheets.ui.ctrl.SaveAction;
064import csheets.ui.ctrl.SaveAsAction;
065import csheets.ui.ctrl.SearchAction;
066import csheets.ui.ctrl.SelectAllAction;
067import csheets.ui.ctrl.SelectionEvent;
068import csheets.ui.ctrl.SelectionListener;
069import csheets.ui.ctrl.SortAction;
070import csheets.ui.ctrl.UIController;
071import csheets.ui.ctrl.UndoAction;
072import csheets.ui.ext.UIExtension;
073import csheets.ui.sheet.AddressBox;
074import csheets.ui.sheet.CellEditor;
075import csheets.ui.sheet.WorkbookPane;
076
077/**
078 * The main frame of the GUI.
079 * @author Einar Pehrson
080 */
081@SuppressWarnings("serial")
082public 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}