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