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.Component; 024import java.awt.event.ActionEvent; 025import java.awt.event.KeyEvent; 026import java.io.File; 027import java.util.Properties; 028 029import javax.swing.AbstractAction; 030import javax.swing.ImageIcon; 031import javax.swing.JMenu; 032import javax.swing.JMenuItem; 033import javax.swing.JSeparator; 034 035import csheets.CleanSheets; 036import csheets.SpreadsheetAppEvent; 037import csheets.SpreadsheetAppListener; 038import csheets.ui.ctrl.OpenAction; 039import csheets.ui.ctrl.UIController; 040 041/** 042 * A menu for displaying recently opened files, and allowing the user to 043 * reopen them. 044 * @author Einar Pehrson 045 */ 046@SuppressWarnings("serial") 047public class ReopenMenu extends JMenu implements SpreadsheetAppListener { 048 049 /** The CleanSheets application */ 050 private CleanSheets app; 051 052 /** The maximum number of items in the menu */ 053 private int maximumItems = 10; 054 055 /** The application properties */ 056 private Properties props; 057 058 /** The number of menu items on the menu not denoting files */ 059 private int nonReopenItems; 060 061 /** The user interface controller */ 062 private UIController uiController; 063 064 /** 065 * Creates a reopen menu, and creates items using the given properties (if available). 066 * @param app the CleanSheets application 067 * @param uiController the user interface controller 068 */ 069 public ReopenMenu(CleanSheets app, UIController uiController) { 070 super("Reopen"); 071 072 // Stores members 073 this.app = app; 074 this.uiController = uiController; 075 this.props = app.getUserProperties(); 076 077 // Configures menu 078 app.addSpreadsheetAppListener(this); 079 setMnemonic(KeyEvent.VK_R); 080 setIcon(new ImageIcon(CleanSheets.class.getResource("res/img/reopen.gif"))); 081 082 if (props != null) { 083 // Loads recent files from properties and adds menu items 084 String filename; 085 for (int i = 0; (filename = props.getProperty("recentfile" + i)) != null; i++) { 086 File file = new File(filename); 087 if (file.exists()) addReopenItem(file, false); 088 } 089 } 090 091 // Adds removal items 092 addSeparator(); 093 add(new RemoveObsoleteAction()); 094 add(new RemoveAllAction()); 095 nonReopenItems = 3; 096 } 097 098 /** 099 * Adds an item for this file to the top of the reopen menu. 100 * @param file the filename of the file 101 * @return the item that was added 102 */ 103 public JMenuItem addReopenItem(File file) { 104 return addReopenItem(file, true); 105 } 106 107 /** 108 * Adds an item for this file to the top of the reopen menu. 109 * @param file the filename of the file 110 * @param updateProperties whether to update properties after adding the iten 111 * @return the item that was added 112 */ 113 private JMenuItem addReopenItem(File file, boolean updateProperties) { 114 // Removes any existing identical items 115 Component[] items = getMenuComponents(); 116 for (int i = 0; i < items.length; i++) { 117 // Breaks at separator 118 if (items[i] instanceof JSeparator) break; 119 120 // Removes item, if identical 121 JMenuItem item = (JMenuItem)items[i]; 122 if (file.getAbsolutePath().equals(item.getText())) 123 remove(item); 124 } 125 126 // Adds the item to the menu and trims the menu to the appropriate size 127 JMenuItem item = insert(new ReopenAction(app, uiController, file), 0); 128 while (getMenuComponentCount() - nonReopenItems > maximumItems) remove(maximumItems); 129 130 // Updates properties 131 if (updateProperties) 132 updateProperties(); 133 134 return item; 135 } 136 137 /** 138 * Removes all obsolete file items from the reopen menu, 139 * i.e. the items referring to files that don't exist. 140 */ 141 public void removeObsolete() { 142 Component[] items = getMenuComponents(); 143 for (int i = 0; i < items.length; i++) { 144 // Breaks at separator 145 if (items[i] instanceof JSeparator) break; 146 147 // Removes item, if obsolete 148 JMenuItem item = (JMenuItem)items[i]; 149 if (!new File(item.getText()).exists()) 150 remove(item); 151 } 152 153 // Updates properties 154 updateProperties(); 155 } 156 157 /** 158 * Removes all file items from the reopen menu, 159 */ 160 public void removeAll() { 161 Component[] items = getMenuComponents(); 162 for (int i = 0; i < items.length; i++) { 163 // Breaks at separator 164 if (items[i] instanceof JSeparator) break; 165 166 // Removes item 167 remove(items[i]); 168 } 169 170 // Updates properties 171 updateProperties(); 172 } 173 174 /** 175 * Sets the maximum number of reopen items in the menu. 176 * @param items the number of reopen items in the menu 177 */ 178 public void setMaximumItems(int items) { 179 this.maximumItems = items; 180 } 181 182 /** 183 * Updates the recent files in the application properties. 184 */ 185 private void updateProperties() { 186 if (props != null) { 187 // Stores the current recent files 188 int i = 0; 189 for (int n = getMenuComponentCount() - nonReopenItems; i < n; i++) 190 props.setProperty("recentfile" + (n - i - 1), 191 ((JMenuItem)getMenuComponent(i)).getText()); 192 193 for (; (props.getProperty("recentfile" + i)) != null; i++) 194 props.remove("recentfile" + i); 195 } 196 } 197 198 public void workbookCreated(SpreadsheetAppEvent event) {} 199 200 public void workbookLoaded(SpreadsheetAppEvent event) { 201 addReopenItem(event.getFile(), true); 202 } 203 204 public void workbookUnloaded(SpreadsheetAppEvent event) {} 205 206 public void workbookSaved(SpreadsheetAppEvent event) { 207 addReopenItem(event.getFile(), true); 208 } 209 210 /** 211 * An action for reopening a spreadsheet. 212 * @author Einar Pehrson 213 */ 214 @SuppressWarnings("serial") 215 protected static class ReopenAction extends OpenAction { 216 217 /** The file to open */ 218 private File file; 219 220 /** 221 * Creates a new reopen action. 222 * @param app the CleanSheets application 223 * @param uiController the user interface controller 224 * @param file the file to open 225 */ 226 public ReopenAction(CleanSheets app, UIController uiController, 227 File file) { 228 super(app, uiController, null); 229 this.file = file; 230 setEnabled(true); 231 putValue(NAME, file.getAbsolutePath()); 232 putValue(ACTION_COMMAND_KEY, file.getAbsolutePath()); 233 } 234 235 protected void defineProperties() { 236 putValue(SHORT_DESCRIPTION, null); 237 putValue(SMALL_ICON, null); 238 } 239 240 public File getFile() { 241 return file; 242 } 243 } 244 245 /** 246 * An action for removing the obsolete items from the menu. 247 */ 248 @SuppressWarnings("serial") 249 protected class RemoveObsoleteAction extends AbstractAction { 250 251 /** 252 * Creates a new remove obsolete action. 253 */ 254 public RemoveObsoleteAction() { 255 // Configures action 256 String name = "Remove obsolete"; 257 putValue(NAME, name); 258 putValue(SHORT_DESCRIPTION, name); 259 putValue(ACTION_COMMAND_KEY, name); 260 putValue(MNEMONIC_KEY, KeyEvent.VK_O); 261 } 262 263 public void actionPerformed(ActionEvent e) { 264 removeObsolete(); 265 } 266 } 267 268 /** 269 * An action for removing all items from the menu. 270 */ 271 @SuppressWarnings("serial") 272 protected class RemoveAllAction extends AbstractAction { 273 274 /** 275 * Creates a new remove all action. 276 */ 277 public RemoveAllAction() { 278 // Configures action 279 String name = "Remove all"; 280 putValue(NAME, name); 281 putValue(SHORT_DESCRIPTION, name); 282 putValue(ACTION_COMMAND_KEY, name); 283 putValue(MNEMONIC_KEY, KeyEvent.VK_R); 284 } 285 286 public void actionPerformed(ActionEvent e) { 287 removeAll(); 288 } 289 } 290}