001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.layer; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.event.ActionEvent; 007import java.awt.event.KeyEvent; 008import java.lang.ref.WeakReference; 009import java.util.List; 010 011import javax.swing.AbstractAction; 012 013import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 014import org.openstreetmap.josm.gui.util.MultikeyActionsHandler; 015import org.openstreetmap.josm.gui.util.MultikeyShortcutAction; 016import org.openstreetmap.josm.tools.Shortcut; 017 018/** 019 * Manages actions to jump from one marker to the next for layers that show markers 020 * ({@link org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer}, 021 * {@link org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer}). 022 * 023 * Registers global multi-key shortcuts and offers actions for the right-click menu of 024 * the layers. 025 */ 026public final class JumpToMarkerActions { 027 028 /** 029 * Interface for a layer that displays markers and supports jumping from 030 * one marker to the next. 031 */ 032 public interface JumpToMarkerLayer { 033 /** 034 * Jump (move the viewport) to the next marker. 035 */ 036 void jumpToNextMarker(); 037 038 /** 039 * Jump (move the viewport) to the previous marker. 040 */ 041 void jumpToPreviousMarker(); 042 } 043 044 private JumpToMarkerActions() { 045 // Hide default constructor for utils classes 046 } 047 048 private static volatile JumpToNextMarker jumpToNextMarkerAction; 049 private static volatile JumpToPreviousMarker jumpToPreviousMarkerAction; 050 051 /** 052 * Initialize the actions, register shortcuts. 053 */ 054 public static void initialize() { 055 jumpToNextMarkerAction = new JumpToNextMarker(null); 056 jumpToPreviousMarkerAction = new JumpToPreviousMarker(null); 057 MultikeyActionsHandler.getInstance().addAction(jumpToNextMarkerAction); 058 MultikeyActionsHandler.getInstance().addAction(jumpToPreviousMarkerAction); 059 } 060 061 /** 062 * Unregister the actions. 063 */ 064 public static void unregisterActions() { 065 MultikeyActionsHandler.getInstance().removeAction(jumpToNextMarkerAction); 066 MultikeyActionsHandler.getInstance().removeAction(jumpToPreviousMarkerAction); 067 } 068 069 private abstract static class JumpToMarker extends AbstractAction implements MultikeyShortcutAction { 070 071 private final transient JumpToMarkerLayer layer; 072 private final transient Shortcut multikeyShortcut; 073 private transient WeakReference<Layer> lastLayer; 074 075 JumpToMarker(JumpToMarkerLayer layer, Shortcut shortcut) { 076 this.layer = layer; 077 this.multikeyShortcut = shortcut; 078 this.multikeyShortcut.setAccelerator(this); 079 } 080 081 protected final void setLastLayer(Layer l) { 082 lastLayer = new WeakReference<>(l); 083 } 084 085 @Override 086 public Shortcut getMultikeyShortcut() { 087 return multikeyShortcut; 088 } 089 090 @Override 091 public void actionPerformed(ActionEvent e) { 092 execute(layer); 093 } 094 095 @Override 096 public void executeMultikeyAction(int index, boolean repeat) { 097 Layer l = LayerListDialog.getLayerForIndex(index); 098 if (l != null) { 099 if (l instanceof JumpToMarkerLayer) { 100 execute((JumpToMarkerLayer) l); 101 } 102 } else if (repeat && lastLayer != null) { 103 l = lastLayer.get(); 104 if (LayerListDialog.isLayerValid(l) && l instanceof JumpToMarkerLayer) { 105 execute((JumpToMarkerLayer) l); 106 } 107 } 108 } 109 110 protected abstract void execute(JumpToMarkerLayer l); 111 112 @Override 113 public List<MultikeyInfo> getMultikeyCombinations() { 114 return LayerListDialog.getLayerInfoByClass(JumpToMarkerLayer.class); 115 } 116 117 @Override 118 public MultikeyInfo getLastMultikeyAction() { 119 if (lastLayer != null) 120 return LayerListDialog.getLayerInfo(lastLayer.get()); 121 else 122 return null; 123 } 124 } 125 126 public static final class JumpToNextMarker extends JumpToMarker { 127 128 public JumpToNextMarker(JumpToMarkerLayer layer) { 129 super(layer, Shortcut.registerShortcut("core_multikey:nextMarker", tr("Multikey: {0}", tr("Next marker")), 130 KeyEvent.VK_J, Shortcut.ALT_CTRL)); 131 putValue(SHORT_DESCRIPTION, tr("Jump to next marker")); 132 putValue(NAME, tr("Jump to next marker")); 133 } 134 135 @Override 136 protected void execute(JumpToMarkerLayer l) { 137 l.jumpToNextMarker(); 138 setLastLayer((Layer) l); 139 } 140 } 141 142 public static final class JumpToPreviousMarker extends JumpToMarker { 143 144 public JumpToPreviousMarker(JumpToMarkerLayer layer) { 145 super(layer, Shortcut.registerShortcut("core_multikey:previousMarker", tr("Multikey: {0}", tr("Previous marker")), 146 KeyEvent.VK_P, Shortcut.ALT_CTRL)); 147 putValue(SHORT_DESCRIPTION, tr("Jump to previous marker")); 148 putValue(NAME, tr("Jump to previous marker")); 149 } 150 151 @Override 152 protected void execute(JumpToMarkerLayer l) { 153 l.jumpToPreviousMarker(); 154 setLastLayer((Layer) l); 155 } 156 } 157}