Source code: com/simscomputing/util/MruMenuManager.java
1 package com.simscomputing.util;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.JMenu;
6 import javax.swing.JMenuItem;
7 import java.util.ArrayList;
8 import java.util.Iterator;
9 import java.util.List;
10 import java.util.Map;
11
12 /**
13 Works with a JMenu to manipulate most recently used items. This works to
14 achieve the effect found in many popular software products: keeping track
15 of the items that a user has chosen most recently for easy retrieval.
16
17 When constructed with an ApplicationProperties object, MruMenuManager will
18 load and store these mru items for persistence between client sessions.
19
20 @see com.simscomputing.util.ApplicationProperties
21
22 @author Dave Lamy (daveandjeri@stubbydog.com)
23 */
24 public class MruMenuManager implements ActionListener {
25 private int startIndex;
26 private JMenu mruMenu;
27 private int mruSize;
28 private List mruItems;
29 private List mruListeners;
30 private ApplicationProperties properties;
31 private String propertyPrefix;
32
33 /**
34 Constructs a new MruMenuManager with no persistence capability
35 */
36 public MruMenuManager(JMenu mruMenu, int startMenuIndex, int mruSize) {
37 this(mruMenu, startMenuIndex, mruSize, null, null);
38 } // constructor
39
40 /**
41 Constructs a new MruMenuManager with the specified parameters.
42 This constructor will go ahead and load the menu items present
43 in the ApplicationProperties object. If no ApplicationProperties
44 object is passed in, the load operation will be skipped.
45
46 @param mruMenu - the JMenu to manipulate with MRU items
47 @param startMenuIndex - the root index of the JMenu where this object
48 should start adding and removing MRU items
49 @param mruSize - the maximum number of MRU item entries to track. If
50 this size is reached and a new MRU item is added, the last MRU
51 item in the list will be removed to make room for the new item.
52 @param appProperties - The ApplicationProperties instance that works as
53 the persistence store of MRU items.
54 @param propertyPrefix - The String prefix of MRU items in the
55 ApplicationProperties object.
56 <p>
57 Example: if there are 2 MRU items in the ApplicationProperties
58 instance:
59 <p>
60 <code>
61 com.simscomputing.testbed.mru.0<br>
62 com.simscomputing.testbed.mru.1
63 </code>
64 <p>
65 Then the propertyPrefix would be
66 "<code>com.simscomputing.testbed.mru</code>".
67 */
68 public MruMenuManager(JMenu mruMenu, int startMenuIndex, int mruSize,
69 ApplicationProperties appProperties, String propertyPrefix) {
70 this.mruMenu = mruMenu;
71 startIndex = startMenuIndex;
72 this.mruSize = mruSize;
73 mruItems = new ArrayList(mruSize + 1);
74 this.properties = appProperties;
75 this.propertyPrefix = propertyPrefix;
76 mruListeners = new ArrayList();
77 loadMruItems();
78 }
79
80 /**
81 Adds a new mru item to the mru list. If the item to add
82 is already being displayed, it will not be repeated. If, by
83 adding this item, the mru size defined in the constructor will
84 be exceeded, this method will remove the last item in the list
85 to make room. The new item will be added to the top of the list.
86 The menu refresh will happen immediately.
87
88 @param itemToAdd - the text of the JMenuItem to add.
89 */
90 public void addMruItem(String itemToAdd) {
91 addMruItem(itemToAdd, true);
92 }
93
94 /**
95 Adds a new mru item to the mru list. If the item to add
96 is already being displayed, it will not be repeated. If, by
97 adding this item, the mru size defined in the constructor will
98 be exceeded, this method will remove the last item in the list
99 to make room. The new item will be added to the top of the list.
100 The JMenu will only be refreshed if <code>refreshImmediately</code>
101 has been set to <code>true</code>.
102
103 @param itemToAdd - the text of the JMenuItem to add.
104 @param refreshImmediately - whether or not to refesh the JMenu as
105 part of this method.
106 */
107 public void addMruItem(String itemToAdd, boolean refreshImmediately) {
108 Iterator it = mruItems.iterator();
109 while (it.hasNext()) {
110 JMenuItem menuItem = (JMenuItem)it.next();
111 if (menuItem.getText().equals(itemToAdd)) {
112 return;
113 } // if
114 } // while
115 int oldSize = mruItems.size();
116 JMenuItem newItem = new JMenuItem(itemToAdd);
117 newItem.addActionListener(this);
118 if (mruItems.size() == 0) {
119 mruItems.add(newItem);
120 } // if
121 else {
122 for (int i = mruItems.size() - 1; i >= 0; i--) {
123 if (i + 1 >= mruSize) continue;
124 if (i + 1 == mruItems.size()) {
125 mruItems.add(mruItems.get(i));
126 } // if
127 else {
128 mruItems.set(i + 1, mruItems.get(i));
129 } // else
130 } // for
131 mruItems.set(0, newItem);
132 } // else
133 if (refreshImmediately) {
134 resetMenu(oldSize);
135 } // if
136 }
137
138 /**
139 Adds an ActionListener to a private list. When ActionEvents
140 are received from mru JMenuItems, all ActionListeners in
141 this list will be notified.
142 */
143 public void addActionListener(ActionListener listener) {
144 mruListeners.add(listener);
145 }
146
147 /**
148 Removes the specified ActionListener from the list.
149 */
150 public void removeActionListener(ActionListener listener) {
151 mruListeners.remove(listener);
152 }
153
154 // Resets the JMenu to whatever is now in the mruItems list.
155 private void resetMenu(int oldSize) {
156 // first, remove all items from the JMenu
157 for (int i=startIndex; i < (startIndex + oldSize); i++) {
158 mruMenu.remove(startIndex);
159 } // for
160 // Now add all current items back in
161 for (int i=0; i < mruItems.size(); i++) {
162 JMenuItem item = (JMenuItem)mruItems.get(i);
163 mruMenu.insert(item, startIndex + i);
164 } // for
165 } // resetMenu
166
167 /**
168 Stores the mru items in the ApplicationProperties object. Note
169 that this will not physically persist the items. The ApplicationProperties
170 object will physically persist the data to disk when the
171 <code>storeProperties</code> method is called on it.
172
173 If no ApplicationProperties object was set during construction
174 this method will not do anything.
175 */
176 public void storeMruItems() {
177 if (properties == null) return;
178 // First get rid of all current mru items
179 Map currentItemMap = properties.getPropertiesLike(propertyPrefix);
180 Iterator keyIt = currentItemMap.keySet().iterator();
181 while (keyIt.hasNext()) {
182 properties.removeProperty((String)keyIt.next());
183 } // while
184
185 // Now add all items in
186 for (int i=0; i < mruItems.size(); i++) {
187 JMenuItem menuItem = (JMenuItem)mruItems.get(i);
188 String item = menuItem.getText();
189 String propertyName = propertyPrefix + "." + new Integer(i).toString();
190 properties.setProperty(propertyName, item);
191 } // for
192 } // storeMruItems
193
194 /**
195 Loads mru items from the ApplicationProperties object. This
196 method is called during construction of the MruMenuManager object.
197 If no ApplicationProperties object was passed in during construction,
198 this method will not do anything.
199 */
200 public void loadMruItems() {
201 if (properties == null) return;
202 Map itemMap = properties.getPropertiesLike(propertyPrefix);
203 Iterator keyIt = itemMap.keySet().iterator();
204 while (keyIt.hasNext()) {
205 String propertyName = (String)keyIt.next();
206 int dotIndex = propertyName.lastIndexOf(".");
207 String idxString = propertyName.substring(dotIndex + 1);
208 int idx = new Integer(idxString).intValue();
209 addMruItem(itemMap.get(propertyName).toString(), false);
210 } // while
211 resetMenu(0);
212 } // loadMruItems
213
214 /**
215 Implementation of the ActionListener interface. The MruMenuManager
216 will catch events from all mru items it creates and subsequently
217 broadcast them to all ActionListeners attached to it.
218 */
219 public void actionPerformed(ActionEvent e) {
220 Iterator listenerIt = mruListeners.iterator();
221 while (listenerIt.hasNext()) {
222 ActionListener listener = (ActionListener)listenerIt.next();
223 listener.actionPerformed(e);
224 } // while
225 } // mruMenuItemSelected
226
227
228
229
230
231
232
233
234 }