001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.drjava.ui;
038:
039: import javax.swing.*;
040: import java.awt.event.*;
041: import java.io.File;
042: import java.io.IOException;
043: import java.util.Vector;
044:
045: import edu.rice.cs.drjava.DrJava;
046: import edu.rice.cs.drjava.model.*;
047: import edu.rice.cs.drjava.config.*;
048:
049: import edu.rice.cs.util.FileOpenSelector;
050:
051: /**
052: * Manages a list of the most recently used files to be displayed
053: * in the File menu.
054: * @version $Id: RecentFileManager.java 4255 2007-08-28 19:17:37Z mgricken $
055: */
056: public class RecentFileManager implements OptionConstants {
057: /** Position in the file menu for the next insert. */
058: protected int _pos;
059:
060: /** All of the recently used files in the list, in order. */
061: protected Vector<File> _recentFiles;
062:
063: /** Menu items corresponding to each file in _recentFiles. */
064: protected Vector<JMenuItem> _recentMenuItems;
065:
066: /** The maximum number of files to display in the list. */
067: protected int MAX = DrJava.getConfig().getSetting(
068: RECENT_FILES_MAX_SIZE).intValue();
069:
070: /** The File menu containing the entries. */
071: protected JMenu _fileMenu;
072:
073: /** The OptionConstant that should be used to retrieve the list of recent files. */
074: protected VectorOption<File> _settingConfigConstant;
075:
076: /** An action that will be invoked when the file is clicked. */
077: protected RecentFileAction _recentFileAction;
078:
079: /** Creates a new RecentFileManager.
080: * @param pos Position in the file menu
081: * @param fileMenu File menu to add the entry to
082: */
083: public RecentFileManager(int pos, JMenu fileMenu,
084: RecentFileAction action,
085: VectorOption<File> settingConfigConstant) {
086: _pos = pos;
087: _fileMenu = fileMenu;
088: _recentFileAction = action;
089: _recentFiles = new Vector<File>();
090: _recentMenuItems = new Vector<JMenuItem>();
091: _settingConfigConstant = settingConfigConstant;
092:
093: // Add each of the files stored in the config
094: Vector<File> files = DrJava.getConfig().getSetting(
095: _settingConfigConstant);
096:
097: for (int i = files.size() - 1; i >= 0; i--) {
098: File f = files.get(i);
099: if (f.exists())
100: updateOpenFiles(f);
101: }
102: }
103:
104: /** Returns the list of recently used files, in order. */
105: public Vector<File> getFileVector() {
106: return _recentFiles;
107: }
108:
109: /** Changes the maximum number of files to display in the list.
110: * @param newMax The new maximum number of files to display
111: */
112: public void updateMax(int newMax) {
113: MAX = newMax;
114: }
115:
116: /** Saves the current list of files to the config object. */
117: public void saveRecentFiles() {
118: DrJava.getConfig().setSetting(_settingConfigConstant,
119: _recentFiles);
120: }
121:
122: /** Updates the list after the given file has been opened. */
123: public void updateOpenFiles(final File file) {
124:
125: if (_recentMenuItems.size() == 0) {
126: _fileMenu.insertSeparator(_pos); //one at top
127: _pos++;
128: }
129:
130: final FileOpenSelector recentSelector = new FileOpenSelector() {
131: public File[] getFiles() {
132: return new File[] { file };
133: }
134: };
135:
136: JMenuItem newItem = new JMenuItem("");
137: newItem.addActionListener(new AbstractAction("Open "
138: + file.getName()) {
139: public void actionPerformed(ActionEvent ae) {
140: if (_recentFileAction != null) {
141: _recentFileAction.actionPerformed(recentSelector);
142: }
143: }
144: });
145: try {
146: newItem.setToolTipText(file.getCanonicalPath());
147: } catch (IOException e) {
148: // don't worry about it at this point
149: }
150: removeIfInList(file);
151: _recentMenuItems.add(0, newItem);
152: _recentFiles.add(0, file);
153: numberItems();
154: _fileMenu.insert(newItem, _pos);
155: }
156:
157: /** Removes the given file from the list if it is already there.
158: * Only removes the first occurrence of the file, since each
159: * entry should be unique (based on canonical path).
160: */
161: public void removeIfInList(File file) {
162: // Use canonical path if possible
163: File canonical = null;
164: try {
165: canonical = file.getCanonicalFile();
166: } catch (IOException ioe) {
167: // Oh well, compare against the file as is
168: }
169:
170: for (int i = 0; i < _recentFiles.size(); i++) {
171: File currFile = _recentFiles.get(i);
172: boolean match;
173: if (canonical != null) {
174: try {
175: match = currFile.getCanonicalFile().equals(
176: canonical);
177: } catch (IOException ioe) {
178: // Oh well, compare the files themselves
179: match = currFile.equals(file);
180: }
181: } else {
182: // (couldn't find canonical for file; compare as is)
183: match = currFile.equals(file);
184: }
185:
186: if (match) {
187: _recentFiles.remove(i);
188: JMenuItem menuItem = _recentMenuItems.get(i);
189: _fileMenu.remove(menuItem);
190: _recentMenuItems.remove(i);
191: break;
192: }
193: }
194: }
195:
196: /**
197: * Trims the recent file list to the configured size and numbers the
198: * remaining files according to their position in the list
199: */
200: public void numberItems() {
201: int delPos = _recentMenuItems.size();
202: boolean wasEmpty = (delPos == 0);
203: while (delPos > MAX) {
204: JMenuItem delItem = _recentMenuItems.get(delPos - 1);
205: _recentMenuItems.remove(delPos - 1);
206: _recentFiles.remove(delPos - 1);
207: _fileMenu.remove(delItem);
208:
209: delPos = _recentMenuItems.size();
210: }
211: JMenuItem currItem;
212: for (int i = 0; i < _recentMenuItems.size(); i++) {
213: currItem = _recentMenuItems.get(i);
214: currItem.setText((i + 1) + ". "
215: + _recentFiles.get(i).getName());
216: }
217: // remove the separator
218: if (MAX == 0 && !wasEmpty) {
219: _fileMenu.remove(--_pos);
220: }
221: }
222:
223: /**
224: * This interface is to be implemented and passed to the manager
225: * upon creation. This action specifies what is performed when the
226: * user selects a file from the list
227: */
228: public interface RecentFileAction {
229: public void actionPerformed(FileOpenSelector selector);
230: }
231: }
|