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