]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/MenuManager.java
Version 14, October 2012
[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 _cropTrackItem = null;
58         private JMenuItem _compressItem = null;
59         private JMenuItem _markRectangleItem = null;
60         private JMenuItem _deleteMarkedPointsItem = null;
61         private JMenuItem _interpolateItem = null;
62         private JMenuItem _averageItem = null;
63         private JMenuItem _selectAllItem = null;
64         private JMenuItem _selectNoneItem = null;
65         private JMenuItem _selectStartItem = null;
66         private JMenuItem _selectEndItem = null;
67         private JMenuItem _findWaypointItem = null;
68         private JMenuItem _duplicatePointItem = null;
69         private JMenuItem _reverseItem = null;
70         private JMenuItem _addTimeOffsetItem = null;
71         private JMenuItem _addAltitudeOffsetItem = null;
72         private JMenuItem _mergeSegmentsItem = null;
73         private JMenu     _rearrangeMenu = null;
74         private JMenuItem _cutAndMoveItem = null;
75         private JMenuItem _convertNamesToTimesItem = null;
76         private JMenuItem _deleteFieldValuesItem = null;
77         private JCheckBoxMenuItem _mapCheckbox = null;
78         private JMenuItem _show3dItem = null;
79         private JMenu     _browserMapMenu = null;
80         private JMenuItem _chartItem = null;
81         private JMenuItem _getGpsiesItem = null;
82         private JMenuItem _uploadGpsiesItem = null;
83         private JMenuItem _lookupSrtmItem = null;
84         private JMenuItem _lookupWikipediaItem = null;
85         private JMenuItem _downloadOsmItem = null;
86         private JMenuItem _distanceItem = null;
87         private JMenuItem _fullRangeDetailsItem = null;
88         private JMenuItem _saveExifItem = null;
89         private JMenuItem _photoPopupItem = null;
90         private JMenuItem _selectNoPhotoItem = null;
91         private JMenuItem _connectPhotoItem = null;
92         private JMenuItem _removePhotoItem = null;
93         private JMenuItem _disconnectPhotoItem = null;
94         private JMenuItem _correlatePhotosItem = null;
95         private JMenuItem _rearrangePhotosItem = null;
96         private JMenuItem _rotatePhotoLeft = null;
97         private JMenuItem _rotatePhotoRight = null;
98         private JMenuItem _ignoreExifThumb = null;
99         private JMenuItem _connectAudioItem = null;
100         private JMenuItem _disconnectAudioItem = null;
101         private JMenuItem _removeAudioItem = null;
102         private JMenuItem _correlateAudiosItem = null;
103         private JMenuItem _selectNoAudioItem = null;
104         private JCheckBoxMenuItem _onlineCheckbox = null;
105         private JCheckBoxMenuItem _autosaveSettingsCheckbox = null;
106
107         // ActionListeners for reuse by menu and toolbar
108         private ActionListener _openFileAction = null;
109         private ActionListener _addPhotoAction = null;
110         private ActionListener _saveAction = null;
111         private ActionListener _undoAction = null;
112         private ActionListener _editPointAction = null;
113         private ActionListener _deletePointAction = null;
114         private ActionListener _selectStartAction = null;
115         private ActionListener _selectEndAction = null;
116
117         // Toolbar buttons which need enabling/disabling
118         private JButton _saveButton = null;
119         private JButton _undoButton = null;
120         private JButton _editPointButton = null;
121         private JButton _deletePointButton = null;
122         private JButton _deleteRangeButton = null;
123         private JButton _cutAndMoveButton = null;
124         private JButton _selectStartButton = null;
125         private JButton _selectEndButton = null;
126         private JButton _connectButton = null;
127
128         /** Array of key events */
129         private static final int[] KEY_EVENTS = {
130                 KeyEvent.VK_A, KeyEvent.VK_B, KeyEvent.VK_C, KeyEvent.VK_D, KeyEvent.VK_E,
131                 KeyEvent.VK_F, KeyEvent.VK_G, KeyEvent.VK_H, KeyEvent.VK_I, KeyEvent.VK_J,
132                 KeyEvent.VK_K, KeyEvent.VK_L, KeyEvent.VK_M, KeyEvent.VK_N, KeyEvent.VK_O,
133                 KeyEvent.VK_P, KeyEvent.VK_Q, KeyEvent.VK_R, KeyEvent.VK_S, KeyEvent.VK_T,
134                 KeyEvent.VK_U, KeyEvent.VK_V, KeyEvent.VK_W, KeyEvent.VK_X, KeyEvent.VK_Y, KeyEvent.VK_Z};
135
136
137         /**
138          * Constructor
139          * @param inApp application to call on menu actions
140          * @param inTrackInfo track info object
141          */
142         public MenuManager(App inApp, TrackInfo inTrackInfo)
143         {
144                 _app = inApp;
145                 _track = inTrackInfo.getTrack();
146                 _selection = inTrackInfo.getSelection();
147         }
148
149
150         /**
151          * Create a JMenuBar containing all menu items
152          * @return JMenuBar
153          */
154         public JMenuBar createMenuBar()
155         {
156                 JMenuBar menubar = new JMenuBar();
157                 JMenu fileMenu = new JMenu(I18nManager.getText("menu.file"));
158                 setAltKey(fileMenu, "altkey.menu.file");
159                 // Open file
160                 JMenuItem openMenuItem = new JMenuItem(I18nManager.getText("function.open"));
161                 setShortcut(openMenuItem, "shortcut.menu.file.open");
162                 _openFileAction = new ActionListener() {
163                         public void actionPerformed(ActionEvent e) {
164                                 _app.openFile();
165                         }
166                 };
167                 openMenuItem.addActionListener(_openFileAction);
168                 fileMenu.add(openMenuItem);
169                 // import through gpsbabel
170                 JMenuItem importBabelItem = makeMenuItem(FunctionLibrary.FUNCTION_IMPORTBABEL);
171                 fileMenu.add(importBabelItem);
172                 // Add photos
173                 JMenuItem addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
174                 _addPhotoAction = new ActionListener() {
175                         public void actionPerformed(ActionEvent e) {
176                                 _app.addPhotos();
177                         }
178                 };
179                 addPhotosMenuItem.addActionListener(_addPhotoAction);
180                 fileMenu.add(addPhotosMenuItem);
181                 // Add audio clips
182                 JMenuItem addAudioMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_LOAD_AUDIO);
183                 fileMenu.add(addAudioMenuItem);
184                 // recent files
185                 _recentFileMenu = new JMenu(I18nManager.getText("menu.file.recentfiles"));
186                 _recentFileMenu.setEnabled(false);
187                 fileMenu.add(_recentFileMenu);
188                 fileMenu.addSeparator();
189                 // Load from GPS
190                 JMenuItem loadFromGpsMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSLOAD);
191                 setShortcut(loadFromGpsMenuItem, "shortcut.menu.file.load");
192                 fileMenu.add(loadFromGpsMenuItem);
193                 // Send to GPS
194                 _sendGpsItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSSAVE, false);
195                 fileMenu.add(_sendGpsItem);
196                 fileMenu.addSeparator();
197                 // Save
198                 _saveItem = new JMenuItem(I18nManager.getText("menu.file.save"), KeyEvent.VK_S);
199                 setShortcut(_saveItem, "shortcut.menu.file.save");
200                 _saveAction = new ActionListener() {
201                         public void actionPerformed(ActionEvent e) {
202                                 _app.saveFile();
203                         }
204                 };
205                 _saveItem.addActionListener(_saveAction);
206                 _saveItem.setEnabled(false);
207                 fileMenu.add(_saveItem);
208                 // Export - Kml
209                 _exportKmlItem = makeMenuItem(FunctionLibrary.FUNCTION_KMLEXPORT, false);
210                 fileMenu.add(_exportKmlItem);
211                 // Gpx
212                 _exportGpxItem = makeMenuItem(FunctionLibrary.FUNCTION_GPXEXPORT, false);
213                 fileMenu.add(_exportGpxItem);
214                 // Pov
215                 _exportPovItem = makeMenuItem(FunctionLibrary.FUNCTION_POVEXPORT, false);
216                 fileMenu.add(_exportPovItem);
217                 // Svg
218                 _exportSvgItem = makeMenuItem(FunctionLibrary.FUNCTION_SVGEXPORT, false);
219                 fileMenu.add(_exportSvgItem);
220                 fileMenu.addSeparator();
221                 JMenuItem exitMenuItem = new JMenuItem(I18nManager.getText("menu.file.exit"));
222                 exitMenuItem.addActionListener(new ActionListener() {
223                         public void actionPerformed(ActionEvent e) {
224                                 _app.exit();
225                         }
226                 });
227                 fileMenu.add(exitMenuItem);
228                 menubar.add(fileMenu);
229
230                 // Track menu
231                 JMenu trackMenu = new JMenu(I18nManager.getText("menu.track"));
232                 setAltKey(trackMenu, "altkey.menu.track");
233                 _undoItem = new JMenuItem(I18nManager.getText("menu.track.undo"));
234                 setShortcut(_undoItem, "shortcut.menu.track.undo");
235                 _undoAction = new ActionListener() {
236                         public void actionPerformed(ActionEvent e) {
237                                 _app.beginUndo();
238                         }
239                 };
240                 _undoItem.addActionListener(_undoAction);
241                 _undoItem.setEnabled(false);
242                 trackMenu.add(_undoItem);
243                 _clearUndoItem = new JMenuItem(I18nManager.getText("menu.track.clearundo"));
244                 _clearUndoItem.addActionListener(new ActionListener() {
245                         public void actionPerformed(ActionEvent e) {
246                                 _app.clearUndo();
247                         }
248                 });
249                 _clearUndoItem.setEnabled(false);
250                 trackMenu.add(_clearUndoItem);
251                 trackMenu.addSeparator();
252                 _compressItem = makeMenuItem(FunctionLibrary.FUNCTION_COMPRESS, false);
253                 setShortcut(_compressItem, "shortcut.menu.edit.compress");
254                 trackMenu.add(_compressItem);
255                 _markRectangleItem = new JMenuItem(I18nManager.getText("menu.track.markrectangle"));
256                 _markRectangleItem.addActionListener(new ActionListener() {
257                         public void actionPerformed(ActionEvent e) {
258                                 _app.setCurrentMode(App.AppMode.DRAWRECT);
259                                 UpdateMessageBroker.informSubscribers();
260                         }
261                 });
262                 _markRectangleItem.setEnabled(false);
263                 trackMenu.add(_markRectangleItem);
264                 _deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.track.deletemarked"));
265                 _deleteMarkedPointsItem.addActionListener(new ActionListener() {
266                         public void actionPerformed(ActionEvent e) {
267                                 _app.finishCompressTrack();
268                         }
269                 });
270                 _deleteMarkedPointsItem.setEnabled(false);
271                 trackMenu.add(_deleteMarkedPointsItem);
272                 trackMenu.addSeparator();
273                 // Rearrange waypoints
274                 _rearrangeMenu = new JMenu(I18nManager.getText("menu.track.rearrange"));
275                 _rearrangeMenu.setEnabled(false);
276                 JMenuItem  rearrangeStartItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.start"));
277                 rearrangeStartItem.addActionListener(new ActionListener() {
278                         public void actionPerformed(ActionEvent e) {
279                                 FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_START);
280                         }
281                 });
282                 rearrangeStartItem.setEnabled(true);
283                 _rearrangeMenu.add(rearrangeStartItem);
284                 JMenuItem rearrangeEndItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.end"));
285                 rearrangeEndItem.addActionListener(new ActionListener() {
286                         public void actionPerformed(ActionEvent e) {
287                                 FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_END);
288                         }
289                 });
290                 rearrangeEndItem.setEnabled(true);
291                 _rearrangeMenu.add(rearrangeEndItem);
292                 JMenuItem rearrangeNearestItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.nearest"));
293                 rearrangeNearestItem.addActionListener(new ActionListener() {
294                         public void actionPerformed(ActionEvent e) {
295                                 FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_NEAREST);
296                         }
297                 });
298                 rearrangeNearestItem.setEnabled(true);
299                 _rearrangeMenu.add(rearrangeNearestItem);
300                 trackMenu.add(_rearrangeMenu);
301                 // Get gpsies tracks
302                 _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES, false);
303                 trackMenu.add(_getGpsiesItem);
304                 // Upload to gpsies
305                 _uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES, false);
306                 trackMenu.add(_uploadGpsiesItem);
307                 _lookupSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_SRTM, false);
308                 trackMenu.add(_lookupSrtmItem);
309                 _lookupWikipediaItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_WIKIPEDIA, false);
310                 trackMenu.add(_lookupWikipediaItem);
311                 JMenuItem searchWikipediaNamesItem = makeMenuItem(FunctionLibrary.FUNCTION_SEARCH_WIKIPEDIA);
312                 trackMenu.add(searchWikipediaNamesItem);
313                 _downloadOsmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_OSM, false);
314                 trackMenu.add(_downloadOsmItem);
315                 menubar.add(trackMenu);
316
317                 // Range menu
318                 JMenu rangeMenu = new JMenu(I18nManager.getText("menu.range"));
319                 setAltKey(rangeMenu, "altkey.menu.range");
320                 _selectAllItem = new JMenuItem(I18nManager.getText("menu.range.all"));
321                 setShortcut(_selectAllItem, "shortcut.menu.range.all");
322                 _selectAllItem.setEnabled(false);
323                 _selectAllItem.addActionListener(new ActionListener() {
324                         public void actionPerformed(ActionEvent e) {
325                                 _selection.selectRange(0, _track.getNumPoints()-1);
326                         }
327                 });
328                 rangeMenu.add(_selectAllItem);
329                 _selectNoneItem = new JMenuItem(I18nManager.getText("menu.range.none"));
330                 _selectNoneItem.setEnabled(false);
331                 _selectNoneItem.addActionListener(new ActionListener() {
332                         public void actionPerformed(ActionEvent e) {
333                                 _app.selectNone();
334                         }
335                 });
336                 rangeMenu.add(_selectNoneItem);
337                 rangeMenu.addSeparator();
338                 _selectStartItem = new JMenuItem(I18nManager.getText("menu.range.start"));
339                 _selectStartItem.setEnabled(false);
340                 _selectStartAction = new ActionListener() {
341                         public void actionPerformed(ActionEvent e) {
342                                 _selection.selectRangeStart();
343                         }
344                 };
345                 _selectStartItem.addActionListener(_selectStartAction);
346                 rangeMenu.add(_selectStartItem);
347                 _selectEndItem = new JMenuItem(I18nManager.getText("menu.range.end"));
348                 _selectEndItem.setEnabled(false);
349                 _selectEndAction = new ActionListener() {
350                         public void actionPerformed(ActionEvent e) {
351                                 _selection.selectRangeEnd();
352                         }
353                 };
354                 _selectEndItem.addActionListener(_selectEndAction);
355                 rangeMenu.add(_selectEndItem);
356                 rangeMenu.addSeparator();
357                 _deleteRangeItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_RANGE, false);
358                 rangeMenu.add(_deleteRangeItem);
359                 _cropTrackItem = makeMenuItem(FunctionLibrary.FUNCTION_CROP_TRACK, false);
360                 rangeMenu.add(_cropTrackItem);
361                 _reverseItem = new JMenuItem(I18nManager.getText("menu.range.reverse"));
362                 _reverseItem.addActionListener(new ActionListener() {
363                         public void actionPerformed(ActionEvent e) {
364                                 _app.reverseRange();
365                         }
366                 });
367                 _reverseItem.setEnabled(false);
368                 rangeMenu.add(_reverseItem);
369                 _addTimeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_TIME_OFFSET, false);
370                 rangeMenu.add(_addTimeOffsetItem);
371                 _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET, false);
372                 rangeMenu.add(_addAltitudeOffsetItem);
373                 _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.range.mergetracksegments"));
374                 _mergeSegmentsItem.addActionListener(new ActionListener() {
375                         public void actionPerformed(ActionEvent e) {
376                                 _app.mergeTrackSegments();
377                         }
378                 });
379                 _mergeSegmentsItem.setEnabled(false);
380                 rangeMenu.add(_mergeSegmentsItem);
381                 _deleteFieldValuesItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_FIELD_VALUES, false);
382                 rangeMenu.add(_deleteFieldValuesItem);
383                 rangeMenu.addSeparator();
384                 _interpolateItem = makeMenuItem(FunctionLibrary.FUNCTION_INTERPOLATE, 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(MAPSERVER_CHANGED);
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("function.deleterange"));
765                 _deleteRangeButton.addActionListener(new ActionListener() {
766                         public void actionPerformed(ActionEvent arg0) {
767                                 FunctionLibrary.FUNCTION_DELETE_RANGE.begin();
768                         }
769                 });
770                 _deleteRangeButton.setEnabled(false);
771                 toolbar.add(_deleteRangeButton);
772                 // Cut and move
773                 _cutAndMoveButton = new JButton(IconManager.getImageIcon(IconManager.CUT_AND_MOVE));
774                 _cutAndMoveButton.setToolTipText(I18nManager.getText("menu.range.cutandmove"));
775                 _cutAndMoveButton.addActionListener(new ActionListener() {
776                         public void actionPerformed(ActionEvent arg0) {
777                                 _app.cutAndMoveSelection();
778                         }
779                 });
780                 _cutAndMoveButton.setEnabled(false);
781                 toolbar.add(_cutAndMoveButton);
782                 // Select start, end
783                 _selectStartButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_START));
784                 _selectStartButton.setToolTipText(I18nManager.getText("menu.range.start"));
785                 _selectStartButton.addActionListener(_selectStartAction);
786                 _selectStartButton.setEnabled(false);
787                 toolbar.add(_selectStartButton);
788                 _selectEndButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_END));
789                 _selectEndButton.setToolTipText(I18nManager.getText("menu.range.end"));
790                 _selectEndButton.addActionListener(_selectEndAction);
791                 _selectEndButton.setEnabled(false);
792                 toolbar.add(_selectEndButton);
793                 // Connect to point
794                 _connectButton = new JButton(IconManager.getImageIcon(IconManager.CONNECT_PHOTO));
795                 _connectButton.setToolTipText(I18nManager.getText(FunctionLibrary.FUNCTION_CONNECT_TO_POINT.getNameKey()));
796                 _connectButton.addActionListener(new ActionListener() {
797                         public void actionPerformed(ActionEvent arg0) {
798                                 FunctionLibrary.FUNCTION_CONNECT_TO_POINT.begin();
799                         }
800                 });
801                 _connectButton.setEnabled(false);
802                 toolbar.add(_connectButton);
803                 // finish off
804                 toolbar.setFloatable(false);
805                 return toolbar;
806         }
807
808
809         /**
810          * Method to update menu when file loaded
811          */
812         public void informFileLoaded()
813         {
814                 // save, undo, delete enabled
815                 _sendGpsItem.setEnabled(true);
816                 _saveItem.setEnabled(true);
817                 _undoItem.setEnabled(true);
818                 _compressItem.setEnabled(true);
819                 _deleteMarkedPointsItem.setEnabled(false);
820         }
821
822
823         /**
824          * @see tim.prune.DataSubscriber#dataUpdated(tim.prune.data.Track)
825          */
826         public void dataUpdated(byte inUpdateType)
827         {
828                 boolean hasData = (_track != null && _track.getNumPoints() > 0);
829                 // set functions which require data
830                 _sendGpsItem.setEnabled(hasData);
831                 _saveItem.setEnabled(hasData);
832                 _saveButton.setEnabled(hasData);
833                 _exportKmlItem.setEnabled(hasData);
834                 _exportGpxItem.setEnabled(hasData);
835                 _exportPovItem.setEnabled(hasData);
836                 _exportSvgItem.setEnabled(hasData);
837                 _compressItem.setEnabled(hasData);
838                 _markRectangleItem.setEnabled(hasData);
839                 _deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints());
840                 _rearrangeMenu.setEnabled(hasData && _track.hasTrackPoints() && _track.hasWaypoints());
841                 _selectAllItem.setEnabled(hasData);
842                 _selectNoneItem.setEnabled(hasData);
843                 _show3dItem.setEnabled(hasData);
844                 _chartItem.setEnabled(hasData);
845                 _browserMapMenu.setEnabled(hasData);
846                 _distanceItem.setEnabled(hasData);
847                 _getGpsiesItem.setEnabled(hasData);
848                 _uploadGpsiesItem.setEnabled(hasData && _track.hasTrackPoints());
849                 _lookupSrtmItem.setEnabled(hasData);
850                 _lookupWikipediaItem.setEnabled(hasData);
851                 _downloadOsmItem.setEnabled(hasData);
852                 _findWaypointItem.setEnabled(hasData && _track.hasWaypoints());
853                 // is undo available?
854                 boolean hasUndo = !_app.getUndoStack().isEmpty();
855                 _undoItem.setEnabled(hasUndo);
856                 _undoButton.setEnabled(hasUndo);
857                 _clearUndoItem.setEnabled(hasUndo);
858                 // is there a current point?
859                 boolean hasPoint = (hasData && _selection.getCurrentPointIndex() >= 0);
860                 _editPointItem.setEnabled(hasPoint);
861                 _editPointButton.setEnabled(hasPoint);
862                 _editWaypointNameItem.setEnabled(hasPoint);
863                 _deletePointItem.setEnabled(hasPoint);
864                 _deletePointButton.setEnabled(hasPoint);
865                 _selectStartItem.setEnabled(hasPoint);
866                 _selectStartButton.setEnabled(hasPoint);
867                 _selectEndItem.setEnabled(hasPoint);
868                 _selectEndButton.setEnabled(hasPoint);
869                 _duplicatePointItem.setEnabled(hasPoint);
870                 // are there any photos?
871                 boolean anyPhotos = _app.getTrackInfo().getPhotoList().getNumPhotos() > 0;
872                 _saveExifItem.setEnabled(anyPhotos && _app.getTrackInfo().getPhotoList().hasMediaWithFile());
873                 // is there a current photo, audio?
874                 Photo currentPhoto = _app.getTrackInfo().getCurrentPhoto();
875                 boolean hasPhoto = currentPhoto != null;
876                 AudioClip currentAudio = _app.getTrackInfo().getCurrentAudio();
877                 boolean hasAudio = currentAudio != null;
878                 // connect is available if (photo/audio) and point selected, and media has no point
879                 boolean connectAvailable = (hasPhoto && hasPoint && currentPhoto.getDataPoint() == null)
880                         || (hasAudio && hasPoint && currentAudio.getDataPoint() == null);
881                 _connectPhotoItem.setEnabled(hasPhoto && hasPoint && currentPhoto.getDataPoint() == null);
882                 _connectButton.setEnabled(connectAvailable);
883                 _disconnectPhotoItem.setEnabled(hasPhoto && currentPhoto.getDataPoint() != null);
884                 _correlatePhotosItem.setEnabled(anyPhotos && hasData);
885                 _rearrangePhotosItem.setEnabled(anyPhotos && hasData && _track.getNumPoints() > 1);
886                 _removePhotoItem.setEnabled(hasPhoto);
887                 _rotatePhotoLeft.setEnabled(hasPhoto);
888                 _rotatePhotoRight.setEnabled(hasPhoto);
889                 _photoPopupItem.setEnabled(hasPhoto);
890                 _ignoreExifThumb.setEnabled(hasPhoto && currentPhoto.getExifThumbnail() != null);
891                 _selectNoPhotoItem.setEnabled(hasPhoto);
892                 boolean anyAudios = _app.getTrackInfo().getAudioList().getNumAudios() > 0;
893                 _selectNoAudioItem.setEnabled(hasAudio);
894                 _removeAudioItem.setEnabled(hasAudio);
895                 _connectAudioItem.setEnabled(hasAudio && hasPoint && currentAudio.getDataPoint() == null);
896                 _disconnectAudioItem.setEnabled(hasAudio && _app.getTrackInfo().getCurrentAudio().getDataPoint() != null);
897                 _correlateAudiosItem.setEnabled(anyAudios && hasData);
898                 // is there a current range?
899                 boolean hasRange = (hasData && _selection.hasRangeSelected());
900                 _deleteRangeItem.setEnabled(hasRange);
901                 _deleteRangeButton.setEnabled(hasRange);
902                 _cropTrackItem.setEnabled(hasRange);
903                 _interpolateItem.setEnabled(hasRange);
904                 _averageItem.setEnabled(hasRange);
905                 _mergeSegmentsItem.setEnabled(hasRange);
906                 _reverseItem.setEnabled(hasRange);
907                 _addTimeOffsetItem.setEnabled(hasRange);
908                 _addAltitudeOffsetItem.setEnabled(hasRange);
909                 _convertNamesToTimesItem.setEnabled(hasRange && _track.hasWaypoints());
910                 _deleteFieldValuesItem.setEnabled(hasRange);
911                 _fullRangeDetailsItem.setEnabled(hasRange);
912                 // Is the currently selected point outside the current range?
913                 boolean canCutAndMove = hasRange && hasPoint &&
914                         (_selection.getCurrentPointIndex() < _selection.getStart()
915                         || _selection.getCurrentPointIndex() > (_selection.getEnd()+1));
916                 _cutAndMoveItem.setEnabled(canCutAndMove);
917                 _cutAndMoveButton.setEnabled(canCutAndMove);
918                 // Has the map been switched on/off?
919                 boolean mapsOn = Config.getConfigBoolean(Config.KEY_SHOW_MAP);
920                 if (_mapCheckbox.isSelected() != mapsOn) {
921                         _mapCheckbox.setSelected(mapsOn);
922                 }
923                 // Are there any recently-used files?
924                 RecentFileList rfl = Config.getRecentFileList();
925                 final int numRecentFiles = rfl.getNumEntries();
926                 final boolean hasRecentFiles = numRecentFiles > 0;
927                 _recentFileMenu.setEnabled(hasRecentFiles);
928                 if (hasRecentFiles)
929                 {
930                         int numItems = _recentFileMenu.getMenuComponentCount();
931                         if (numItems == numRecentFiles)
932                         {
933                                 // Right number of items, just change texts
934                                 for (int i=0; i<numRecentFiles; i++)
935                                 {
936                                         JMenuItem item = _recentFileMenu.getItem(i);
937                                         item.setText(rfl.getFile(i)==null?"":rfl.getFile(i).getFile().getName());
938                                         item.setToolTipText(rfl.getFile(i)==null?null:rfl.getFile(i).getFile().getAbsolutePath());
939                                 }
940                         }
941                         else
942                         {
943                                 // Rebuild menus
944                                 _recentFileMenu.removeAll();
945                                 for (int i=0; i<rfl.getSize(); i++)
946                                 {
947                                         RecentFile rf = rfl.getFile(i);
948                                         if (rf != null && rf.isValid())
949                                         {
950                                                 JMenuItem menuItem = new JMenuItem(rf.getFile().getName());
951                                                 menuItem.setToolTipText(rf.getFile().getAbsolutePath());
952                                                 menuItem.addActionListener(new RecentFileTrigger(_app, i));
953                                                 _recentFileMenu.add(menuItem);
954                                         }
955                                 }
956                         }
957                 }
958         }
959
960
961         /**
962          * Ignore action completed signals
963          * @see tim.prune.DataSubscriber#actionCompleted(java.lang.String)
964          */
965         public void actionCompleted(String inMessage)
966         {}
967 }