// License: Public Domain. For details, see LICENSE file. package livegps; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.JosmAction; import org.openstreetmap.josm.data.gpx.GpxData; import org.openstreetmap.josm.gui.MainMenu; import org.openstreetmap.josm.gui.MapFrame; import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent; import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener; import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent; import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent; import org.openstreetmap.josm.plugins.Plugin; import org.openstreetmap.josm.plugins.PluginInformation; import org.openstreetmap.josm.tools.Shortcut; public class LiveGpsPlugin extends Plugin implements LayerChangeListener { private boolean enabled = false; private LiveGpsAcquirer acquirer = null; private Thread acquirerThread = null; private JMenu lgpsmenu = null; private JCheckBoxMenuItem lgpscapture; private JCheckBoxMenuItem lgpsautocenter; private LiveGpsDialog lgpsdialog; /* List of foreign (e.g. other plugins) subscribers */ List<PropertyChangeListener> listenerQueue = new ArrayList<>(); private GpxData data = new GpxData(); private LiveGpsLayer lgpslayer = null; public class CaptureAction extends JosmAction { public CaptureAction() { super( tr("Capture GPS Track"), "capturemenu", tr("Connect to gpsd server and show current position in LiveGPS layer."), Shortcut.registerShortcut("menu:livegps:capture", tr( "Menu: {0}", tr("Capture GPS Track")), KeyEvent.VK_R, Shortcut.CTRL), true); } @Override public void actionPerformed(ActionEvent e) { enableTracking(lgpscapture.isSelected()); } } public class CenterAction extends JosmAction { public CenterAction() { super(tr("Center Once"), "centermenu", tr("Center the LiveGPS layer to current position."), Shortcut.registerShortcut("edit:centergps", tr("Edit: {0}", tr("Center Once")), KeyEvent.VK_HOME, Shortcut.DIRECT), true); } @Override public void actionPerformed(ActionEvent e) { if (lgpslayer != null) { lgpslayer.center(); } } } public class AutoCenterAction extends JosmAction { public AutoCenterAction() { super( tr("Auto-Center"), "autocentermenu", tr("Continuously center the LiveGPS layer to current position."), Shortcut.registerShortcut("menu:livegps:autocenter", tr( "Menu: {0}", tr("Capture GPS Track")), KeyEvent.VK_HOME, Shortcut.CTRL), true); } @Override public void actionPerformed(ActionEvent e) { if (lgpslayer != null) { setAutoCenter(lgpsautocenter.isSelected()); } } } @Override public void layerOrderChanged(LayerOrderChangeEvent e) { } @Override public void layerAdded(LayerAddEvent e) { } @Override public void layerRemoving(LayerRemoveEvent e) { Layer oldLayer = e.getRemovedLayer(); if (oldLayer != lgpslayer) return; enableTracking(false); lgpscapture.setSelected(false); Main.getLayerManager().removeLayerChangeListener(this); lgpslayer = null; } public LiveGpsPlugin(PluginInformation info) { super(info); MainMenu menu = Main.main.menu; lgpsmenu = menu.gpsMenu; if (lgpsmenu.getItemCount() > 0) { lgpsmenu.addSeparator(); } JosmAction captureAction = new CaptureAction(); lgpscapture = new JCheckBoxMenuItem(captureAction); lgpsmenu.add(lgpscapture); lgpscapture.setAccelerator(captureAction.getShortcut().getKeyStroke()); JosmAction centerAction = new CenterAction(); MainMenu.add(lgpsmenu, centerAction); JosmAction autoCenterAction = new AutoCenterAction(); lgpsautocenter = new JCheckBoxMenuItem(autoCenterAction); lgpsmenu.add(lgpsautocenter); lgpsautocenter.setAccelerator(autoCenterAction.getShortcut().getKeyStroke()); } /** * Set to <code>true</code> if the current position should always be in the center of the map. * @param autoCenter if <code>true</code> the map is always centered. */ public void setAutoCenter(boolean autoCenter) { lgpsautocenter.setSelected(autoCenter); // just in case this method was // not called from the menu if (lgpslayer != null) { lgpslayer.setAutoCenter(autoCenter); if (autoCenter) lgpslayer.center(); } } /** * Returns <code>true</code> if autocenter is selected. * @return <code>true</code> if autocenter is selected. */ public boolean isAutoCenter() { return lgpsautocenter.isSelected(); } /** * Enable or disable gps tracking * @param enable if <code>true</code> tracking is started. */ public void enableTracking(boolean enable) { if (enable && !enabled) { assert (acquirer == null); assert (acquirerThread == null); acquirer = new LiveGpsAcquirer(); acquirerThread = new Thread(acquirer); if (lgpslayer == null) { lgpslayer = new LiveGpsLayer(data); Main.getLayerManager().addLayer(lgpslayer); Main.getLayerManager().addLayerChangeListener(this); lgpslayer.setAutoCenter(isAutoCenter()); } acquirer.addPropertyChangeListener(lgpslayer); acquirer.addPropertyChangeListener(lgpsdialog); for (PropertyChangeListener listener : listenerQueue) { acquirer.addPropertyChangeListener(listener); } acquirerThread.start(); enabled = true; } else if (!enable && enabled) { assert (lgpslayer != null); assert (acquirer != null); assert (acquirerThread != null); acquirer.shutdown(); acquirer = null; acquirerThread = null; enabled = false; } } /** * Add a listener for gps events. * @param listener the listener. */ public void addPropertyChangeListener(PropertyChangeListener listener) { assert !listenerQueue.contains(listener); listenerQueue.add(listener); if (acquirer != null) acquirer.addPropertyChangeListener(listener); } /** * Remove a listener for gps events. * @param listener the listener. */ public void removePropertyChangeListener(PropertyChangeListener listener) { assert listenerQueue.contains(listener); listenerQueue.remove(listener); if (acquirer != null) acquirer.removePropertyChangeListener(listener); } @Override public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) { if (newFrame != null) newFrame.addToggleDialog(lgpsdialog = new LiveGpsDialog(newFrame)); } /** * @return the lgpsmenu */ public JMenu getLgpsMenu() { return this.lgpsmenu; } }