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