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