/** * */ package com.tilusnet.josm.plugins.alignways; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.Cursor; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JOptionPane; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.mapmode.MapMode; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent; import org.openstreetmap.josm.data.osm.event.DataChangedEvent; import org.openstreetmap.josm.data.osm.event.DataSetListener; import org.openstreetmap.josm.data.osm.event.NodeMovedEvent; import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent; import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent; import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent; import org.openstreetmap.josm.data.osm.event.TagsChangedEvent; import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent; import org.openstreetmap.josm.gui.IconToggleButton; import org.openstreetmap.josm.gui.MapFrame; import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.tools.Shortcut; /** * @author tilusnet <tilusnet@gmail.com> * Handles the state machine and user interaction (mouse clicks). * */ public class AlignWaysMode extends MapMode implements DataSetListener { private static final long serialVersionUID = -1090955708412011141L; private final AlignWaysState noneSelected; private final AlignWaysState referenceSelected; private final AlignWaysState aligneeSelected; private final AlignWaysState bothSelected; private AlignWaysState currentState; private AlignWaysSegmentMgr awSegs; boolean tipShown; public AlignWaysMode(MapFrame mapFrame, String name, String desc) { super(tr(name), "alignways.png", tr(desc), Shortcut.registerShortcut("mapmode:alignways", tr("Mode: {0}", tr("Align Ways")), KeyEvent.VK_N, Shortcut.SHIFT), mapFrame, Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); noneSelected = new AlignWaysSelNoneState(); referenceSelected = new AlignWaysSelRefState(); aligneeSelected = new AlignWaysSelAlgnState(); bothSelected = new AlignWaysSelBothState(); tipShown = false; } @Override public void enterMode() { super.enterMode(); AlignWaysPlugin.getAwDialog().activate(true); IconToggleButton optBtn = AlignWaysPlugin.getOptBtn(); if (!optBtn.isSelected()) { // Make sure the option panel is visible when align mode starts optBtn.doClick(); } boolean showTips = Boolean.parseBoolean(Main.pref.get("alignways.showtips", "true")); if ((showTips) && (!tipShown)) { showTips(); } int majorVer = Integer.parseInt(Main.pref.get("alignways.majorver", "-1")); if (majorVer != AlignWaysPlugin.AlignWaysMajorVersion) { showWhatsNew(); } awSegs = AlignWaysSegmentMgr.getInstance(Main.map.mapView); Main.map.mapView.addMouseListener(this); DataSet ds = Main.getLayerManager().getEditDataSet(); if (ds != null) ds.addDataSetListener(this); setCurrentState(noneSelected); } @Override public void exitMode() { super.exitMode(); AlignWaysPlugin.getAwDialog().activate(false); IconToggleButton optBtn = AlignWaysPlugin.getOptBtn(); if (optBtn.isSelected()) { // The option panel will be switched off optBtn.doClick(); } setCurrentState(noneSelected); Main.map.mapView.removeMouseListener(this); DataSet ds = Main.getLayerManager().getEditDataSet(); if (ds != null) ds.removeDataSetListener(this); AlignWaysPlugin.getAwAction().setEnabled(false); } @Override public void mouseClicked(MouseEvent e) { boolean ctrlPressed = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; boolean altPressed = (e.getModifiers() & (ActionEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0; if (e.getButton() == MouseEvent.BUTTON1) { if (altPressed) { currentState.altLClick(this); } else { Point clickedPoint = new Point(e.getX(), e.getY()); if (!ctrlPressed) { // Alignee could change if (awSegs.algnUpdate(clickedPoint)) { currentState.leftClick(this); } } else { // Reference could change if (awSegs.refUpdate(clickedPoint)) { currentState.ctrlLClick(this); } } } } Main.map.mapView.repaint(); } /** * Sets the current state based on the selected segments. * @param mgr AlignWays segment manager singleton */ public void setCurrentState(AlignWaysSegmentMgr mgr) { boolean algnSelected = mgr.getAlgnSeg() != null; boolean refSelected = mgr.getRefSeg() != null; if (algnSelected && refSelected) setCurrentState(getBothSelected()); else if (algnSelected) setCurrentState(getAligneeSelected()); else if (refSelected) setCurrentState(getReferenceSelected()); else setCurrentState(getNoneSelected()); } /** * Sets the current state. * @param currentState One of the AlignWays states */ public void setCurrentState(AlignWaysState currentState) { this.currentState = currentState; currentState.setHelpText(); // Activate the Align Ways button if we have enough selections AlignWaysPlugin.getAwAction().setEnabled(currentState == bothSelected); if (currentState == noneSelected) { awSegs.cleanupWays(); // getEditDataSet() may return null when the editable layer had // already been removed by JOSM. This happens e.g. when the user closes // JOSM while AlignWays mode is still active. DataSet ds = getLayerManager().getEditDataSet(); if (ds != null) { ds.clearSelection(); } } } /** * @return the noneSelected */ public AlignWaysState getNoneSelected() { return noneSelected; } /** * @return the referenceSelected */ public AlignWaysState getReferenceSelected() { return referenceSelected; } /** * @return the aligneeSelected */ public AlignWaysState getAligneeSelected() { return aligneeSelected; } /** * @return the bothSelected */ public AlignWaysState getBothSelected() { return bothSelected; } private void showTips() { AlignWaysTipsPanel atp = new AlignWaysTipsPanel(); Object[] okButton = {tr("I''m ready!")}; JOptionPane tipPane = new JOptionPane(atp, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, okButton, okButton[0]); tipPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 30, 10)); JDialog tipDialog = tipPane.createDialog(Main.parent, tr("AlignWays Tips")); tipDialog.setIconImage(new ImageIcon(getClass().getResource("/images/alignways.png")).getImage()); tipDialog.setResizable(true); tipDialog.setVisible(true); tipShown = true; tipDialog.dispose(); Main.pref.put("alignways.showtips", !atp.isChkBoxSelected()); } private void showWhatsNew() { AlignWaysWhatsNewPanel awnp = new AlignWaysWhatsNewPanel(); JOptionPane wnPane = new JOptionPane(awnp, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null); wnPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); JDialog wnDialog = wnPane.createDialog(Main.parent, tr("AlignWays: What''s New...")); wnDialog.setIconImage(new ImageIcon(getClass().getResource("/images/alignways.png")).getImage()); wnDialog.setResizable(true); wnDialog.setVisible(true); wnDialog.dispose(); Main.pref.put("alignways.majorver", Integer.toString(AlignWaysPlugin.AlignWaysMajorVersion)); } @Override public boolean layerIsSupported(Layer l) { return l instanceof OsmDataLayer; } @Override protected void updateEnabledState() { setEnabled(getLayerManager().getEditLayer() != null); } /* --------------- * * DataSetListener * * --------------- */ @Override public void primitivesAdded(PrimitivesAddedEvent event) { } @Override public void primitivesRemoved(PrimitivesRemovedEvent event) { awSegs = AlignWaysSegmentMgr.getInstance(Main.map.mapView); // Check whether any of the removed primitives were part of a highlighted alignee or reference segment. // If so: remove the affected segment and update the state accordingly. if (awSegs.primitivesRemoved(event.getPrimitives())) setCurrentState(awSegs); } @Override public void tagsChanged(TagsChangedEvent event) { } @Override public void nodeMoved(NodeMovedEvent event) { } @Override public void wayNodesChanged(WayNodesChangedEvent event) { } @Override public void relationMembersChanged(RelationMembersChangedEvent event) { } @Override public void otherDatasetChange(AbstractDatasetChangedEvent event) { } @Override public void dataChanged(DataChangedEvent event) { } }