]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/MenuManager.java
8229aa322fb58458db950de8eabdb27f9e16ddeb
[GpsPrune.git] / tim / prune / gui / MenuManager.java
1 package tim.prune.gui;
2
3 import java.awt.Toolkit;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.KeyEvent;
7
8 import javax.swing.JButton;
9 import javax.swing.JCheckBoxMenuItem;
10 import javax.swing.JMenu;
11 import javax.swing.JMenuBar;
12 import javax.swing.JMenuItem;
13 import javax.swing.JToolBar;
14 import javax.swing.KeyStroke;
15
16 import tim.prune.App;
17 import tim.prune.DataSubscriber;
18 import tim.prune.FunctionLibrary;
19 import tim.prune.GenericFunction;
20 import tim.prune.I18nManager;
21 import tim.prune.UpdateMessageBroker;
22 import tim.prune.config.Config;
23 import tim.prune.data.AudioClip;
24 import tim.prune.data.Photo;
25 import tim.prune.data.RecentFile;
26 import tim.prune.data.RecentFileList;
27 import tim.prune.data.Selection;
28 import tim.prune.data.Track;
29 import tim.prune.data.TrackInfo;
30 import tim.prune.function.RearrangeWaypointsFunction.Rearrange;
31 import tim.prune.function.browser.UrlGenerator;
32
33 /**
34  * Class to manage the menu bar and tool bar,
35  * including enabling and disabling the items
36  */
37 public class MenuManager implements DataSubscriber
38 {
39         private App _app = null;
40         private Track _track = null;
41         private Selection _selection = null;
42
43         // Menu items which need enabling/disabling
44         private JMenuItem _sendGpsItem = null;
45         private JMenuItem _saveItem = null;
46         private JMenuItem _exportKmlItem = null;
47         private JMenuItem _exportGpxItem = null;
48         private JMenuItem _exportPovItem = null;
49         private JMenuItem _exportSvgItem = null;
50         private JMenu     _recentFileMenu = null;
51         private JMenuItem _undoItem = null;
52         private JMenuItem _clearUndoItem = null;
53         private JMenuItem _editPointItem = null;
54         private JMenuItem _editWaypointNameItem = null;
55         private JMenuItem _deletePointItem = null;
56         private JMenuItem _deleteRangeItem = null;
57         private JMenuItem _compressItem = null;
58         private JMenuItem _deleteMarkedPointsItem = null;
59         private JMenuItem _interpolateItem = null;
60         private JMenuItem _averageItem = null;
61         private JMenuItem _selectAllItem = null;
62         private JMenuItem _selectNoneItem = null;
63         private JMenuItem _selectStartItem = null;
64         private JMenuItem _selectEndItem = null;
65         private JMenuItem _findWaypointItem = null;
66         private JMenuItem _duplicatePointItem = null;
67         private JMenuItem _reverseItem = null;
68         private JMenuItem _addTimeOffsetItem = null;
69         private JMenuItem _addAltitudeOffsetItem = null;
70         private JMenuItem _mergeSegmentsItem = null;
71         private JMenu     _rearrangeMenu = null;
72         private JMenuItem _cutAndMoveItem = null;
73         private JMenuItem _convertNamesToTimesItem = null;
74         private JMenuItem _deleteFieldValuesItem = null;
75         private JCheckBoxMenuItem _mapCheckbox = null;
76         private JMenuItem _show3dItem = null;
77         private JMenu     _browserMapMenu = null;
78         private JMenuItem _chartItem = null;
79         private JMenuItem _getGpsiesItem = null;
80         private JMenuItem _uploadGpsiesItem = null;
81         private JMenuItem _lookupSrtmItem = null;
82         private JMenuItem _lookupWikipediaItem = null;
83         private JMenuItem _downloadOsmItem = null;
84         private JMenuItem _distanceItem = null;
85         private JMenuItem _fullRangeDetailsItem = null;
86         private JMenuItem _saveExifItem = null;
87         private JMenuItem _photoPopupItem = null;
88         private JMenuItem _selectNoPhotoItem = null;
89         private JMenuItem _connectPhotoItem = null;
90         private JMenuItem _removePhotoItem = null;
91         private JMenuItem _disconnectPhotoItem = null;
92         private JMenuItem _correlatePhotosItem = null;
93         private JMenuItem _rearrangePhotosItem = null;
94         private JMenuItem _rotatePhotoLeft = null;
95         private JMenuItem _rotatePhotoRight = null;
96         private JMenuItem _ignoreExifThumb = null;
97         private JMenuItem _connectAudioItem = null;
98         private JMenuItem _disconnectAudioItem = null;
99         private JMenuItem _removeAudioItem = null;
100         private JMenuItem _correlateAudiosItem = null;
101         private JMenuItem _selectNoAudioItem = null;
102         private JCheckBoxMenuItem _onlineCheckbox = null;
103         private JCheckBoxMenuItem _autosaveSettingsCheckbox = null;
104
105         // ActionListeners for reuse by menu and toolbar
106         private ActionListener _openFileAction = null;
107         private ActionListener _addPhotoAction = null;
108         private ActionListener _saveAction = null;
109         private ActionListener _undoAction = null;
110         private ActionListener _editPointAction = null;
111         private ActionListener _deletePointAction = null;
112         private ActionListener _deleteRangeAction = null;
113         private ActionListener _selectStartAction = null;
114         private ActionListener _selectEndAction = null;
115
116         // Toolbar buttons which need enabling/disabling
117         private JButton _saveButton = null;
118         private JButton _undoButton = null;
119         private JButton _editPointButton = null;
120         private JButton _deletePointButton = null;
121         private JButton _deleteRangeButton = null;
122         private JButton _selectStartButton = null;
123         private JButton _selectEndButton = null;
124         private JButton _connectButton = null;
125
126         /** Array of key events */
127         private static final int[] KEY_EVENTS = {
128                 KeyEvent.VK_A, KeyEvent.VK_B, KeyEvent.VK_C, KeyEvent.VK_D, KeyEvent.VK_E,
129                 KeyEvent.VK_F, KeyEvent.VK_G, KeyEvent.VK_H, KeyEvent.VK_I, KeyEvent.VK_J,
130                 KeyEvent.VK_K, KeyEvent.VK_L, KeyEvent.VK_M, KeyEvent.VK_N, KeyEvent.VK_O,
131                 KeyEvent.VK_P, KeyEvent.VK_Q, KeyEvent.VK_R, KeyEvent.VK_S, KeyEvent.VK_T,
132                 KeyEvent.VK_U, KeyEvent.VK_V, KeyEvent.VK_W, KeyEvent.VK_X, KeyEvent.VK_Y, KeyEvent.VK_Z};
133
134
135         /**
136          * Constructor
137          * @param inApp application to call on menu actions
138          * @param inTrackInfo track info object
139          */
140         public MenuManager(App inApp, TrackInfo inTrackInfo)
141         {
142                 _app = inApp;
143                 _track = inTrackInfo.getTrack();
144                 _selection = inTrackInfo.getSelection();
145         }
146
147
148         /**
149          * Create a JMenuBar containing all menu items
150          * @return JMenuBar
151          */
152         public JMenuBar createMenuBar()
153         {
154                 JMenuBar menubar = new JMenuBar();
155                 JMenu fileMenu = new JMenu(I18nManager.getText("menu.file"));
156                 setAltKey(fileMenu, "altkey.menu.file");
157                 // Open file
158                 JMenuItem openMenuItem = new JMenuItem(I18nManager.getText("function.open"));
159                 setShortcut(openMenuItem, "shortcut.menu.file.open");
160                 _openFileAction = new ActionListener() {
161                         public void actionPerformed(ActionEvent e) {
162                                 _app.openFile();
163                         }
164                 };
165                 openMenuItem.addActionListener(_openFileAction);
166                 fileMenu.add(openMenuItem);
167                 // import through gpsbabel
168                 JMenuItem importBabelItem = makeMenuItem(FunctionLibrary.FUNCTION_IMPORTBABEL);
169                 fileMenu.add(importBabelItem);
170                 // Add photos
171                 JMenuItem addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
172                 _addPhotoAction = new ActionListener() {
173                         public void actionPerformed(ActionEvent e) {
174                                 _app.addPhotos();
175                         }
176                 };
177                 addPhotosMenuItem.addActionListener(_addPhotoAction);
178                 fileMenu.add(addPhotosMenuItem);
179                 // Add audio clips
180                 JMenuItem addAudioMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_LOAD_AUDIO);
181                 fileMenu.add(addAudioMenuItem);
182                 // recent files
183                 _recentFileMenu = new JMenu(I18nManager.getText("menu.file.recentfiles"));
184                 _recentFileMenu.setEnabled(false);
185                 fileMenu.add(_recentFileMenu);
186                 fileMenu.addSeparator();
187                 // Load from GPS
188                 JMenuItem loadFromGpsMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSLOAD);
189                 setShortcut(loadFromGpsMenuItem, "shortcut.menu.file.load");
190                 fileMenu.add(loadFromGpsMenuItem);
191                 // Send to GPS
192                 _sendGpsItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSSAVE, false);
193                 fileMenu.add(_sendGpsItem);
194                 fileMenu.addSeparator();
195                 // Save
196                 _saveItem = new JMenuItem(I18nManager.getText("menu.file.save"), KeyEvent.VK_S);
197                 setShortcut(_saveItem, "shortcut.menu.file.save");
198                 _saveAction = new ActionListener() {
199                         public void actionPerformed(ActionEvent e) {
200                                 _app.saveFile();
201                         }
202                 };
203                 _saveItem.addActionListener(_saveAction);
204                 _saveItem.setEnabled(false);
205                 fileMenu.add(_saveItem);
206                 // Export - Kml
207                 _exportKmlItem = makeMenuItem(FunctionLibrary.FUNCTION_KMLEXPORT, false);
208                 fileMenu.add(_exportKmlItem);
209                 // Gpx
210                 _exportGpxItem = makeMenuItem(FunctionLibrary.FUNCTION_GPXEXPORT, false);
211                 fileMenu.add(_exportGpxItem);
212                 // Pov
213                 _exportPovItem = makeMenuItem(FunctionLibrary.FUNCTION_POVEXPORT, false);
214                 fileMenu.add(_exportPovItem);
215                 // Svg
216                 _exportSvgItem = makeMenuItem(FunctionLibrary.FUNCTION_SVGEXPORT, false);
217                 fileMenu.add(_exportSvgItem);
218                 fileMenu.addSeparator();
219                 JMenuItem exitMenuItem = new JMenuItem(I18nManager.getText("menu.file.exit"));
220                 exitMenuItem.addActionListener(new ActionListener() {
221                         public void actionPerformed(ActionEvent e) {
222                                 _app.exit();
223                         }
224                 });
225                 fileMenu.add(exitMenuItem);
226                 menubar.add(fileMenu);
227
228                 // Track menu
229                 JMenu trackMenu = new JMenu(I18nManager.getText("menu.track"));
230                 setAltKey(trackMenu, "altkey.menu.track");
231                 _undoItem = new JMenuItem(I18nManager.getText("menu.track.undo"));
232                 setShortcut(_undoItem, "shortcut.menu.track.undo");
233                 _undoAction = new ActionListener() {
234                         public void actionPerformed(ActionEvent e) {
235                                 _app.beginUndo();
236                         }
237                 };
238                 _undoItem.addActionListener(_undoAction);
239                 _undoItem.setEnabled(false);
240                 trackMenu.add(_undoItem);
241                 _clearUndoItem = new JMenuItem(I18nManager.getText("menu.track.clearundo"));
242                 _clearUndoItem.addActionListener(new ActionListener() {
243                         public void actionPerformed(ActionEvent e) {
244                                 _app.clearUndo();
245                         }
246                 });
247                 _clearUndoItem.setEnabled(false);
248                 trackMenu.add(_clearUndoItem);
249                 trackMenu.addSeparator();
250                 _compressItem = makeMenuItem(FunctionLibrary.FUNCTION_COMPRESS, false);
251                 setShortcut(_compressItem, "shortcut.menu.edit.compress");
252                 trackMenu.add(_compressItem);
253                 _deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.track.deletemarked"));
254                 _deleteMarkedPointsItem.addActionListener(new ActionListener() {
255                         public void actionPerformed(ActionEvent e) {
256                                 _app.finishCompressTrack();
257                         }
258                 });
259                 _deleteMarkedPointsItem.setEnabled(false);
260                 trackMenu.add(_deleteMarkedPointsItem);
261                 trackMenu.addSeparator();
262                 // Rearrange waypoints
263                 _rearrangeMenu = new JMenu(I18nManager.getText("menu.track.rearrange"));
264                 _rearrangeMenu.setEnabled(false);
265                 JMenuItem  rearrangeStartItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.start"));
266                 rearrangeStartItem.addActionListener(new ActionListener() {
267                         public void actionPerformed(ActionEvent e) {
268                                 FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_START);
269                         }
270                 });
271                 rearrangeStartItem.setEnabled(true);
272                 _rearrangeMenu.add(rearrangeStartItem);
273                 JMenuItem rearrangeEndItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.end"));
274                 rearrangeEndItem.addActionListener(new ActionListener() {
275                         public void actionPerformed(ActionEvent e) {
276                                 FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_END);
277                         }
278                 });
279                 rearrangeEndItem.setEnabled(true);
280                 _rearrangeMenu.add(rearrangeEndItem);
281                 JMenuItem rearrangeNearestItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.nearest"));
282                 rearrangeNearestItem.addActionListener(new ActionListener() {
283                         public void actionPerformed(ActionEvent e) {
284                                 FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_NEAREST);
285                         }
286                 });
287                 rearrangeNearestItem.setEnabled(true);
288                 _rearrangeMenu.add(rearrangeNearestItem);
289                 trackMenu.add(_rearrangeMenu);
290                 // Get gpsies tracks
291                 _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES, false);
292                 trackMenu.add(_getGpsiesItem);
293                 // Upload to gpsies
294                 _uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES, false);
295                 trackMenu.add(_uploadGpsiesItem);
296                 _lookupSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_SRTM, false);
297                 trackMenu.add(_lookupSrtmItem);
298                 _lookupWikipediaItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_WIKIPEDIA, false);
299                 trackMenu.add(_lookupWikipediaItem);
300                 JMenuItem searchWikipediaNamesItem = makeMenuItem(FunctionLibrary.FUNCTION_SEARCH_WIKIPEDIA);
301                 trackMenu.add(searchWikipediaNamesItem);
302                 _downloadOsmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_OSM, false);
303                 trackMenu.add(_downloadOsmItem);
304                 menubar.add(trackMenu);
305
306                 // Range menu
307                 JMenu rangeMenu = new JMenu(I18nManager.getText("menu.range"));
308                 setAltKey(rangeMenu, "altkey.menu.range");
309                 _selectAllItem = new JMenuItem(I18nManager.getText("menu.range.all"));
310                 setShortcut(_selectAllItem, "shortcut.menu.range.all");
311                 _selectAllItem.setEnabled(false);
312                 _selectAllItem.addActionListener(new ActionListener() {
313                         public void actionPerformed(ActionEvent e) {
314                                 _selection.selectRange(0, _track.getNumPoints()-1);
315                         }
316                 });
317                 rangeMenu.add(_selectAllItem);
318                 _selectNoneItem = new JMenuItem(I18nManager.getText("menu.range.none"));
319                 _selectNoneItem.setEnabled(false);
320                 _selectNoneItem.addActionListener(new ActionListener() {
321                         public void actionPerformed(ActionEvent e) {
322                                 _app.selectNone();
323                         }
324                 });
325                 rangeMenu.add(_selectNoneItem);
326                 rangeMenu.addSeparator();
327                 _selectStartItem = new JMenuItem(I18nManager.getText("menu.range.start"));
328                 _selectStartItem.setEnabled(false);
329                 _selectStartAction = new ActionListener() {
330                         public void actionPerformed(ActionEvent e) {
331                                 _selection.selectRangeStart();
332                         }
333                 };
334                 _selectStartItem.addActionListener(_selectStartAction);
335                 rangeMenu.add(_selectStartItem);
336                 _selectEndItem = new JMenuItem(I18nManager.getText("menu.range.end"));
337                 _selectEndItem.setEnabled(false);
338                 _selectEndAction = new ActionListener() {
339                         public void actionPerformed(ActionEvent e) {
340                                 _selection.selectRangeEnd();
341                         }
342                 };
343                 _selectEndItem.addActionListener(_selectEndAction);
344                 rangeMenu.add(_selectEndItem);
345                 rangeMenu.addSeparator();
346                 _deleteRangeItem = new JMenuItem(I18nManager.getText("menu.range.deleterange"));
347                 _deleteRangeAction = new ActionListener() {
348                         public void actionPerformed(ActionEvent e) {
349                                 _app.deleteSelectedRange();
350                         }
351                 };
352                 _deleteRangeItem.addActionListener(_deleteRangeAction);
353                 _deleteRangeItem.setEnabled(false);
354                 rangeMenu.add(_deleteRangeItem);
355                 _reverseItem = new JMenuItem(I18nManager.getText("menu.range.reverse"));
356                 _reverseItem.addActionListener(new ActionListener() {
357                         public void actionPerformed(ActionEvent e) {
358                                 _app.reverseRange();
359                         }
360                 });
361                 _reverseItem.setEnabled(false);
362                 rangeMenu.add(_reverseItem);
363                 _addTimeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_TIME_OFFSET, false);
364                 rangeMenu.add(_addTimeOffsetItem);
365                 _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET, false);
366                 rangeMenu.add(_addAltitudeOffsetItem);
367                 _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.range.mergetracksegments"));
368                 _mergeSegmentsItem.addActionListener(new ActionListener() {
369                         public void actionPerformed(ActionEvent e) {
370                                 _app.mergeTrackSegments();
371                         }
372                 });
373                 _mergeSegmentsItem.setEnabled(false);
374                 rangeMenu.add(_mergeSegmentsItem);
375                 _deleteFieldValuesItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_FIELD_VALUES, false);
376                 rangeMenu.add(_deleteFieldValuesItem);
377                 rangeMenu.addSeparator();
378                 _interpolateItem = new JMenuItem(I18nManager.getText("menu.range.interpolate"));
379                 _interpolateItem.addActionListener(new ActionListener() {
380                         public void actionPerformed(ActionEvent e) {
381                                 _app.interpolateSelection();
382                         }
383                 });
384                 _interpolateItem.setEnabled(false);
385                 rangeMenu.add(_interpolateItem);
386                 _averageItem = new JMenuItem(I18nManager.getText("menu.range.average"));
387                 _averageItem.addActionListener(new ActionListener() {
388                         public void actionPerformed(ActionEvent e) {
389                                 _app.averageSelection();
390                         }
391                 });
392                 _averageItem.setEnabled(false);
393                 rangeMenu.add(_averageItem);
394                 _cutAndMoveItem = new JMenuItem(I18nManager.getText("menu.range.cutandmove"));
395                 _cutAndMoveItem.addActionListener(new ActionListener() {
396                         public void actionPerformed(ActionEvent e)
397                         {
398                                 _app.cutAndMoveSelection();
399                         }
400                 });
401                 _cutAndMoveItem.setEnabled(false);
402                 rangeMenu.add(_cutAndMoveItem);
403                 _convertNamesToTimesItem = makeMenuItem(FunctionLibrary.FUNCTION_CONVERT_NAMES_TO_TIMES, false);
404                 rangeMenu.add(_convertNamesToTimesItem);
405                 menubar.add(rangeMenu);
406
407                 // Point menu
408                 JMenu pointMenu = new JMenu(I18nManager.getText("menu.point"));
409                 setAltKey(pointMenu, "altkey.menu.point");
410                 _editPointItem = new JMenuItem(I18nManager.getText("menu.point.editpoint"));
411                 _editPointAction = new ActionListener() {
412                         public void actionPerformed(ActionEvent e) {
413                                 _app.editCurrentPoint();
414                         }
415                 };
416                 _editPointItem.addActionListener(_editPointAction);
417                 _editPointItem.setEnabled(false);
418                 pointMenu.add(_editPointItem);
419                 _editWaypointNameItem = makeMenuItem(FunctionLibrary.FUNCTION_EDIT_WAYPOINT_NAME, false);
420                 pointMenu.add(_editWaypointNameItem);
421                 _deletePointItem = new JMenuItem(I18nManager.getText("menu.point.deletepoint"));
422                 _deletePointAction = new ActionListener() {
423                         public void actionPerformed(ActionEvent e) {
424                                 _app.deleteCurrentPoint();
425                         }
426                 };
427                 _deletePointItem.addActionListener(_deletePointAction);
428                 _deletePointItem.setEnabled(false);
429                 _deletePointItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
430                 pointMenu.add(_deletePointItem);
431                 pointMenu.addSeparator();
432                 // find a waypoint
433                 _findWaypointItem = makeMenuItem(FunctionLibrary.FUNCTION_FIND_WAYPOINT, false);
434                 pointMenu.add(_findWaypointItem);
435                 // duplicate current point
436                 _duplicatePointItem = makeMenuItem(FunctionLibrary.FUNCTION_DUPLICATE_POINT, false);
437                 pointMenu.add(_duplicatePointItem);
438                 // paste coordinates function
439                 JMenuItem pasteCoordsItem = makeMenuItem(FunctionLibrary.FUNCTION_PASTE_COORDINATES);
440                 pointMenu.add(pasteCoordsItem);
441                 menubar.add(pointMenu);
442
443                 // Add view menu
444                 JMenu viewMenu = new JMenu(I18nManager.getText("menu.view"));
445                 setAltKey(viewMenu, "altkey.menu.view");
446                 // Turn map display on/off
447                 _mapCheckbox = new JCheckBoxMenuItem(
448                         I18nManager.getText("menu.map.showmap"), false);
449                 _mapCheckbox.addActionListener(new ActionListener() {
450                         public void actionPerformed(ActionEvent e) {
451                                 Config.setConfigBoolean(Config.KEY_SHOW_MAP, _mapCheckbox.isSelected());
452                                 UpdateMessageBroker.informSubscribers();
453                         }
454                 });
455                 viewMenu.add(_mapCheckbox);
456                 // Turn off the sidebars
457                 JCheckBoxMenuItem sidebarsCheckbox = new JCheckBoxMenuItem(I18nManager.getText("menu.view.showsidebars"));
458                 sidebarsCheckbox.setSelected(true);
459                 sidebarsCheckbox.addActionListener(new ActionListener() {
460                         public void actionPerformed(ActionEvent e) {
461                                 _app.toggleSidebars();
462                         }
463                 });
464                 sidebarsCheckbox.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0)); // shortcut F11
465                 viewMenu.add(sidebarsCheckbox);
466                 // 3d
467                 _show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D, false);
468                 viewMenu.add(_show3dItem);
469                 // browser submenu
470                 _browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
471                 _browserMapMenu.setEnabled(false);
472                 JMenuItem googleMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.google"));
473                 googleMapsItem.addActionListener(new ActionListener() {
474                         public void actionPerformed(ActionEvent e) {
475                                 _app.showExternalMap(UrlGenerator.MAP_SOURCE_GOOGLE);
476                         }
477                 });
478                 _browserMapMenu.add(googleMapsItem);
479                 JMenuItem openMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.openstreetmap"));
480                 openMapsItem.addActionListener(new ActionListener() {
481                         public void actionPerformed(ActionEvent e) {
482                                 _app.showExternalMap(UrlGenerator.MAP_SOURCE_OSM);
483                         }
484                 });
485                 _browserMapMenu.add(openMapsItem);
486                 JMenuItem mapquestMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.mapquest"));
487                 mapquestMapsItem.addActionListener(new ActionListener() {
488                         public void actionPerformed(ActionEvent e) {
489                                 _app.showExternalMap(UrlGenerator.MAP_SOURCE_MAPQUEST);
490                         }
491                 });
492                 _browserMapMenu.add(mapquestMapsItem);
493                 JMenuItem yahooMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.yahoo"));
494                 yahooMapsItem.addActionListener(new ActionListener() {
495                         public void actionPerformed(ActionEvent e) {
496                                 _app.showExternalMap(UrlGenerator.MAP_SOURCE_YAHOO);
497                         }
498                 });
499                 _browserMapMenu.add(yahooMapsItem);
500                 JMenuItem bingMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.bing"));
501                 bingMapsItem.addActionListener(new ActionListener() {
502                         public void actionPerformed(ActionEvent e) {
503                                 _app.showExternalMap(UrlGenerator.MAP_SOURCE_BING);
504                         }
505                 });
506                 _browserMapMenu.add(bingMapsItem);
507                 viewMenu.add(_browserMapMenu);
508                 // Charts
509                 _chartItem = makeMenuItem(FunctionLibrary.FUNCTION_CHARTS, false);
510                 viewMenu.add(_chartItem);
511                 // Distances
512                 _distanceItem = makeMenuItem(FunctionLibrary.FUNCTION_DISTANCES, false);
513                 viewMenu.add(_distanceItem);
514                 // full range details
515                 _fullRangeDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_RANGE_DETAILS, false);
516                 viewMenu.add(_fullRangeDetailsItem);
517                 menubar.add(viewMenu);
518
519                 // Add photo menu
520                 JMenu photoMenu = new JMenu(I18nManager.getText("menu.photo"));
521                 setAltKey(photoMenu, "altkey.menu.photo");
522                 addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
523                 addPhotosMenuItem.addActionListener(_addPhotoAction);
524                 photoMenu.add(addPhotosMenuItem);
525                 _saveExifItem = new JMenuItem(I18nManager.getText("menu.photo.saveexif"));
526                 _saveExifItem.addActionListener(new ActionListener() {
527                         public void actionPerformed(ActionEvent e) {
528                                 _app.saveExif();
529                         }
530                 });
531                 _saveExifItem.setEnabled(false);
532                 photoMenu.add(_saveExifItem);
533                 // Deselect current photo
534                 _selectNoPhotoItem = new JMenuItem(I18nManager.getText("menu.range.none"));
535                 _selectNoPhotoItem.setEnabled(false);
536                 _selectNoPhotoItem.addActionListener(new ActionListener() {
537                         public void actionPerformed(ActionEvent e) {
538                                 _app.getTrackInfo().selectPhoto(-1);
539                         }
540                 });
541                 photoMenu.add(_selectNoPhotoItem);
542                 photoMenu.addSeparator();
543                 _connectPhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_CONNECT_TO_POINT, false);
544                 photoMenu.add(_connectPhotoItem);
545                 // disconnect photo
546                 _disconnectPhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_DISCONNECT_PHOTO, false);
547                 photoMenu.add(_disconnectPhotoItem);
548                 _removePhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_PHOTO, false);
549                 photoMenu.add(_removePhotoItem);
550                 // Rotate current photo
551                 _rotatePhotoLeft = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_LEFT, false);
552                 photoMenu.add(_rotatePhotoLeft);
553                 _rotatePhotoRight = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_RIGHT, false);
554                 photoMenu.add(_rotatePhotoRight);
555                 // Show photo popup
556                 _photoPopupItem = makeMenuItem(FunctionLibrary.FUNCTION_PHOTO_POPUP, false);
557                 photoMenu.add(_photoPopupItem);
558                 _ignoreExifThumb = makeMenuItem(FunctionLibrary.FUNCTION_IGNORE_EXIF_THUMB, false);
559                 photoMenu.add(_ignoreExifThumb);
560                 photoMenu.addSeparator();
561                 // correlate all photos
562                 _correlatePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_PHOTOS, false);
563                 photoMenu.add(_correlatePhotosItem);
564                 // rearrange photo points
565                 _rearrangePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_REARRANGE_PHOTOS, false);
566                 photoMenu.add(_rearrangePhotosItem);
567                 menubar.add(photoMenu);
568
569                 // Audio menu
570                 JMenu audioMenu = new JMenu(I18nManager.getText("menu.audio"));
571                 setAltKey(audioMenu, "altkey.menu.audio");
572                 addAudioMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_LOAD_AUDIO);
573                 audioMenu.add(addAudioMenuItem);
574                 _selectNoAudioItem = new JMenuItem(I18nManager.getText("menu.range.none"));
575                 _selectNoAudioItem.setEnabled(false);
576                 _selectNoAudioItem.addActionListener(new ActionListener() {
577                         public void actionPerformed(ActionEvent e) {
578                                 _app.getTrackInfo().selectAudio(-1);
579                         }
580                 });
581                 audioMenu.add(_selectNoAudioItem);
582                 audioMenu.addSeparator();
583                 // connect audio
584                 _connectAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_CONNECT_TO_POINT, false);
585                 audioMenu.add(_connectAudioItem);
586                 // Disconnect current audio clip
587                 _disconnectAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_DISCONNECT_AUDIO, false);
588                 audioMenu.add(_disconnectAudioItem);
589                 // Remove current audio clip
590                 _removeAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_AUDIO, false);
591                 audioMenu.add(_removeAudioItem);
592                 audioMenu.addSeparator();
593                 // Correlate audio clips
594                 _correlateAudiosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_AUDIOS, false);
595                 audioMenu.add(_correlateAudiosItem);
596                 menubar.add(audioMenu);
597
598                 // Settings menu
599                 JMenu settingsMenu = new JMenu(I18nManager.getText("menu.settings"));
600                 setAltKey(settingsMenu, "altkey.menu.settings");
601                 // Set the map background
602                 JMenuItem mapBgItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_MAP_BG);
603                 settingsMenu.add(mapBgItem);
604                 _onlineCheckbox = new JCheckBoxMenuItem(I18nManager.getText("menu.settings.onlinemode"));
605                 _onlineCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_ONLINE_MODE));
606                 _onlineCheckbox.addActionListener(new ActionListener() {
607                         public void actionPerformed(ActionEvent e) {
608                                 boolean isOnline = _onlineCheckbox.isSelected();
609                                 Config.setConfigBoolean(Config.KEY_ONLINE_MODE, isOnline);
610                                 if (isOnline) {UpdateMessageBroker.informSubscribers();}
611                         }
612                 });
613                 settingsMenu.add(_onlineCheckbox);
614                 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_DISK_CACHE));
615                 settingsMenu.addSeparator();
616                 // Set kmz image size
617                 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_KMZ_IMAGE_SIZE));
618                 // Set program paths
619                 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_PATHS));
620                 // Set colours
621                 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_COLOURS));
622                 // Set line width used for drawing
623                 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_LINE_WIDTH));
624                 // Set language
625                 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_LANGUAGE));
626                 settingsMenu.addSeparator();
627                 // Save configuration
628                 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SAVECONFIG));
629                 _autosaveSettingsCheckbox = new JCheckBoxMenuItem(
630                         I18nManager.getText("menu.settings.autosave"), false);
631                 _autosaveSettingsCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS));
632                 _autosaveSettingsCheckbox.addActionListener(new ActionListener() {
633                         public void actionPerformed(ActionEvent e) {
634                                 Config.setConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS, _autosaveSettingsCheckbox.isSelected());
635                         }
636                 });
637                 settingsMenu.add(_autosaveSettingsCheckbox);
638                 menubar.add(settingsMenu);
639
640                 // Help menu
641                 JMenu helpMenu = new JMenu(I18nManager.getText("menu.help"));
642                 setAltKey(helpMenu, "altkey.menu.help");
643                 JMenuItem helpItem = makeMenuItem(FunctionLibrary.FUNCTION_HELP);
644                 setShortcut(helpItem, "shortcut.menu.help.help");
645                 helpMenu.add(helpItem);
646                 helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SHOW_KEYS));
647                 helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_ABOUT));
648                 helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_CHECK_VERSION));
649                 menubar.add(helpMenu);
650
651                 return menubar;
652         }
653
654         /**
655          * Convenience method for making a menu item using a function
656          * @param inFunction function
657          * @param inEnabled flag to specify initial enabled state
658          * @return menu item using localized name of function
659          */
660         private static JMenuItem makeMenuItem(GenericFunction inFunction, boolean inEnabled)
661         {
662                 JMenuItem item = makeMenuItem(inFunction);
663                 item.setEnabled(inEnabled);
664                 return item;
665         }
666
667         /**
668          * Convenience method for making a menu item using a function
669          * @param inFunction function
670          * @return menu item using localized name of function
671          */
672         private static JMenuItem makeMenuItem(GenericFunction inFunction)
673         {
674                 JMenuItem item = new JMenuItem(I18nManager.getText(inFunction.getNameKey()));
675                 item.addActionListener(new FunctionLauncher(inFunction));
676                 return item;
677         }
678
679         /**
680          * Set the alt key for the given menu
681          * @param inMenu menu to set
682          * @param inKey key to lookup to get language-sensitive altkey
683          */
684         private static void setAltKey(JMenu inMenu, String inKey)
685         {
686                 // Lookup the key in the properties
687                 String altKey = I18nManager.getText(inKey);
688                 if (altKey != null && altKey.length() == 1)
689                 {
690                         int code = altKey.charAt(0) - 'A';
691                         if (code >= 0 && code < 26)
692                         {
693                                 // Found a valid code between A and Z
694                                 inMenu.setMnemonic(KEY_EVENTS[code]);
695                         }
696                 }
697         }
698
699         /**
700          * Set the shortcut key for the given menu item
701          * @param inMenuItem menu item to set
702          * @param inKey key to lookup to get language-sensitive shortcut
703          */
704         private static void setShortcut(JMenuItem inMenuItem, String inKey)
705         {
706                 // Lookup the key in the properties
707                 String altKey = I18nManager.getText(inKey);
708                 if (altKey != null && altKey.length() == 1)
709                 {
710                         int code = altKey.charAt(0) - 'A';
711                         if (code >= 0 && code < 26)
712                         {
713                                 // Found a valid code between A and Z
714                                 inMenuItem.setAccelerator(KeyStroke.getKeyStroke(KEY_EVENTS[code],
715                                         Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
716                                 // use platform-specific key mask so Ctrl on Linux/Win, Clover on Mac
717                         }
718                 }
719         }
720
721         /**
722          * Create a JToolBar containing all toolbar buttons
723          * @return toolbar containing buttons
724          */
725         public JToolBar createToolBar()
726         {
727                 JToolBar toolbar = new JToolBar();
728                 // Add text file
729                 JButton openFileButton = new JButton(IconManager.getImageIcon(IconManager.OPEN_FILE));
730                 openFileButton.setToolTipText(I18nManager.getText("function.open"));
731                 openFileButton.addActionListener(_openFileAction);
732                 toolbar.add(openFileButton);
733                 // Add photo
734                 JButton addPhotoButton = new JButton(IconManager.getImageIcon(IconManager.ADD_PHOTO));
735                 addPhotoButton.setToolTipText(I18nManager.getText("menu.file.addphotos"));
736                 addPhotoButton.addActionListener(_addPhotoAction);
737                 toolbar.add(addPhotoButton);
738                 // Save
739                 _saveButton = new JButton(IconManager.getImageIcon(IconManager.SAVE_FILE));
740                 _saveButton.setToolTipText(I18nManager.getText("menu.file.save"));
741                 _saveButton.addActionListener(_saveAction);
742                 _saveButton.setEnabled(false);
743                 toolbar.add(_saveButton);
744                 // Undo
745                 _undoButton = new JButton(IconManager.getImageIcon(IconManager.UNDO));
746                 _undoButton.setToolTipText(I18nManager.getText("menu.track.undo"));
747                 _undoButton.addActionListener(_undoAction);
748                 _undoButton.setEnabled(false);
749                 toolbar.add(_undoButton);
750                 // Edit point
751                 _editPointButton = new JButton(IconManager.getImageIcon(IconManager.EDIT_POINT));
752                 _editPointButton.setToolTipText(I18nManager.getText("menu.point.editpoint"));
753                 _editPointButton.addActionListener(_editPointAction);
754                 _editPointButton.setEnabled(false);
755                 toolbar.add(_editPointButton);
756                 // Delete point
757                 _deletePointButton = new JButton(IconManager.getImageIcon(IconManager.DELETE_POINT));
758                 _deletePointButton.setToolTipText(I18nManager.getText("menu.point.deletepoint"));
759                 _deletePointButton.addActionListener(_deletePointAction);
760                 _deletePointButton.setEnabled(false);
761                 toolbar.add(_deletePointButton);
762                 // Delete range
763                 _deleteRangeButton = new JButton(IconManager.getImageIcon(IconManager.DELETE_RANGE));
764                 _deleteRangeButton.setToolTipText(I18nManager.getText("menu.range.deleterange"));
765                 _deleteRangeButton.addActionListener(_deleteRangeAction);
766                 _deleteRangeButton.setEnabled(false);
767                 toolbar.add(_deleteRangeButton);
768                 // Select start, end
769                 _selectStartButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_START));
770                 _selectStartButton.setToolTipText(I18nManager.getText("menu.range.start"));
771                 _selectStartButton.addActionListener(_selectStartAction);
772                 _selectStartButton.setEnabled(false);
773                 toolbar.add(_selectStartButton);
774                 _selectEndButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_END));
775                 _selectEndButton.setToolTipText(I18nManager.getText("menu.range.end"));
776                 _selectEndButton.addActionListener(_selectEndAction);
777                 _selectEndButton.setEnabled(false);
778                 toolbar.add(_selectEndButton);
779                 // Connect to point
780                 _connectButton = new JButton(IconManager.getImageIcon(IconManager.CONNECT_PHOTO));
781                 _connectButton.setToolTipText(I18nManager.getText(FunctionLibrary.FUNCTION_CONNECT_TO_POINT.getNameKey()));
782                 _connectButton.addActionListener(new ActionListener() {
783                         public void actionPerformed(ActionEvent arg0) {
784                                 FunctionLibrary.FUNCTION_CONNECT_TO_POINT.begin();
785                         }
786                 });
787                 _connectButton.setEnabled(false);
788                 toolbar.add(_connectButton);
789                 // finish off
790                 toolbar.setFloatable(false);
791                 return toolbar;
792         }
793
794
795         /**
796          * Method to update menu when file loaded
797          */
798         public void informFileLoaded()
799         {
800                 // save, undo, delete enabled
801                 _sendGpsItem.setEnabled(true);
802                 _saveItem.setEnabled(true);
803                 _undoItem.setEnabled(true);
804                 _compressItem.setEnabled(true);
805                 _deleteMarkedPointsItem.setEnabled(false);
806         }
807
808
809         /**
810          * @see tim.prune.DataSubscriber#dataUpdated(tim.prune.data.Track)
811          */
812         public void dataUpdated(byte inUpdateType)
813         {
814                 boolean hasData = (_track != null && _track.getNumPoints() > 0);
815                 // set functions which require data
816                 _sendGpsItem.setEnabled(hasData);
817                 _saveItem.setEnabled(hasData);
818                 _saveButton.setEnabled(hasData);
819                 _exportKmlItem.setEnabled(hasData);
820                 _exportGpxItem.setEnabled(hasData);
821                 _exportPovItem.setEnabled(hasData);
822                 _exportSvgItem.setEnabled(hasData);
823                 _compressItem.setEnabled(hasData);
824                 _deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints());
825                 _rearrangeMenu.setEnabled(hasData && _track.hasTrackPoints() && _track.hasWaypoints());
826                 _selectAllItem.setEnabled(hasData);
827                 _selectNoneItem.setEnabled(hasData);
828                 _show3dItem.setEnabled(hasData);
829                 _chartItem.setEnabled(hasData);
830                 _browserMapMenu.setEnabled(hasData);
831                 _distanceItem.setEnabled(hasData);
832                 _getGpsiesItem.setEnabled(hasData);
833                 _uploadGpsiesItem.setEnabled(hasData && _track.hasTrackPoints());
834                 _lookupSrtmItem.setEnabled(hasData);
835                 _lookupWikipediaItem.setEnabled(hasData);
836                 _downloadOsmItem.setEnabled(hasData);
837                 _findWaypointItem.setEnabled(hasData && _track.hasWaypoints());
838                 // is undo available?
839                 boolean hasUndo = !_app.getUndoStack().isEmpty();
840                 _undoItem.setEnabled(hasUndo);
841                 _undoButton.setEnabled(hasUndo);
842                 _clearUndoItem.setEnabled(hasUndo);
843                 // is there a current point?
844                 boolean hasPoint = (hasData && _selection.getCurrentPointIndex() >= 0);
845                 _editPointItem.setEnabled(hasPoint);
846                 _editPointButton.setEnabled(hasPoint);
847                 _editWaypointNameItem.setEnabled(hasPoint);
848                 _deletePointItem.setEnabled(hasPoint);
849                 _deletePointButton.setEnabled(hasPoint);
850                 _selectStartItem.setEnabled(hasPoint);
851                 _selectStartButton.setEnabled(hasPoint);
852                 _selectEndItem.setEnabled(hasPoint);
853                 _selectEndButton.setEnabled(hasPoint);
854                 _duplicatePointItem.setEnabled(hasPoint);
855                 // are there any photos?
856                 boolean anyPhotos = _app.getTrackInfo().getPhotoList().getNumPhotos() > 0;
857                 _saveExifItem.setEnabled(anyPhotos && _app.getTrackInfo().getPhotoList().hasMediaWithFile());
858                 // is there a current photo, audio?
859                 Photo currentPhoto = _app.getTrackInfo().getCurrentPhoto();
860                 boolean hasPhoto = currentPhoto != null;
861                 AudioClip currentAudio = _app.getTrackInfo().getCurrentAudio();
862                 boolean hasAudio = currentAudio != null;
863                 // connect is available if (photo/audio) and point selected, and media has no point
864                 boolean connectAvailable = (hasPhoto && hasPoint && currentPhoto.getDataPoint() == null)
865                         || (hasAudio && hasPoint && currentAudio.getDataPoint() == null);
866                 _connectPhotoItem.setEnabled(hasPhoto && hasPoint && currentPhoto.getDataPoint() == null);
867                 _connectButton.setEnabled(connectAvailable);
868                 _disconnectPhotoItem.setEnabled(hasPhoto && currentPhoto.getDataPoint() != null);
869                 _correlatePhotosItem.setEnabled(anyPhotos && hasData);
870                 _rearrangePhotosItem.setEnabled(anyPhotos && hasData && _track.getNumPoints() > 1);
871                 _removePhotoItem.setEnabled(hasPhoto);
872                 _rotatePhotoLeft.setEnabled(hasPhoto);
873                 _rotatePhotoRight.setEnabled(hasPhoto);
874                 _photoPopupItem.setEnabled(hasPhoto);
875                 _ignoreExifThumb.setEnabled(hasPhoto && currentPhoto.getExifThumbnail() != null);
876                 _selectNoPhotoItem.setEnabled(hasPhoto);
877                 boolean anyAudios = _app.getTrackInfo().getAudioList().getNumAudios() > 0;
878                 _selectNoAudioItem.setEnabled(hasAudio);
879                 _removeAudioItem.setEnabled(hasAudio);
880                 _connectAudioItem.setEnabled(hasAudio && hasPoint && currentAudio.getDataPoint() == null);
881                 _disconnectAudioItem.setEnabled(hasAudio && _app.getTrackInfo().getCurrentAudio().getDataPoint() != null);
882                 _correlateAudiosItem.setEnabled(anyAudios && hasData);
883                 // is there a current range?
884                 boolean hasRange = (hasData && _selection.hasRangeSelected());
885                 _deleteRangeItem.setEnabled(hasRange);
886                 _deleteRangeButton.setEnabled(hasRange);
887                 _interpolateItem.setEnabled(hasRange
888                         && (_selection.getEnd() - _selection.getStart()) == 1);
889                 _averageItem.setEnabled(hasRange);
890                 _mergeSegmentsItem.setEnabled(hasRange);
891                 _reverseItem.setEnabled(hasRange);
892                 _addTimeOffsetItem.setEnabled(hasRange);
893                 _addAltitudeOffsetItem.setEnabled(hasRange);
894                 _convertNamesToTimesItem.setEnabled(hasRange && _track.hasWaypoints());
895                 _deleteFieldValuesItem.setEnabled(hasRange);
896                 _fullRangeDetailsItem.setEnabled(hasRange);
897                 // Is the currently selected point outside the current range?
898                 _cutAndMoveItem.setEnabled(hasRange && hasPoint &&
899                         (_selection.getCurrentPointIndex() < _selection.getStart()
900                                 || _selection.getCurrentPointIndex() > (_selection.getEnd()+1)));
901                 // Has the map been switched on/off?
902                 boolean mapsOn = Config.getConfigBoolean(Config.KEY_SHOW_MAP);
903                 if (_mapCheckbox.isSelected() != mapsOn) {
904                         _mapCheckbox.setSelected(mapsOn);
905                 }
906                 // Are there any recently-used files?
907                 RecentFileList rfl = Config.getRecentFileList();
908                 final int numRecentFiles = rfl.getNumEntries();
909                 final boolean hasRecentFiles = numRecentFiles > 0;
910                 _recentFileMenu.setEnabled(hasRecentFiles);
911                 if (hasRecentFiles)
912                 {
913                         int numItems = _recentFileMenu.getMenuComponentCount();
914                         if (numItems == numRecentFiles)
915                         {
916                                 // Right number of items, just change texts
917                                 for (int i=0; i<numRecentFiles; i++)
918                                 {
919                                         JMenuItem item = _recentFileMenu.getItem(i);
920                                         item.setText(rfl.getFile(i)==null?"":rfl.getFile(i).getFile().getName());
921                                         item.setToolTipText(rfl.getFile(i)==null?null:rfl.getFile(i).getFile().getAbsolutePath());
922                                 }
923                         }
924                         else
925                         {
926                                 // Rebuild menus
927                                 _recentFileMenu.removeAll();
928                                 for (int i=0; i<rfl.getSize(); i++)
929                                 {
930                                         RecentFile rf = rfl.getFile(i);
931                                         if (rf != null && rf.isValid())
932                                         {
933                                                 JMenuItem menuItem = new JMenuItem(rf.getFile().getName());
934                                                 menuItem.setToolTipText(rf.getFile().getAbsolutePath());
935                                                 menuItem.addActionListener(new RecentFileTrigger(_app, i));
936                                                 _recentFileMenu.add(menuItem);
937                                         }
938                                 }
939                         }
940                 }
941         }
942
943
944         /**
945          * Ignore action completed signals
946          * @see tim.prune.DataSubscriber#actionCompleted(java.lang.String)
947          */
948         public void actionCompleted(String inMessage)
949         {}
950 }