3 import java.awt.Toolkit;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.KeyEvent;
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;
17 import tim.prune.DataSubscriber;
18 import tim.prune.FunctionLibrary;
19 import tim.prune.GenericFunction;
20 import tim.prune.I18nManager;
21 import tim.prune.UpdateMessageBroker;
22 import tim.prune.config.Config;
23 import tim.prune.data.AudioClip;
24 import tim.prune.data.DataPoint;
25 import tim.prune.data.Field;
26 import tim.prune.data.Photo;
27 import tim.prune.data.RecentFile;
28 import tim.prune.data.RecentFileList;
29 import tim.prune.data.Selection;
30 import tim.prune.data.Track;
31 import tim.prune.data.TrackInfo;
32 import tim.prune.function.ChooseSingleParameter;
33 import tim.prune.function.browser.UrlGenerator;
36 * Class to manage the menu bar and tool bar,
37 * including enabling and disabling the items
39 public class MenuManager implements DataSubscriber
41 private App _app = null;
42 private Track _track = null;
43 private Selection _selection = null;
45 // Menu items which need enabling/disabling
46 private JMenuItem _sendGpsItem = null;
47 private JMenuItem _saveItem = null;
48 private JMenuItem _exportKmlItem = null;
49 private JMenuItem _exportGpxItem = null;
50 private JMenuItem _exportPovItem = null;
51 private JMenuItem _exportSvgItem = null;
52 private JMenuItem _exportImageItem = null;
53 private JMenu _recentFileMenu = null;
54 private JMenuItem _undoItem = null;
55 private JMenuItem _clearUndoItem = null;
56 private JMenuItem _editPointItem = null;
57 private JMenuItem _editWaypointNameItem = null;
58 private JMenuItem _deletePointItem = null;
59 private JMenuItem _deleteRangeItem = null;
60 private JMenuItem _cropTrackItem = null;
61 private JMenuItem _compressItem = null;
62 private JMenuItem _markRectangleItem = null;
63 private JMenuItem _deleteMarkedPointsItem = null;
64 private JMenuItem _deleteByDateItem = null;
65 private JMenuItem _interpolateItem = null;
66 private JMenuItem _averageItem = null;
67 private JMenuItem _selectAllItem = null;
68 private JMenuItem _selectNoneItem = null;
69 private JMenuItem _selectSegmentItem = null;
70 private JMenuItem _selectStartItem = null;
71 private JMenuItem _selectEndItem = null;
72 private JMenuItem _findWaypointItem = null;
73 private JMenuItem _duplicatePointItem = null;
74 private JMenuItem _reverseItem = null;
75 private JMenuItem _addTimeOffsetItem = null;
76 private JMenuItem _addAltitudeOffsetItem = null;
77 private JMenuItem _mergeSegmentsItem = null;
78 private JMenuItem _rearrangeWaypointsItem = null;
79 private JMenuItem _splitSegmentsItem = null;
80 private JMenuItem _sewSegmentsItem = null;
81 private JMenuItem _cutAndMoveItem = null;
82 private JMenuItem _convertNamesToTimesItem = null;
83 private JMenuItem _deleteFieldValuesItem = null;
84 private JCheckBoxMenuItem _mapCheckbox = null;
85 private JMenuItem _show3dItem = null;
86 private JMenu _browserMapMenu = null;
87 private JMenuItem _chartItem = null;
88 private JMenuItem _getGpsiesItem = null;
89 private JMenuItem _uploadGpsiesItem = null;
90 private JMenuItem _lookupSrtmItem = null;
91 private JMenuItem _downloadSrtmItem = null;
92 private JMenuItem _lookupWikipediaItem = null;
93 private JMenuItem _downloadOsmItem = null;
94 private JMenuItem _getWeatherItem = null;
95 private JMenuItem _distanceItem = null;
96 private JMenuItem _fullRangeDetailsItem = null;
97 private JMenuItem _estimateTimeItem = null;
98 private JMenuItem _learnEstimationParams = null;
99 private JMenuItem _saveExifItem = null;
100 private JMenuItem _photoPopupItem = null;
101 private JMenuItem _selectNoPhotoItem = null;
102 private JMenuItem _connectPhotoItem = null;
103 private JMenuItem _removePhotoItem = null;
104 private JMenuItem _disconnectPhotoItem = null;
105 private JMenuItem _correlatePhotosItem = null;
106 private JMenuItem _rearrangePhotosItem = null;
107 private JMenuItem _rotatePhotoLeft = null;
108 private JMenuItem _rotatePhotoRight = null;
109 private JMenuItem _ignoreExifThumb = null;
110 private JMenuItem _connectAudioItem = null;
111 private JMenuItem _disconnectAudioItem = null;
112 private JMenuItem _removeAudioItem = null;
113 private JMenuItem _correlateAudiosItem = null;
114 private JMenuItem _selectNoAudioItem = null;
115 private JCheckBoxMenuItem _onlineCheckbox = null;
116 private JCheckBoxMenuItem _autosaveSettingsCheckbox = null;
118 // ActionListeners for reuse by menu and toolbar
119 private ActionListener _openFileAction = null;
120 private ActionListener _addPhotoAction = null;
121 private ActionListener _saveAction = null;
122 private ActionListener _undoAction = null;
123 private ActionListener _editPointAction = null;
124 private ActionListener _deletePointAction = null;
125 private ActionListener _selectStartAction = null;
126 private ActionListener _selectEndAction = null;
128 // Toolbar buttons which need enabling/disabling
129 private JButton _saveButton = null;
130 private JButton _undoButton = null;
131 private JButton _editPointButton = null;
132 private JButton _deletePointButton = null;
133 private JButton _deleteRangeButton = null;
134 private JButton _cutAndMoveButton = null;
135 private JButton _selectStartButton = null;
136 private JButton _selectEndButton = null;
137 private JButton _connectButton = null;
139 /** Array of key events */
140 private static final int[] KEY_EVENTS = {
141 KeyEvent.VK_A, KeyEvent.VK_B, KeyEvent.VK_C, KeyEvent.VK_D, KeyEvent.VK_E,
142 KeyEvent.VK_F, KeyEvent.VK_G, KeyEvent.VK_H, KeyEvent.VK_I, KeyEvent.VK_J,
143 KeyEvent.VK_K, KeyEvent.VK_L, KeyEvent.VK_M, KeyEvent.VK_N, KeyEvent.VK_O,
144 KeyEvent.VK_P, KeyEvent.VK_Q, KeyEvent.VK_R, KeyEvent.VK_S, KeyEvent.VK_T,
145 KeyEvent.VK_U, KeyEvent.VK_V, KeyEvent.VK_W, KeyEvent.VK_X, KeyEvent.VK_Y, KeyEvent.VK_Z};
150 * @param inApp application to call on menu actions
151 * @param inTrackInfo track info object
153 public MenuManager(App inApp, TrackInfo inTrackInfo)
156 _track = inTrackInfo.getTrack();
157 _selection = inTrackInfo.getSelection();
162 * Create a JMenuBar containing all menu items
165 public JMenuBar createMenuBar()
167 JMenuBar menubar = new JMenuBar();
168 JMenu fileMenu = new JMenu(I18nManager.getText("menu.file"));
169 setAltKey(fileMenu, "altkey.menu.file");
171 JMenuItem openMenuItem = new JMenuItem(I18nManager.getText("function.open"));
172 setShortcut(openMenuItem, "shortcut.menu.file.open");
173 _openFileAction = new ActionListener() {
174 public void actionPerformed(ActionEvent e) {
178 openMenuItem.addActionListener(_openFileAction);
179 fileMenu.add(openMenuItem);
180 // import through gpsbabel
181 JMenuItem importBabelItem = makeMenuItem(FunctionLibrary.FUNCTION_IMPORTBABEL);
182 fileMenu.add(importBabelItem);
184 JMenuItem addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
185 _addPhotoAction = new ActionListener() {
186 public void actionPerformed(ActionEvent e) {
190 addPhotosMenuItem.addActionListener(_addPhotoAction);
191 fileMenu.add(addPhotosMenuItem);
193 JMenuItem addAudioMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_LOAD_AUDIO);
194 fileMenu.add(addAudioMenuItem);
196 _recentFileMenu = new JMenu(I18nManager.getText("menu.file.recentfiles"));
197 _recentFileMenu.setEnabled(false);
198 fileMenu.add(_recentFileMenu);
199 fileMenu.addSeparator();
201 JMenuItem loadFromGpsMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSLOAD);
202 setShortcut(loadFromGpsMenuItem, "shortcut.menu.file.load");
203 fileMenu.add(loadFromGpsMenuItem);
205 _sendGpsItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSSAVE, false);
206 fileMenu.add(_sendGpsItem);
207 fileMenu.addSeparator();
209 _saveItem = new JMenuItem(I18nManager.getText("menu.file.save"), KeyEvent.VK_S);
210 setShortcut(_saveItem, "shortcut.menu.file.save");
211 _saveAction = new ActionListener() {
212 public void actionPerformed(ActionEvent e) {
216 _saveItem.addActionListener(_saveAction);
217 _saveItem.setEnabled(false);
218 fileMenu.add(_saveItem);
220 _exportKmlItem = makeMenuItem(FunctionLibrary.FUNCTION_KMLEXPORT, false);
221 fileMenu.add(_exportKmlItem);
223 _exportGpxItem = makeMenuItem(FunctionLibrary.FUNCTION_GPXEXPORT, false);
224 fileMenu.add(_exportGpxItem);
226 _exportPovItem = makeMenuItem(FunctionLibrary.FUNCTION_POVEXPORT, false);
227 fileMenu.add(_exportPovItem);
229 _exportSvgItem = makeMenuItem(FunctionLibrary.FUNCTION_SVGEXPORT, false);
230 fileMenu.add(_exportSvgItem);
232 _exportImageItem = makeMenuItem(FunctionLibrary.FUNCTION_IMAGEEXPORT, false);
233 fileMenu.add(_exportImageItem);
234 fileMenu.addSeparator();
236 JMenuItem exitMenuItem = new JMenuItem(I18nManager.getText("menu.file.exit"));
237 exitMenuItem.addActionListener(new ActionListener() {
238 public void actionPerformed(ActionEvent e) {
242 fileMenu.add(exitMenuItem);
243 menubar.add(fileMenu);
245 ////////////////////////////////////////////////////
247 JMenu onlineMenu = new JMenu(I18nManager.getText("menu.online"));
248 setAltKey(onlineMenu, "altkey.menu.online");
250 _lookupSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_SRTM, false);
251 onlineMenu.add(_lookupSrtmItem);
252 _downloadSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_SRTM, false);
253 onlineMenu.add(_downloadSrtmItem);
255 _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES, false);
256 onlineMenu.add(_getGpsiesItem);
258 _uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES, false);
259 onlineMenu.add(_uploadGpsiesItem);
260 onlineMenu.addSeparator();
261 _lookupWikipediaItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_WIKIPEDIA, false);
262 onlineMenu.add(_lookupWikipediaItem);
263 JMenuItem searchWikipediaNamesItem = makeMenuItem(FunctionLibrary.FUNCTION_SEARCH_WIKIPEDIA);
264 onlineMenu.add(searchWikipediaNamesItem);
265 _downloadOsmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_OSM, false);
266 onlineMenu.add(_downloadOsmItem);
267 onlineMenu.addSeparator();
268 _getWeatherItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_WEATHER_FORECAST, false);
269 onlineMenu.add(_getWeatherItem);
270 menubar.add(onlineMenu);
272 ////////////////////////////////////////////////////
274 JMenu trackMenu = new JMenu(I18nManager.getText("menu.track"));
275 setAltKey(trackMenu, "altkey.menu.track");
276 _undoItem = new JMenuItem(I18nManager.getText("menu.track.undo"));
277 setShortcut(_undoItem, "shortcut.menu.track.undo");
278 _undoAction = new ActionListener() {
279 public void actionPerformed(ActionEvent e) {
283 _undoItem.addActionListener(_undoAction);
284 _undoItem.setEnabled(false);
285 trackMenu.add(_undoItem);
286 _clearUndoItem = new JMenuItem(I18nManager.getText("menu.track.clearundo"));
287 _clearUndoItem.addActionListener(new ActionListener() {
288 public void actionPerformed(ActionEvent e) {
292 _clearUndoItem.setEnabled(false);
293 trackMenu.add(_clearUndoItem);
294 trackMenu.addSeparator();
295 _compressItem = makeMenuItem(FunctionLibrary.FUNCTION_COMPRESS, false);
296 setShortcut(_compressItem, "shortcut.menu.edit.compress");
297 trackMenu.add(_compressItem);
298 _markRectangleItem = new JMenuItem(I18nManager.getText("menu.track.markrectangle"));
299 _markRectangleItem.addActionListener(new ActionListener() {
300 public void actionPerformed(ActionEvent e) {
301 _app.setCurrentMode(App.AppMode.DRAWRECT);
302 UpdateMessageBroker.informSubscribers();
305 _markRectangleItem.setEnabled(false);
306 trackMenu.add(_markRectangleItem);
307 _deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.track.deletemarked"));
308 _deleteMarkedPointsItem.addActionListener(new ActionListener() {
309 public void actionPerformed(ActionEvent e) {
310 _app.finishCompressTrack();
313 _deleteMarkedPointsItem.setEnabled(false);
314 trackMenu.add(_deleteMarkedPointsItem);
315 _deleteByDateItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_BY_DATE, false);
316 trackMenu.add(_deleteByDateItem);
317 trackMenu.addSeparator();
318 // Rearrange waypoints
319 _rearrangeWaypointsItem = makeMenuItem(FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS, false);
320 trackMenu.add(_rearrangeWaypointsItem);
321 // Split track segments
322 _splitSegmentsItem = makeMenuItem(FunctionLibrary.FUNCTION_SPLIT_SEGMENTS, false);
323 trackMenu.add(_splitSegmentsItem);
324 // Sew track segments
325 _sewSegmentsItem = makeMenuItem(FunctionLibrary.FUNCTION_SEW_SEGMENTS, false);
326 trackMenu.add(_sewSegmentsItem);
327 trackMenu.addSeparator();
328 _learnEstimationParams = makeMenuItem(FunctionLibrary.FUNCTION_LEARN_ESTIMATION_PARAMS, false);
329 trackMenu.add(_learnEstimationParams);
330 menubar.add(trackMenu);
333 JMenu rangeMenu = new JMenu(I18nManager.getText("menu.range"));
334 setAltKey(rangeMenu, "altkey.menu.range");
335 _selectAllItem = new JMenuItem(I18nManager.getText("menu.range.all"));
336 setShortcut(_selectAllItem, "shortcut.menu.range.all");
337 _selectAllItem.setEnabled(false);
338 _selectAllItem.addActionListener(new ActionListener() {
339 public void actionPerformed(ActionEvent e) {
340 _selection.selectRange(0, _track.getNumPoints()-1);
343 rangeMenu.add(_selectAllItem);
344 _selectNoneItem = new JMenuItem(I18nManager.getText("menu.range.none"));
345 _selectNoneItem.setEnabled(false);
346 _selectNoneItem.addActionListener(new ActionListener() {
347 public void actionPerformed(ActionEvent e) {
351 rangeMenu.add(_selectNoneItem);
352 _selectSegmentItem = makeMenuItem(FunctionLibrary.FUNCTION_SELECT_SEGMENT);
353 rangeMenu.add(_selectSegmentItem);
354 rangeMenu.addSeparator();
355 _selectStartItem = new JMenuItem(I18nManager.getText("menu.range.start"));
356 _selectStartItem.setEnabled(false);
357 _selectStartAction = new ActionListener() {
358 public void actionPerformed(ActionEvent e) {
359 _selection.selectRangeStart();
362 _selectStartItem.addActionListener(_selectStartAction);
363 rangeMenu.add(_selectStartItem);
364 _selectEndItem = new JMenuItem(I18nManager.getText("menu.range.end"));
365 _selectEndItem.setEnabled(false);
366 _selectEndAction = new ActionListener() {
367 public void actionPerformed(ActionEvent e) {
368 _selection.selectRangeEnd();
371 _selectEndItem.addActionListener(_selectEndAction);
372 rangeMenu.add(_selectEndItem);
373 rangeMenu.addSeparator();
374 _deleteRangeItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_RANGE, false);
375 rangeMenu.add(_deleteRangeItem);
376 _cropTrackItem = makeMenuItem(FunctionLibrary.FUNCTION_CROP_TRACK, false);
377 rangeMenu.add(_cropTrackItem);
378 _reverseItem = new JMenuItem(I18nManager.getText("menu.range.reverse"));
379 _reverseItem.addActionListener(new ActionListener() {
380 public void actionPerformed(ActionEvent e) {
384 _reverseItem.setEnabled(false);
385 rangeMenu.add(_reverseItem);
386 _addTimeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_TIME_OFFSET, false);
387 rangeMenu.add(_addTimeOffsetItem);
388 _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET, false);
389 rangeMenu.add(_addAltitudeOffsetItem);
390 _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.range.mergetracksegments"));
391 _mergeSegmentsItem.addActionListener(new ActionListener() {
392 public void actionPerformed(ActionEvent e) {
393 _app.mergeTrackSegments();
396 _mergeSegmentsItem.setEnabled(false);
397 rangeMenu.add(_mergeSegmentsItem);
398 _deleteFieldValuesItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_FIELD_VALUES, false);
399 rangeMenu.add(_deleteFieldValuesItem);
400 rangeMenu.addSeparator();
401 _interpolateItem = makeMenuItem(new ChooseSingleParameter(_app, FunctionLibrary.FUNCTION_INTERPOLATE), false);
402 rangeMenu.add(_interpolateItem);
403 _averageItem = new JMenuItem(I18nManager.getText("menu.range.average"));
404 _averageItem.addActionListener(new ActionListener() {
405 public void actionPerformed(ActionEvent e) {
406 _app.averageSelection();
409 _averageItem.setEnabled(false);
410 rangeMenu.add(_averageItem);
411 _cutAndMoveItem = new JMenuItem(I18nManager.getText("menu.range.cutandmove"));
412 _cutAndMoveItem.addActionListener(new ActionListener() {
413 public void actionPerformed(ActionEvent e)
415 _app.cutAndMoveSelection();
418 _cutAndMoveItem.setEnabled(false);
419 rangeMenu.add(_cutAndMoveItem);
420 _convertNamesToTimesItem = makeMenuItem(FunctionLibrary.FUNCTION_CONVERT_NAMES_TO_TIMES, false);
421 rangeMenu.add(_convertNamesToTimesItem);
422 menubar.add(rangeMenu);
425 JMenu pointMenu = new JMenu(I18nManager.getText("menu.point"));
426 setAltKey(pointMenu, "altkey.menu.point");
427 _editPointItem = new JMenuItem(I18nManager.getText("menu.point.editpoint"));
428 _editPointAction = new ActionListener() {
429 public void actionPerformed(ActionEvent e) {
430 _app.editCurrentPoint();
433 _editPointItem.addActionListener(_editPointAction);
434 _editPointItem.setEnabled(false);
435 pointMenu.add(_editPointItem);
436 _editWaypointNameItem = makeMenuItem(FunctionLibrary.FUNCTION_EDIT_WAYPOINT_NAME, false);
437 pointMenu.add(_editWaypointNameItem);
438 _deletePointItem = new JMenuItem(I18nManager.getText("menu.point.deletepoint"));
439 _deletePointAction = new ActionListener() {
440 public void actionPerformed(ActionEvent e) {
441 _app.deleteCurrentPoint();
444 _deletePointItem.addActionListener(_deletePointAction);
445 _deletePointItem.setEnabled(false);
446 _deletePointItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
447 pointMenu.add(_deletePointItem);
448 pointMenu.addSeparator();
450 _findWaypointItem = makeMenuItem(FunctionLibrary.FUNCTION_FIND_WAYPOINT, false);
451 pointMenu.add(_findWaypointItem);
452 // duplicate current point
453 _duplicatePointItem = makeMenuItem(FunctionLibrary.FUNCTION_DUPLICATE_POINT, false);
454 pointMenu.add(_duplicatePointItem);
455 // paste coordinates function
456 JMenuItem pasteCoordsItem = makeMenuItem(FunctionLibrary.FUNCTION_PASTE_COORDINATES);
457 pointMenu.add(pasteCoordsItem);
458 menubar.add(pointMenu);
461 JMenu viewMenu = new JMenu(I18nManager.getText("menu.view"));
462 setAltKey(viewMenu, "altkey.menu.view");
463 // Turn map display on/off
464 _mapCheckbox = new JCheckBoxMenuItem(
465 I18nManager.getText("menu.map.showmap"), false);
466 _mapCheckbox.addActionListener(new ActionListener() {
467 public void actionPerformed(ActionEvent e) {
468 Config.setConfigBoolean(Config.KEY_SHOW_MAP, _mapCheckbox.isSelected());
469 UpdateMessageBroker.informSubscribers(MAPSERVER_CHANGED);
472 viewMenu.add(_mapCheckbox);
473 // Turn off the sidebars
474 JCheckBoxMenuItem sidebarsCheckbox = new JCheckBoxMenuItem(I18nManager.getText("menu.view.showsidebars"));
475 sidebarsCheckbox.setSelected(true);
476 sidebarsCheckbox.addActionListener(new ActionListener() {
477 public void actionPerformed(ActionEvent e) {
478 _app.toggleSidebars();
481 sidebarsCheckbox.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0)); // shortcut F11
482 viewMenu.add(sidebarsCheckbox);
484 _show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D, false);
485 viewMenu.add(_show3dItem);
487 _browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
488 _browserMapMenu.setEnabled(false);
489 JMenuItem googleMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.google"));
490 googleMapsItem.addActionListener(new ActionListener() {
491 public void actionPerformed(ActionEvent e) {
492 _app.showExternalMap(UrlGenerator.MAP_SOURCE_GOOGLE);
495 _browserMapMenu.add(googleMapsItem);
496 JMenuItem openMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.openstreetmap"));
497 openMapsItem.addActionListener(new ActionListener() {
498 public void actionPerformed(ActionEvent e) {
499 _app.showExternalMap(UrlGenerator.MAP_SOURCE_OSM);
502 _browserMapMenu.add(openMapsItem);
503 JMenuItem mapquestMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.mapquest"));
504 mapquestMapsItem.addActionListener(new ActionListener() {
505 public void actionPerformed(ActionEvent e) {
506 _app.showExternalMap(UrlGenerator.MAP_SOURCE_MAPQUEST);
509 _browserMapMenu.add(mapquestMapsItem);
510 JMenuItem yahooMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.yahoo"));
511 yahooMapsItem.addActionListener(new ActionListener() {
512 public void actionPerformed(ActionEvent e) {
513 _app.showExternalMap(UrlGenerator.MAP_SOURCE_YAHOO);
516 _browserMapMenu.add(yahooMapsItem);
517 JMenuItem bingMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.bing"));
518 bingMapsItem.addActionListener(new ActionListener() {
519 public void actionPerformed(ActionEvent e) {
520 _app.showExternalMap(UrlGenerator.MAP_SOURCE_BING);
523 _browserMapMenu.add(bingMapsItem);
524 viewMenu.add(_browserMapMenu);
526 _chartItem = makeMenuItem(FunctionLibrary.FUNCTION_CHARTS, false);
527 viewMenu.add(_chartItem);
528 viewMenu.addSeparator();
530 _distanceItem = makeMenuItem(FunctionLibrary.FUNCTION_DISTANCES, false);
531 viewMenu.add(_distanceItem);
532 // full range details
533 _fullRangeDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_RANGE_DETAILS, false);
534 viewMenu.add(_fullRangeDetailsItem);
536 _estimateTimeItem = makeMenuItem(FunctionLibrary.FUNCTION_ESTIMATE_TIME, false);
537 viewMenu.add(_estimateTimeItem);
538 menubar.add(viewMenu);
541 JMenu photoMenu = new JMenu(I18nManager.getText("menu.photo"));
542 setAltKey(photoMenu, "altkey.menu.photo");
543 addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
544 addPhotosMenuItem.addActionListener(_addPhotoAction);
545 photoMenu.add(addPhotosMenuItem);
546 _saveExifItem = new JMenuItem(I18nManager.getText("menu.photo.saveexif"));
547 _saveExifItem.addActionListener(new ActionListener() {
548 public void actionPerformed(ActionEvent e) {
552 _saveExifItem.setEnabled(false);
553 photoMenu.add(_saveExifItem);
554 // Deselect current photo
555 _selectNoPhotoItem = new JMenuItem(I18nManager.getText("menu.range.none"));
556 _selectNoPhotoItem.setEnabled(false);
557 _selectNoPhotoItem.addActionListener(new ActionListener() {
558 public void actionPerformed(ActionEvent e) {
559 _app.getTrackInfo().selectPhoto(-1);
562 photoMenu.add(_selectNoPhotoItem);
563 photoMenu.addSeparator();
564 _connectPhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_CONNECT_TO_POINT, false);
565 photoMenu.add(_connectPhotoItem);
567 _disconnectPhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_DISCONNECT_PHOTO, false);
568 photoMenu.add(_disconnectPhotoItem);
569 _removePhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_PHOTO, false);
570 photoMenu.add(_removePhotoItem);
571 // Rotate current photo
572 _rotatePhotoLeft = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_LEFT, false);
573 photoMenu.add(_rotatePhotoLeft);
574 _rotatePhotoRight = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_RIGHT, false);
575 photoMenu.add(_rotatePhotoRight);
577 _photoPopupItem = makeMenuItem(FunctionLibrary.FUNCTION_PHOTO_POPUP, false);
578 photoMenu.add(_photoPopupItem);
579 _ignoreExifThumb = makeMenuItem(FunctionLibrary.FUNCTION_IGNORE_EXIF_THUMB, false);
580 photoMenu.add(_ignoreExifThumb);
581 photoMenu.addSeparator();
582 // correlate all photos
583 _correlatePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_PHOTOS, false);
584 photoMenu.add(_correlatePhotosItem);
585 // rearrange photo points
586 _rearrangePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_REARRANGE_PHOTOS, false);
587 photoMenu.add(_rearrangePhotosItem);
588 menubar.add(photoMenu);
591 JMenu audioMenu = new JMenu(I18nManager.getText("menu.audio"));
592 setAltKey(audioMenu, "altkey.menu.audio");
593 addAudioMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_LOAD_AUDIO);
594 audioMenu.add(addAudioMenuItem);
595 _selectNoAudioItem = new JMenuItem(I18nManager.getText("menu.range.none"));
596 _selectNoAudioItem.setEnabled(false);
597 _selectNoAudioItem.addActionListener(new ActionListener() {
598 public void actionPerformed(ActionEvent e) {
599 _app.getTrackInfo().selectAudio(-1);
602 audioMenu.add(_selectNoAudioItem);
603 audioMenu.addSeparator();
605 _connectAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_CONNECT_TO_POINT, false);
606 audioMenu.add(_connectAudioItem);
607 // Disconnect current audio clip
608 _disconnectAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_DISCONNECT_AUDIO, false);
609 audioMenu.add(_disconnectAudioItem);
610 // Remove current audio clip
611 _removeAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_AUDIO, false);
612 audioMenu.add(_removeAudioItem);
613 audioMenu.addSeparator();
614 // Correlate audio clips
615 _correlateAudiosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_AUDIOS, false);
616 audioMenu.add(_correlateAudiosItem);
617 menubar.add(audioMenu);
620 JMenu settingsMenu = new JMenu(I18nManager.getText("menu.settings"));
621 setAltKey(settingsMenu, "altkey.menu.settings");
622 // Set the map background
623 JMenuItem mapBgItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_MAP_BG);
624 settingsMenu.add(mapBgItem);
625 _onlineCheckbox = new JCheckBoxMenuItem(I18nManager.getText("menu.settings.onlinemode"));
626 _onlineCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_ONLINE_MODE));
627 _onlineCheckbox.addActionListener(new ActionListener() {
628 public void actionPerformed(ActionEvent e) {
629 boolean isOnline = _onlineCheckbox.isSelected();
630 Config.setConfigBoolean(Config.KEY_ONLINE_MODE, isOnline);
631 if (isOnline) {UpdateMessageBroker.informSubscribers();}
634 settingsMenu.add(_onlineCheckbox);
635 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_DISK_CACHE));
636 settingsMenu.addSeparator();
638 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_PATHS));
640 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_COLOURS));
641 // Set line width used for drawing
642 settingsMenu.add(makeMenuItem(new ChooseSingleParameter(_app, FunctionLibrary.FUNCTION_SET_LINE_WIDTH)));
644 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_LANGUAGE));
645 // Set altitude tolerance
646 settingsMenu.add(makeMenuItem(new ChooseSingleParameter(_app, FunctionLibrary.FUNCTION_SET_ALTITUDE_TOLERANCE)));
647 settingsMenu.addSeparator();
648 // Save configuration
649 settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SAVECONFIG));
650 _autosaveSettingsCheckbox = new JCheckBoxMenuItem(
651 I18nManager.getText("menu.settings.autosave"), false);
652 _autosaveSettingsCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS));
653 _autosaveSettingsCheckbox.addActionListener(new ActionListener() {
654 public void actionPerformed(ActionEvent e) {
655 Config.setConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS, _autosaveSettingsCheckbox.isSelected());
658 settingsMenu.add(_autosaveSettingsCheckbox);
659 menubar.add(settingsMenu);
662 JMenu helpMenu = new JMenu(I18nManager.getText("menu.help"));
663 setAltKey(helpMenu, "altkey.menu.help");
664 JMenuItem helpItem = makeMenuItem(FunctionLibrary.FUNCTION_HELP);
665 setShortcut(helpItem, "shortcut.menu.help.help");
666 helpMenu.add(helpItem);
667 helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SHOW_KEYS));
668 helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_ABOUT));
669 helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_CHECK_VERSION));
670 menubar.add(helpMenu);
676 * Convenience method for making a menu item using a function
677 * @param inFunction function
678 * @param inEnabled flag to specify initial enabled state
679 * @return menu item using localized name of function
681 private static JMenuItem makeMenuItem(GenericFunction inFunction, boolean inEnabled)
683 JMenuItem item = makeMenuItem(inFunction);
684 item.setEnabled(inEnabled);
689 * Convenience method for making a menu item using a function
690 * @param inFunction function
691 * @return menu item using localized name of function
693 private static JMenuItem makeMenuItem(GenericFunction inFunction)
695 JMenuItem item = new JMenuItem(I18nManager.getText(inFunction.getNameKey()));
696 item.addActionListener(new FunctionLauncher(inFunction));
701 * Set the alt key for the given menu
702 * @param inMenu menu to set
703 * @param inKey key to lookup to get language-sensitive altkey
705 private static void setAltKey(JMenu inMenu, String inKey)
707 // Lookup the key in the properties
708 String altKey = I18nManager.getText(inKey);
709 if (altKey != null && altKey.length() == 1)
711 int code = altKey.charAt(0) - 'A';
712 if (code >= 0 && code < 26)
714 // Found a valid code between A and Z
715 inMenu.setMnemonic(KEY_EVENTS[code]);
721 * Set the shortcut key for the given menu item
722 * @param inMenuItem menu item to set
723 * @param inKey key to lookup to get language-sensitive shortcut
725 private static void setShortcut(JMenuItem inMenuItem, String inKey)
727 // Lookup the key in the properties
728 String altKey = I18nManager.getText(inKey);
729 if (altKey != null && altKey.length() == 1)
731 int code = altKey.charAt(0) - 'A';
732 if (code >= 0 && code < 26)
734 // Found a valid code between A and Z
735 inMenuItem.setAccelerator(KeyStroke.getKeyStroke(KEY_EVENTS[code],
736 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
737 // use platform-specific key mask so Ctrl on Linux/Win, Clover on Mac
743 * Create a JToolBar containing all toolbar buttons
744 * @return toolbar containing buttons
746 public JToolBar createToolBar()
748 JToolBar toolbar = new JToolBar();
750 JButton openFileButton = new JButton(IconManager.getImageIcon(IconManager.OPEN_FILE));
751 openFileButton.setToolTipText(I18nManager.getText("function.open"));
752 openFileButton.addActionListener(_openFileAction);
753 toolbar.add(openFileButton);
755 JButton addPhotoButton = new JButton(IconManager.getImageIcon(IconManager.ADD_PHOTO));
756 addPhotoButton.setToolTipText(I18nManager.getText("menu.file.addphotos"));
757 addPhotoButton.addActionListener(_addPhotoAction);
758 toolbar.add(addPhotoButton);
760 _saveButton = new JButton(IconManager.getImageIcon(IconManager.SAVE_FILE));
761 _saveButton.setToolTipText(I18nManager.getText("menu.file.save"));
762 _saveButton.addActionListener(_saveAction);
763 _saveButton.setEnabled(false);
764 toolbar.add(_saveButton);
766 _undoButton = new JButton(IconManager.getImageIcon(IconManager.UNDO));
767 _undoButton.setToolTipText(I18nManager.getText("menu.track.undo"));
768 _undoButton.addActionListener(_undoAction);
769 _undoButton.setEnabled(false);
770 toolbar.add(_undoButton);
772 _editPointButton = new JButton(IconManager.getImageIcon(IconManager.EDIT_POINT));
773 _editPointButton.setToolTipText(I18nManager.getText("menu.point.editpoint"));
774 _editPointButton.addActionListener(_editPointAction);
775 _editPointButton.setEnabled(false);
776 toolbar.add(_editPointButton);
778 _deletePointButton = new JButton(IconManager.getImageIcon(IconManager.DELETE_POINT));
779 _deletePointButton.setToolTipText(I18nManager.getText("menu.point.deletepoint"));
780 _deletePointButton.addActionListener(_deletePointAction);
781 _deletePointButton.setEnabled(false);
782 toolbar.add(_deletePointButton);
784 _deleteRangeButton = new JButton(IconManager.getImageIcon(IconManager.DELETE_RANGE));
785 _deleteRangeButton.setToolTipText(I18nManager.getText("function.deleterange"));
786 _deleteRangeButton.addActionListener(new ActionListener() {
787 public void actionPerformed(ActionEvent arg0) {
788 FunctionLibrary.FUNCTION_DELETE_RANGE.begin();
791 _deleteRangeButton.setEnabled(false);
792 toolbar.add(_deleteRangeButton);
794 _cutAndMoveButton = new JButton(IconManager.getImageIcon(IconManager.CUT_AND_MOVE));
795 _cutAndMoveButton.setToolTipText(I18nManager.getText("menu.range.cutandmove"));
796 _cutAndMoveButton.addActionListener(new ActionListener() {
797 public void actionPerformed(ActionEvent arg0) {
798 _app.cutAndMoveSelection();
801 _cutAndMoveButton.setEnabled(false);
802 toolbar.add(_cutAndMoveButton);
804 _selectStartButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_START));
805 _selectStartButton.setToolTipText(I18nManager.getText("menu.range.start"));
806 _selectStartButton.addActionListener(_selectStartAction);
807 _selectStartButton.setEnabled(false);
808 toolbar.add(_selectStartButton);
809 _selectEndButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_END));
810 _selectEndButton.setToolTipText(I18nManager.getText("menu.range.end"));
811 _selectEndButton.addActionListener(_selectEndAction);
812 _selectEndButton.setEnabled(false);
813 toolbar.add(_selectEndButton);
815 _connectButton = new JButton(IconManager.getImageIcon(IconManager.CONNECT_PHOTO));
816 _connectButton.setToolTipText(I18nManager.getText(FunctionLibrary.FUNCTION_CONNECT_TO_POINT.getNameKey()));
817 _connectButton.addActionListener(new ActionListener() {
818 public void actionPerformed(ActionEvent arg0) {
819 FunctionLibrary.FUNCTION_CONNECT_TO_POINT.begin();
822 _connectButton.setEnabled(false);
823 toolbar.add(_connectButton);
825 toolbar.setFloatable(false);
831 * Method to update menu when file loaded
833 public void informFileLoaded()
835 // save, undo, delete enabled
836 _sendGpsItem.setEnabled(true);
837 _saveItem.setEnabled(true);
838 _undoItem.setEnabled(true);
839 _compressItem.setEnabled(true);
840 _deleteMarkedPointsItem.setEnabled(false);
845 * @see tim.prune.DataSubscriber#dataUpdated(tim.prune.data.Track)
847 public void dataUpdated(byte inUpdateType)
849 final boolean hasData = _track != null && _track.getNumPoints() > 0;
850 final boolean hasMultiplePoints = hasData && _track.getNumPoints() > 1;
852 // set functions which require data
853 _sendGpsItem.setEnabled(hasData);
854 _saveItem.setEnabled(hasData);
855 _saveButton.setEnabled(hasData);
856 _exportKmlItem.setEnabled(hasData);
857 _exportGpxItem.setEnabled(hasData);
858 _exportPovItem.setEnabled(hasMultiplePoints);
859 _exportSvgItem.setEnabled(hasMultiplePoints);
860 _exportImageItem.setEnabled(hasMultiplePoints);
861 _compressItem.setEnabled(hasData);
862 _markRectangleItem.setEnabled(hasData);
863 _deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints());
864 _rearrangeWaypointsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.hasWaypoints());
865 _splitSegmentsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.getNumPoints() > 3);
866 _sewSegmentsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.getNumPoints() > 3);
867 _selectAllItem.setEnabled(hasData);
868 _selectNoneItem.setEnabled(hasData);
869 _show3dItem.setEnabled(hasMultiplePoints);
870 _chartItem.setEnabled(hasData);
871 _browserMapMenu.setEnabled(hasData);
872 _distanceItem.setEnabled(hasData);
873 _getGpsiesItem.setEnabled(hasData);
874 _uploadGpsiesItem.setEnabled(hasData && _track.hasTrackPoints());
875 _lookupSrtmItem.setEnabled(hasData);
876 _lookupWikipediaItem.setEnabled(hasData);
877 _downloadOsmItem.setEnabled(hasData);
878 _getWeatherItem.setEnabled(hasData);
879 _findWaypointItem.setEnabled(hasData && _track.hasWaypoints());
880 // have we got a cache?
881 _downloadSrtmItem.setEnabled(hasData && Config.getConfigString(Config.KEY_DISK_CACHE) != null);
882 // have we got any timestamps?
883 _deleteByDateItem.setEnabled(hasData && _track.hasData(Field.TIMESTAMP));
885 // is undo available?
886 boolean hasUndo = !_app.getUndoStack().isEmpty();
887 _undoItem.setEnabled(hasUndo);
888 _undoButton.setEnabled(hasUndo);
889 _clearUndoItem.setEnabled(hasUndo);
890 // is there a current point?
891 DataPoint currPoint = _app.getTrackInfo().getCurrentPoint();
892 boolean hasPoint = (currPoint != null);
893 _editPointItem.setEnabled(hasPoint);
894 _editPointButton.setEnabled(hasPoint);
895 _editWaypointNameItem.setEnabled(hasPoint);
896 _deletePointItem.setEnabled(hasPoint);
897 _deletePointButton.setEnabled(hasPoint);
898 _selectStartItem.setEnabled(hasPoint);
899 _selectStartButton.setEnabled(hasPoint);
900 _selectEndItem.setEnabled(hasPoint);
901 _selectEndButton.setEnabled(hasPoint);
902 _duplicatePointItem.setEnabled(hasPoint);
904 _selectSegmentItem.setEnabled(hasPoint && !currPoint.isWaypoint());
905 // are there any photos?
906 boolean anyPhotos = _app.getTrackInfo().getPhotoList().getNumPhotos() > 0;
907 _saveExifItem.setEnabled(anyPhotos && _app.getTrackInfo().getPhotoList().hasMediaWithFile());
908 // is there a current photo, audio?
909 Photo currentPhoto = _app.getTrackInfo().getCurrentPhoto();
910 boolean hasPhoto = currentPhoto != null;
911 AudioClip currentAudio = _app.getTrackInfo().getCurrentAudio();
912 boolean hasAudio = currentAudio != null;
913 // connect is available if (photo/audio) and point selected, and media has no point
914 boolean connectAvailable = (hasPhoto && hasPoint && currentPhoto.getDataPoint() == null)
915 || (hasAudio && hasPoint && currentAudio.getDataPoint() == null);
916 _connectPhotoItem.setEnabled(hasPhoto && hasPoint && currentPhoto.getDataPoint() == null);
917 _connectButton.setEnabled(connectAvailable);
918 _disconnectPhotoItem.setEnabled(hasPhoto && currentPhoto.getDataPoint() != null);
919 _correlatePhotosItem.setEnabled(anyPhotos && hasData);
920 _rearrangePhotosItem.setEnabled(anyPhotos && hasMultiplePoints);
921 _removePhotoItem.setEnabled(hasPhoto);
922 _rotatePhotoLeft.setEnabled(hasPhoto);
923 _rotatePhotoRight.setEnabled(hasPhoto);
924 _photoPopupItem.setEnabled(hasPhoto);
925 _ignoreExifThumb.setEnabled(hasPhoto && currentPhoto.getExifThumbnail() != null);
926 _selectNoPhotoItem.setEnabled(hasPhoto);
927 boolean anyAudios = _app.getTrackInfo().getAudioList().getNumAudios() > 0;
928 _selectNoAudioItem.setEnabled(hasAudio);
929 _removeAudioItem.setEnabled(hasAudio);
930 _connectAudioItem.setEnabled(hasAudio && hasPoint && currentAudio.getDataPoint() == null);
931 _disconnectAudioItem.setEnabled(hasAudio && currentAudio.getDataPoint() != null);
932 _correlateAudiosItem.setEnabled(anyAudios && hasData);
933 // is there a current range?
934 boolean hasRange = (hasData && _selection.hasRangeSelected());
935 _deleteRangeItem.setEnabled(hasRange);
936 _deleteRangeButton.setEnabled(hasRange);
937 _cropTrackItem.setEnabled(hasRange);
938 _interpolateItem.setEnabled(hasRange);
939 _averageItem.setEnabled(hasRange);
940 _mergeSegmentsItem.setEnabled(hasRange);
941 _reverseItem.setEnabled(hasRange);
942 _addTimeOffsetItem.setEnabled(hasRange);
943 _addAltitudeOffsetItem.setEnabled(hasRange);
944 _convertNamesToTimesItem.setEnabled(hasRange && _track.hasWaypoints());
945 _deleteFieldValuesItem.setEnabled(hasRange);
946 _fullRangeDetailsItem.setEnabled(hasRange);
947 _estimateTimeItem.setEnabled(hasRange);
948 _learnEstimationParams.setEnabled(hasData && _track.hasTrackPoints() && _track.hasData(Field.TIMESTAMP)
949 && _track.hasAltitudeData());
950 // Is the currently selected point outside the current range?
951 boolean canCutAndMove = hasRange && hasPoint &&
952 (_selection.getCurrentPointIndex() < _selection.getStart()
953 || _selection.getCurrentPointIndex() > (_selection.getEnd()+1));
954 _cutAndMoveItem.setEnabled(canCutAndMove);
955 _cutAndMoveButton.setEnabled(canCutAndMove);
956 // Has the map been switched on/off?
957 boolean mapsOn = Config.getConfigBoolean(Config.KEY_SHOW_MAP);
958 if (_mapCheckbox.isSelected() != mapsOn) {
959 _mapCheckbox.setSelected(mapsOn);
961 // Are there any recently-used files?
962 RecentFileList rfl = Config.getRecentFileList();
963 final int numRecentFiles = rfl.getNumEntries();
964 final boolean hasRecentFiles = numRecentFiles > 0;
965 _recentFileMenu.setEnabled(hasRecentFiles);
968 int numItems = _recentFileMenu.getMenuComponentCount();
969 if (numItems == numRecentFiles)
971 // Right number of items, just change texts
972 for (int i=0; i<numRecentFiles; i++)
974 JMenuItem item = _recentFileMenu.getItem(i);
975 RecentFile rf = rfl.getFile(i);
976 item.setText(rf==null?"":rf.getFile().getName());
977 item.setToolTipText(rf==null?null:rf.getFile().getAbsolutePath());
983 _recentFileMenu.removeAll();
984 for (int i=0; i<rfl.getSize(); i++)
986 RecentFile rf = rfl.getFile(i);
987 if (rf != null && rf.isValid())
989 JMenuItem menuItem = new JMenuItem(rf.getFile().getName());
990 menuItem.setToolTipText(rf.getFile().getAbsolutePath());
991 menuItem.addActionListener(new RecentFileTrigger(_app, i));
992 _recentFileMenu.add(menuItem);
1001 * Ignore action completed signals
1002 * @see tim.prune.DataSubscriber#actionCompleted(java.lang.String)
1004 public void actionCompleted(String inMessage)