Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysAction.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysAction.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysAction.java	(revision 27348)
@@ -0,0 +1,77 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.Collection;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.tools.Shortcut;
+
+import com.tilusnet.josm.plugins.alignways.AlignWaysDialog.AligningModeOption;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ * 
+ */
+public class AlignWaysAction extends JosmAction {
+
+    private static final long serialVersionUID = -1540319652562985458L;
+
+    public AlignWaysAction() {
+        super(
+                tr("Align Way Segments"),
+                "alignways",
+                tr("Makes a pair of selected way segments parallel by rotating one of them "
+                        + "around a chosen pivot."), Shortcut.registerShortcut(
+                                "tools:alignways", tr("Tool: {0}", tr("Align Ways")),
+                                KeyEvent.VK_A, Shortcut.GROUP_EDIT,
+                                KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK), true);
+        setEnabled(false);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (!isEnabled())
+            return;
+        if (getCurrentDataSet() == null)
+            return;
+
+        Collection<Node> affectableNodes = AlignWaysSegmentMgr.getInstance(
+                Main.map.mapView).getSelectedNodes();
+
+        // c is the last command launched, if any
+        Command c = !Main.main.undoRedo.commands.isEmpty() ? Main.main.undoRedo.commands
+                .getLast() : null;
+
+                // Potentially add my type of command only if last command wasn't my type
+                // or, if it was, the rotated nodes were not the same as now
+                if (!(c instanceof AlignWaysCmdKeepLength && affectableNodes
+                        .equals(((AlignWaysCmdKeepLength) c).getPrevAffectedNodes()))) {
+
+                    AlignWaysCmdKeepLength cmdAW;
+                    if (AlignWaysPlugin.awDialog.getAwOpt() == AligningModeOption.ALGN_OPT_KEEP_ANGLE) {
+                        cmdAW = new AlignWaysCmdKeepAngles();
+                    } else {
+                        cmdAW = new AlignWaysCmdKeepLength();
+                    }
+
+                    if (cmdAW.executable()) {
+                        // This will also trigger AlignWaysCmdKeepLength.executeCommand()
+                        Main.main.undoRedo.add(cmdAW);
+                    }
+                }
+
+                Main.map.mapView.repaint();
+
+                return;
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysAlgnSegment.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysAlgnSegment.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysAlgnSegment.java	(revision 27348)
@@ -0,0 +1,286 @@
+package com.tilusnet.josm.plugins.alignways;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Shape;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.NavigatableComponent;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ * 
+ * The segment to be aligned to the reference segment. Actions it can do:
+ *         - remember its selected pivot point
+ *         - keeps its potential pivot point list up to date
+ *         - rotate itself
+ *         - paint itself and its selected pivot point
+ * 
+ */
+public class AlignWaysAlgnSegment extends AlignWaysSegment {
+
+    private enum PivotLocations {
+        NONE, NODE1, NODE2, CENTRE
+    };
+
+    private PivotLocations currPivot;
+    Map<PivotLocations, EastNorth> pivotList = new EnumMap<PivotLocations, EastNorth>(
+            PivotLocations.class);
+    private final Color pivotColor = Color.YELLOW;
+    private final Color crossColor = pivotColor;
+    private final Map<Node,ArrayList<WaySegment>> adjWaySegs = new HashMap<Node,ArrayList<WaySegment>>();
+
+    public AlignWaysAlgnSegment(MapView mapview, Point p)
+            throws IllegalArgumentException {
+        super(mapview, p);
+        setSegment(getNearestWaySegment(p));
+        segmentColor = Color.ORANGE;
+    }
+
+    /**
+     * Sets segment and initialises its pivot list and activates the centre
+     * rotation pivot.
+     */
+    @Override
+    public void setSegment(WaySegment segment) {
+        super.setSegment(segment);
+        setPivots();
+    }
+
+    /* (non-Javadoc)
+     * @see com.tilusnet.josm.plugins.alignways.AlignWaysSegment#setSegmentEndpoints(org.openstreetmap.josm.data.osm.WaySegment)
+     */
+    @Override
+    void setSegmentEndpoints(WaySegment segment) {
+        super.setSegmentEndpoints(segment);
+
+        // Update the list of adjacent waysegments to the endpoints
+        for (Node nA : getSegmentEndPoints()) {
+            adjWaySegs.put(nA, new ArrayList<WaySegment>(determineAdjacentWaysegments(nA)));
+        }
+
+    }
+
+    /**
+     * Useful when segments moves (or e.g. rotates) on the map. Updates the end
+     * segment points and the pivot coordinates without changing the current
+     * pivot.
+     */
+    public void updatePivotsEndpoints() {
+        setPivots(currPivot);
+        setSegmentEndpoints(segment);
+    }
+
+    /**
+     * Updates the segment's pivot list and sets the rotation pivot to centre.
+     */
+    private void setPivots(PivotLocations pivotRef) {
+        if (segment != null) {
+            for (PivotLocations pl : PivotLocations.values()) {
+                pivotList.put(pl, getPivotCoord(pl));
+            }
+            setPivotReference(pivotRef);
+        } else {
+            setPivotReference(PivotLocations.NONE);
+        }
+    }
+
+    private void setPivots() {
+        setPivots(PivotLocations.CENTRE);
+    }
+
+    private void setPivotReference(PivotLocations pp) {
+        currPivot = pp;
+    }
+
+    /**
+     * Returns the EastNorth of the specified pivot point pp. It always returns
+     * up-to-date data from dataset. Assumes segment is not null.
+     * 
+     * @param pp
+     *            The pivot location
+     */
+    private EastNorth getPivotCoord(PivotLocations pp) {
+        switch (pp) {
+        case NONE:
+            return null;
+        case NODE1:
+            return segment.way.getNode(segment.lowerIndex).getEastNorth();
+        case NODE2:
+            return segment.way.getNode(segment.lowerIndex + 1).getEastNorth();
+        case CENTRE:
+            return getPivotCoord(PivotLocations.NODE1).getCenter(
+                    getPivotCoord(PivotLocations.NODE2));
+        default:
+            // Should never happen
+            return null;
+        }
+    }
+
+    /**
+     * @return The EastNorth of the currently selected pivot.
+     */
+    public EastNorth getCurrPivotCoord() {
+        if (segment != null)
+            return getPivotCoord(currPivot);
+        return null;
+    }
+
+    /**
+     * @param clickedPoint
+     *            Pivot may be updated in the vicinity of this point
+     * @return true if a pivot is within reach on the segment, false otherwise
+     */
+    public boolean updatePivot(Point clickedPoint) {
+        // tHQ Done.
+        PivotLocations tmpPivot = findNearbyPivot(clickedPoint);
+        if (tmpPivot != PivotLocations.NONE) {
+            setPivotReference(tmpPivot);
+            return true;
+        } else
+            return false;
+    }
+
+    private PivotLocations findNearbyPivot(Point clickedPoint) {
+        PivotLocations nearest = PivotLocations.NONE;
+        int snapDistance = NavigatableComponent.PROP_SNAP_DISTANCE.get();
+
+        // If no alignee selected yet, there's no point to carry on
+        if (segment == null)
+            return PivotLocations.NONE;
+
+        for (PivotLocations pl : PivotLocations.values()) {
+            if (pl.equals(PivotLocations.NONE)) {
+                continue;
+            }
+            if (mapview.getPoint(pivotList.get(pl)).distance(clickedPoint) <= snapDistance) {
+                nearest = pl;
+                break;
+            }
+        }
+        return nearest;
+    }
+
+    /**
+     * Given a Node (usually an endpoint), it will return a collection of way segments that are adjacently
+     * connected to it. The current alignee waysegment is not added to the collection.
+     * 
+     * @param node The Node (endpoint) to analyse.
+     * @return The collection of the adjacent waysegments.
+     */
+    private Collection<WaySegment> determineAdjacentWaysegments(Node node) {
+        Collection<WaySegment> wsSet = new HashSet<WaySegment>();
+        final double radius = 10.0;
+        final int stepsOnCircle = 24;
+        final double incrementOnCircle = 2 * Math.PI / stepsOnCircle;
+
+        Point p = Main.map.mapView.getPoint(node);
+        for (int i = 0; i < stepsOnCircle; i++) {
+            double ang = i * incrementOnCircle;
+            double x = p.getX() + (Math.cos(ang) * radius);
+            double y = p.getY() + (Math.sin(ang) * radius);
+            Point pnew = new Point();
+            pnew.setLocation(x, y);
+            WaySegment ws = Main.map.mapView.getNearestWaySegment(pnew, OsmPrimitive.isUsablePredicate);
+            if (ws != null &&  !ws.equals(this.segment) &&
+                    (ws.getFirstNode().equals(node) || ws.getSecondNode().equals(node))) {
+                // We won't want to add a:
+                // - 'no match' (=null)
+                // - segment that is not connected to the alignee endpoint
+                wsSet.add(ws);
+            }
+        }
+
+        return wsSet;
+    }
+
+    /**
+     * Returns the collection of adjacent way segments to Node node.
+     * The node is normally a valid endpoint of the segment.
+     * If it isn't, null may be returned.
+     * 
+     * @param node The (endpoint) node.
+     * @return Collection of the adjacent way segments.
+     */
+    public ArrayList<WaySegment> getAdjacentWaySegments(Node node) {
+        return adjWaySegs.get(node);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.tilusnet.josm.plugins.alignways.AlignWaysRefSegment#paint(java
+     * .awt.Graphics2D, org.openstreetmap.josm.gui.MapView,
+     * org.openstreetmap.josm.data.Bounds)
+     */
+    @Override
+    public void paint(Graphics2D g, MapView mv, Bounds bbox) {
+        // Note: segment should never be null here
+        super.paint(g, mv, bbox);
+
+        // Ensure consistency
+        updatePivotsEndpoints();
+
+        // Highlight potential pivot points
+        for (PivotLocations pl : PivotLocations.values()) {
+            if (pl != PivotLocations.NONE) {
+                highlightCross(g, mv, pivotList.get(pl));
+            }
+        }
+
+        // Highlight active pivot
+        highlightPivot(g, mv, getPivotCoord(currPivot));
+
+    }
+
+    private void highlightPivot(Graphics2D g, MapView mv, EastNorth pivot) {
+        g.setColor(pivotColor);
+        g.setStroke(new BasicStroke());
+
+        Shape pvCentrePoint = new Ellipse2D.Double(
+                mv.getPoint(pivot).getX() - 5.0f,
+                mv.getPoint(pivot).getY() - 5.0f, 10.0f, 10.0f);
+        g.fill(pvCentrePoint);
+        Shape pvPoint = new Ellipse2D.Double(mv.getPoint(pivot).getX() - 8.0f,
+                mv.getPoint(pivot).getY() - 8.0f, 16.0f, 16.0f);
+
+        g.draw(pvCentrePoint);
+        g.draw(pvPoint);
+    }
+
+    private void highlightCross(Graphics2D g, MapView mv, EastNorth en) {
+
+        double crossX = mv.getPoint(en).getX();
+        double crossY = mv.getPoint(en).getY();
+        double crossSize = 10.0;
+
+        Line2D crossV = new Line2D.Double(crossX, crossY - crossSize, crossX,
+                crossY + crossSize);
+        Line2D crossH = new Line2D.Double(crossX - crossSize, crossY, crossX
+                + crossSize, crossY);
+
+        g.setColor(crossColor);
+        g.setStroke(new BasicStroke());
+        g.draw(crossV);
+        g.draw(crossH);
+
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysCmdKeepAngles.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysCmdKeepAngles.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysCmdKeepAngles.java	(revision 27348)
@@ -0,0 +1,171 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.WaySegment;
+
+import com.tilusnet.josm.plugins.alignways.geometry.AlignWaysGeomLine;
+import com.tilusnet.josm.plugins.alignways.geometry.AlignWaysGeomLine.IntersectionStatus;
+import com.tilusnet.josm.plugins.alignways.geometry.AlignWaysGeomPoint;
+
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ *
+ */
+public class AlignWaysCmdKeepAngles extends AlignWaysCmdKeepLength {
+
+    AlignableStatus alignableStatKeepAngles = AlignableStatus.ALGN_VALID;
+
+    public AlignWaysCmdKeepAngles() {
+        super();
+
+        // Now the calculatedNodes reflect the coordinates that we'd have
+        // without preserving the angles.
+
+        Map<Node,EastNorth> calcNodesKeepLength = calculatedNodes;
+
+        Node[] nodeArr = algnSeg.getSegmentEndPoints().toArray(new Node[2]);
+
+        EastNorth enCalc1 = calcNodesKeepLength.get(nodeArr[0]);
+        EastNorth enCalc2 = calcNodesKeepLength.get(nodeArr[1]);
+        AlignWaysGeomLine lineKeepLength = new AlignWaysGeomLine(enCalc1.getX(), enCalc1.getY(), enCalc2.getX(), enCalc2.getY());
+
+        recalculateNodes(lineKeepLength, nodeArr[0]);
+        recalculateNodes(lineKeepLength, nodeArr[1]);
+
+    }
+
+
+    void recalculateNodes(AlignWaysGeomLine alignedLineKeepLength, Node endpoint) {
+
+        ArrayList<WaySegment> alws = algnSeg.getAdjacentWaySegments(endpoint);
+        if (alws.size() == 1) {
+            // We need the intersection point of
+            //  - the freely rotated alignee as calculated in calcNodesFreeAngle
+            //  - the adjacent way segment
+
+            EastNorth enAdj1 = alws.get(0).getFirstNode().getEastNorth();
+            EastNorth enAdj2 = alws.get(0).getSecondNode().getEastNorth();
+
+            // Update the calculated node for aligning while keeping angles
+            AlignWaysGeomPoint isectPnt = alignedLineKeepLength.getIntersection(new AlignWaysGeomLine(enAdj1.getX(), enAdj1.getY(), enAdj2.getX(), enAdj2.getY()));
+            // If the intersection is null, the adjacent and the alignee are parallel already:
+            // there's no need to update this node
+            if (isectPnt != null) {
+                calculatedNodes.put(endpoint, new EastNorth(isectPnt.getX(), isectPnt.getY()));
+            } else if (alignedLineKeepLength.getIntersectionStatus() == IntersectionStatus.LINES_PARALLEL) {
+                alignableStatKeepAngles = AlignableStatus.ALGN_INV_ANGLE_PRESERVING_CONFLICT;
+            }
+        } else {
+            if (!endpoint.getEastNorth().equals(pivot)) {
+                // Report non-pivot endpoints only
+                alignableStatKeepAngles = AlignableStatus.ALGN_INV_TOOMANY_CONNECTED_WS;
+            }
+        }
+
+    }
+
+
+    /**
+     * Reports invalid alignable statuses on screen in dialog boxes.
+     * 
+     * @param stat The invalid status to report
+     */
+    @Override
+    void reportInvalidCommand(AlignableStatus stat) {
+        String statMsg;
+
+        switch (stat) {
+        case ALGN_INV_CONNECTED_UNSHARED_PIVOT:
+            statMsg = tr("Please select two segments that don''t share any nodes.\n"
+                    + "Alternatively put the pivot on their common node.\n");
+            break;
+        case ALGN_INV_OUTSIDE_WORLD:
+            statMsg = tr("Aligning would result nodes 'outside the world'.\n"
+                    + "Alignment not possible.\n");
+            break;
+        case ALGN_INV_TOOMANY_CONNECTED_WS:
+            statMsg = tr("There is at least a non-pivot endpoint of the alignee that joins more than two way segments.\n"
+                    + "Preserved angles type alignment is not possible.\n");
+            break;
+        case ALGN_INV_ANGLE_PRESERVING_CONFLICT:
+            statMsg = tr("The alignment is not possible with maintaining the angles of the joint segments.\n"
+                    + "Either choose the ''keep length'' aligning method or select other segments.\n");
+            break;
+        default:
+            statMsg = tr("Undocumented problem occured.\n");
+            break;
+        }
+
+        JOptionPane.showMessageDialog(
+                Main.parent,
+                tr(statMsg),
+                tr("AlignWayS: Alignment not possible"),
+                JOptionPane.WARNING_MESSAGE
+                );
+
+    }
+
+
+    /**
+     * Returns true if the two selected segments are alignable.
+     * They are not if they are connected *and* the pivot is not the connection
+     * node.
+     * They are also not if the moving segment endpoints connect to more than
+     * one other way segment.
+     */
+    @Override
+    AlignableStatus areSegsAlignable() {
+        AlignableStatus status = super.areSegsAlignable();
+
+        // The constructor may already have reported some problems: check.
+        if (alignableStatKeepAngles != AlignableStatus.ALGN_VALID)
+            return alignableStatKeepAngles;
+
+        // The superclass may have reported problems: check.
+        if (status != AlignableStatus.ALGN_VALID)
+            return status;
+
+        // Check the remainder of the potential problems: -
+        // Check for the number of segments connecting to the alignee endpoints
+        for (Node nA : displaceableNodes) {
+            if (nA.getEastNorth().equals(pivot)) {
+                // Pivots set to endpoints are exempt from this check
+                continue;
+            } else {
+                // This node should not connect to more than one other way segment
+                if (isReferredByNOtherWaySegments(nA, 2))
+                    return AlignableStatus.ALGN_INV_TOOMANY_CONNECTED_WS;
+            }
+        }
+
+        // In all other cases alignment is possible
+        return AlignableStatus.ALGN_VALID;
+    }
+
+
+
+
+    private boolean isReferredByNOtherWaySegments(Node node, int numWSeg) {
+
+        Collection<WaySegment> coll_ws = algnSeg.getAdjacentWaySegments(node);
+        if (coll_ws != null)
+            return coll_ws.size() >= numWSeg;
+            else
+                return false;
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysCmdKeepLength.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysCmdKeepLength.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysCmdKeepLength.java	(revision 27348)
@@ -0,0 +1,324 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.SwingConstants;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * Executes one of the desired geometric actions
+ * needed to align the ways.
+ * 
+ * @author tilusnet <tilusnet@gmail.com>
+ */
+
+public class AlignWaysCmdKeepLength extends Command {
+
+    enum AlignableStatus {
+        ALGN_VALID,
+        ALGN_INV_CONNECTED_UNSHARED_PIVOT,
+        ALGN_INV_OUTSIDE_WORLD,
+        ALGN_INV_TOOMANY_CONNECTED_WS,      // for AlignWaysCmdKeepAngles
+        ALGN_INV_ANGLE_PRESERVING_CONFLICT  // for AlignWaysCmdKeepAngles
+    }
+    final AlignWaysAlgnSegment algnSeg;
+
+    /**
+     * The nodes that will move as result of the aligning.
+     */
+    final Collection<Node> displaceableNodes;
+
+    /**
+     * Maps the alignee nodes with their calculated coordinates.
+     * Useful for validation.
+     */
+    final Map<Node,EastNorth> calculatedNodes = new HashMap<Node,EastNorth>();
+
+
+    /**
+     * Set of nodes that were affected by the last command execution.
+     */
+    Collection<Node> lastAffectedNodes;
+
+    /**
+     * Pivot point
+     */
+    final EastNorth pivot;
+
+    /**
+     * Computed rotation angle to rotate the segment
+     * 
+     */
+    private final double rotationAngle;
+
+    /**
+     * List of all old states of the objects.
+     */
+    final Map<Node, Node> oldNodes = new HashMap<Node, Node>();
+
+    /**
+     * Creates an AlignWaysRotateCommand.
+     * TODO Limitation (for now): constructor assumes areSegsAlignable() returns true.
+     */
+    public AlignWaysCmdKeepLength() {
+
+        lastAffectedNodes = null;
+
+        algnSeg = AlignWaysSegmentMgr.getInstance(Main.map.mapView)
+                .getAlgnSeg();
+        WaySegment algnWS = algnSeg.getSegment();
+        WaySegment refWS = AlignWaysSegmentMgr.getInstance(Main.map.mapView)
+                .getRefSeg().getSegment();
+
+        this.pivot = algnSeg.getCurrPivotCoord();
+        this.displaceableNodes = algnSeg.getSegmentEndPoints();
+
+        EastNorth enRefNode1 = refWS.way.getNode(refWS.lowerIndex)
+                .getEastNorth();
+        EastNorth enRefNode2 = refWS.way.getNode(refWS.lowerIndex + 1)
+                .getEastNorth();
+
+        EastNorth enAlgnNode1 = algnWS.way.getNode(algnWS.lowerIndex)
+                .getEastNorth();
+        EastNorth enAlgnNode2 = algnWS.way.getNode(algnWS.lowerIndex + 1)
+                .getEastNorth();
+
+        // Calculate the rotation angle
+        double refAngle = Math.atan2(enRefNode1.north() - enRefNode2.north(),
+                enRefNode1.east() - enRefNode2.east());
+        double algnAngle = Math.atan2(
+                enAlgnNode1.north() - enAlgnNode2.north(), enAlgnNode1.east()
+                - enAlgnNode2.east());
+
+        rotationAngle = normalise_angle(refAngle - algnAngle);
+
+        // Rotate using the rotation matrix known in algebra:
+        // [ x' ] = [ cos(Phi) -sin(Phi) ] [ x ]
+        // [ y' ]   [ sin(Phi)  cos(Phi) ] [ y ]
+        for (Node n : displaceableNodes) {
+            double cosPhi = Math.cos(rotationAngle);
+            double sinPhi = Math.sin(rotationAngle);
+            EastNorth oldEastNorth = n.getEastNorth();
+            double x = oldEastNorth.east() - pivot.east();
+            double y = oldEastNorth.north() - pivot.north();
+            double nx = cosPhi * x - sinPhi * y + pivot.east();
+            double ny = sinPhi * x + cosPhi * y + pivot.north();
+
+            calculatedNodes.put(n, new EastNorth(nx, ny));
+        }
+
+
+        /*
+         * For debug only
+         * String s = "Ref Angle: " + refAngle + " (" + Math.toDegrees(refAngle)
+         * + ")\n";
+         * s += "Algn Angle: " + algnAngle + " (" + Math.toDegrees(algnAngle)
+         * + ")\n";
+         * s += "Rotation angle: " + rotationAngle + " ("
+         * + Math.toDegrees(rotationAngle) + ")";
+         */
+
+    }
+
+    /**
+     * Helper for actually rotating the nodes.
+     * 
+     * @param setModified
+     *            - true if rotated nodes should be flagged "modified"
+     */
+    private void rotateNodes(boolean setModified) {
+
+        // "Backup" state
+        lastAffectedNodes = new HashSet<Node>();
+        for (Node n : this.displaceableNodes) {
+            Node nodeBackup = new Node(n);
+            // Set other fields that clone doesn't copy
+            nodeBackup.setEastNorth(n.getEastNorth());
+            oldNodes.put(n, nodeBackup);
+
+            lastAffectedNodes.add(n);
+        }
+
+        // Physical change occurs here:
+        for (Node n : displaceableNodes) {
+            n.setEastNorth(calculatedNodes.get(n));
+            if (setModified) {
+                n.setModified(true);
+            }
+        }
+        algnSeg.updatePivotsEndpoints();
+    }
+
+    /**
+     * Make sure angle is in interval ( -Pi/2, Pi/2 ].
+     */
+    private double normalise_angle(double a) {
+        while (a > Math.PI) {
+            a -= 2 * Math.PI;
+        }
+        while (a <= -Math.PI) {
+            a += 2 * Math.PI;
+        }
+
+        if (a > Math.PI / 2) {
+            a -= Math.PI;
+        } else if (a < -Math.PI / 2) {
+            a += Math.PI;
+        }
+        return a;
+    }
+
+    @Override
+    public JLabel getDescription() {
+        return new JLabel(tr("Align way segment"), ImageProvider.get("",
+                "alignways"), SwingConstants.HORIZONTAL);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.openstreetmap.josm.command.Command#fillModifiedData(java.util.Collection
+     * , java.util.Collection, java.util.Collection)
+     */
+    @Override
+    public void fillModifiedData(Collection<OsmPrimitive> modified,
+            Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        for (OsmPrimitive osm : displaceableNodes) {
+            modified.add(osm);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.openstreetmap.josm.command.Command#executeCommand()
+     */
+    @Override
+    public boolean executeCommand() {
+        rotateNodes(true);
+        return true;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.openstreetmap.josm.command.Command#undoCommand()
+     */
+    @Override
+    public void undoCommand() {
+        for (Node n : displaceableNodes) {
+            Node oldNode = oldNodes.get(n);
+            n.setCoor(oldNode.getCoor());
+        }
+        algnSeg.updatePivotsEndpoints();
+    }
+
+    public Collection<Node> getPrevAffectedNodes() {
+        return lastAffectedNodes;
+    }
+
+    /**
+     * Returns true if the two selected segments are alignable.
+     * They are not if they are connected *and* the pivot is not the connection
+     * node.
+     */
+    AlignableStatus areSegsAlignable() {
+        Collection<Node> algnNodes = displaceableNodes;
+        Collection<Node> refNodes = AlignWaysSegmentMgr
+                .getInstance(Main.map.mapView).getRefSeg()
+                .getSegmentEndPoints();
+
+        // First check if the pivot node of the alignee exists in the reference:
+        // in this case the pivot is the shared node and alignment is possible
+        for (Node nR : refNodes) {
+            if (nR.getEastNorth().equals(pivot))
+                return AlignableStatus.ALGN_VALID;
+        }
+
+        // Otherwise if the segments are connected, alignment is not possible
+        for (Node nA : algnNodes) {
+            for (Node nR : refNodes) {
+                if (nA.equals(nR))
+                    return AlignableStatus.ALGN_INV_CONNECTED_UNSHARED_PIVOT;
+            }
+        }
+
+        // Deny action if the nodes would end up outside world
+        for (EastNorth en : calculatedNodes.values()) {
+
+            if (Projections.inverseProject(en).isOutSideWorld())
+                return AlignableStatus.ALGN_INV_OUTSIDE_WORLD;
+
+        }
+
+        // In all other cases alignment is possible
+        return AlignableStatus.ALGN_VALID;
+    }
+
+    /**
+     * Validates the circumstances of the alignment command to be executed.
+     * 
+     * @return true if the aligning action can be done, false otherwise.
+     */
+    public boolean executable() {
+        AlignableStatus stat = areSegsAlignable();
+
+        if (stat != AlignableStatus.ALGN_VALID) {
+            reportInvalidCommand(stat);
+            return false;
+        } else
+            // Action valid
+            return true;
+    }
+
+    /**
+     * Reports invalid alignable statuses on screen in dialog boxes.
+     * 
+     * @param stat The invalid status to report
+     */
+    void reportInvalidCommand(AlignableStatus stat) {
+        String statMsg;
+
+        switch (stat) {
+        case ALGN_INV_CONNECTED_UNSHARED_PIVOT:
+            statMsg = tr("Please select two segments that don''t share any nodes\n"
+                    + " or put the pivot on their common node.\n");
+            break;
+        case ALGN_INV_OUTSIDE_WORLD:
+            statMsg = tr("Aligning would result nodes 'outside the world'.\n"
+                    + "Alignment not possible.\n");
+            break;
+        default:
+            statMsg = tr("Undocumented problem occured.\n");
+            break;
+        }
+
+        JOptionPane.showMessageDialog(
+                Main.parent,
+                tr(statMsg),
+                tr("AlignWayS: Alignment not possible"),
+                JOptionPane.WARNING_MESSAGE
+                );
+
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysDialog.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysDialog.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysDialog.java	(revision 27348)
@@ -0,0 +1,171 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JToggleButton;
+
+import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ *
+ */
+public class AlignWaysDialog extends ToggleDialog implements ActionListener {
+
+    private static final long serialVersionUID = 2949349330750246969L;
+
+    private final JLabel infoText;
+    enum AligningModeOption {
+        ALGN_OPT_KEEP_LENGTH,
+        ALGN_OPT_KEEP_ANGLE
+    }
+    AligningModeOption awOpt;
+    JPanel activateInfoPanel, modesPanel, dlgPane;
+
+
+    public AlignWaysDialog(AlignWaysMode awMode) {
+        super(tr("Align Way Segments: Modes"), "alignways_cfg", tr("Align Ways control panel"),
+                null, 70);
+
+        infoText = new JLabel();
+
+        dlgPane = new JPanel();
+        dlgPane.setLayout(new GridLayout(0, 1, 20, 20));
+
+
+        // Create the panel that shows instruction when Align Ways mode is *not* active
+        activateInfoPanel = new JPanel();
+        activateInfoPanel.setLayout(new BoxLayout(activateInfoPanel, BoxLayout.PAGE_AXIS));
+        activateInfoPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        JPanel lbl1Pnl = new JPanel();
+        lbl1Pnl.setLayout(new FlowLayout(FlowLayout.LEADING));
+        JLabel lbl1 = new JLabel(tr("This panel activates in Align Ways mode:"));
+        lbl1Pnl.add(lbl1);
+        activateInfoPanel.add(lbl1Pnl);
+
+        JPanel tglbtnPnl = new JPanel();
+        tglbtnPnl.setLayout(new FlowLayout(FlowLayout.CENTER));
+        JToggleButton tglBtn = new JToggleButton(awMode);
+        tglBtn.setPreferredSize(new Dimension(50, 50));
+        tglBtn.setText(null);
+        tglbtnPnl.add(tglBtn);
+        activateInfoPanel.add(tglbtnPnl);
+
+
+        // Create the Align Ways mode control panel for when Align Ways *is* active
+        modesPanel = new JPanel();
+        modesPanel.setLayout(new BoxLayout(modesPanel, BoxLayout.PAGE_AXIS));
+        /*
+		modesPanel.setBorder(BorderFactory.createCompoundBorder(
+				BorderFactory.createEmptyBorder(10, 10, 10, 10),
+				BorderFactory.createTitledBorder(tr("Align with:")))
+				);
+         */
+        modesPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+        modesPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+        JRadioButton btnKeepLength = new JRadioButton(tr("Length preserved"));
+        btnKeepLength.setActionCommand("awOptKeepLen");
+        btnKeepLength.addActionListener(this);
+
+        JRadioButton btnKeepAngle = new JRadioButton(tr("Angle preserved"));
+        btnKeepAngle.setActionCommand("awOptKeepAng");
+        btnKeepAngle.addActionListener(this);
+
+        ButtonGroup btnGrp = new ButtonGroup();
+        btnGrp.add(btnKeepLength);
+        btnGrp.add(btnKeepAngle);
+
+        modesPanel.add(new JLabel(tr("Align with:")));
+        modesPanel.add(Box.createRigidArea(new Dimension(0, 5)));
+        modesPanel.add(btnKeepLength);
+        modesPanel.add(btnKeepAngle);
+        modesPanel.add(Box.createRigidArea(new Dimension(0, 10)));
+        // modesPanel.add(new JSeparator(SwingConstants.HORIZONTAL));
+        infoText.setBorder(BorderFactory.createCompoundBorder(
+                BorderFactory.createEtchedBorder(),
+                BorderFactory.createEmptyBorder(10, 10, 10, 10) )
+                );
+        modesPanel.add(infoText);
+
+
+
+        // Start inactivated - JOSM cannot start directly in awMode
+        activate(false);
+
+        // It looks like I don't have other choice for placement than this;
+        // ToggleDialog already defines its layout as BoxLayout
+        add(dlgPane, BorderLayout.CENTER);
+
+        // Select length preserved mode by default
+        btnKeepLength.doClick();
+
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (e.getActionCommand() == "awOptKeepLen") {
+            awOpt = AligningModeOption.ALGN_OPT_KEEP_LENGTH;
+            infoText.setText(tr("<html>Aligns the way segment to the reference so that its length is preserved.</html>"));
+        } else if (e.getActionCommand() == "awOptKeepAng") {
+            awOpt = AligningModeOption.ALGN_OPT_KEEP_ANGLE;
+            infoText.setText(tr("<html>Aligns the way segment to the reference so that the angles of its adjacent segments are preserved.<br/>" +
+                    "The length of the aligned segment is likely to change as result.</html>"));
+        }
+    }
+
+    /**
+     * @return the awOpt
+     */
+    public AligningModeOption getAwOpt() {
+        return awOpt;
+    }
+
+
+    /**
+     * @param action If set to true, the dialog will show the mode options, otherwise it will show some instructions
+     */
+    public void activate(boolean activeMode) {
+
+        if (activeMode == true) {
+        	// we're in alignways mode 
+            activateInfoPanel.setVisible(false);
+            modesPanel.setVisible(true);
+            this.setPreferredSize(new Dimension(0, 200));
+
+            dlgPane.remove(activateInfoPanel);
+            dlgPane.add(modesPanel);
+            dlgPane.validate();
+        } else {
+        	// we're not in alignways mode 
+            activateInfoPanel.setVisible(true);
+            modesPanel.setVisible(false);
+            this.setPreferredSize(new Dimension(0, 70));
+
+            dlgPane.remove(modesPanel);
+            dlgPane.add(activateInfoPanel);
+            dlgPane.validate();
+        }
+
+    }
+
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysMode.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysMode.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysMode.java	(revision 27348)
@@ -0,0 +1,243 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Image;
+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.JButton;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.gui.IconToggleButton;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.layer.Layer;
+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 MapViewPaintable */{
+
+    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.GROUP_EDIT, Shortcut.SHIFT_DEFAULT),
+                        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);
+        setCurrentState(noneSelected);
+    }
+
+
+    @Override
+    public void exitMode() {
+        super.exitMode();
+
+        AlignWaysPlugin.getAwDialog().activate(false);
+        IconToggleButton optBtn = AlignWaysPlugin.getOptBtn();
+        if (optBtn.isSelected()) {
+            // The option panel is switched off
+            optBtn.doClick();
+        }
+
+        setCurrentState(noneSelected);
+        Main.map.mapView.removeMouseListener(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);
+                    }
+                }
+            }
+        }
+
+        // Activate the Align Ways button if we have enough selections
+        if (currentState == bothSelected) {
+            AlignWaysPlugin.getAwAction().setEnabled(true);
+        } else {
+            AlignWaysPlugin.getAwAction().setEnabled(false);
+        }
+        Main.map.mapView.repaint();
+    }
+
+    /**
+     * @param currentState
+     *            One of the AlignWays states
+     */
+    public void setCurrentState(AlignWaysState currentState) {
+        this.currentState = currentState;
+        currentState.setHelpText();
+
+        if (currentState == noneSelected) {
+            awSegs.cleanupWays();
+            // TODO getCurrentDataSet 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.
+            if (getCurrentDataSet() != null) {
+                getCurrentDataSet().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;
+    }
+
+    /**
+     * @return the current state
+     */
+    public AlignWaysState getCurrentState() {
+        return currentState;
+    }
+
+    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", new Integer(AlignWaysPlugin.AlignWaysMajorVersion).toString());
+
+    }
+
+    /* (non-Javadoc)
+     * @see org.openstreetmap.josm.actions.mapmode.MapMode#layerIsSupported(org.openstreetmap.josm.gui.layer.Layer)
+     */
+    @Override
+    public boolean layerIsSupported(Layer l) {
+        if (l == null)
+            return false;
+        else
+            return true;
+    }
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysPlugin.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysPlugin.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysPlugin.java	(revision 27348)
@@ -0,0 +1,81 @@
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import javax.swing.JMenuItem;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.gui.IconToggleButton;
+import org.openstreetmap.josm.gui.MainMenu;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ *
+ */
+
+public class AlignWaysPlugin extends Plugin {
+
+    static AlignWaysMode awMode;
+    private final IconToggleButton btn;
+    static JMenuItem alignWaysMenuItem;
+    static JosmAction awAction;
+    static AlignWaysDialog awDialog;
+    static IconToggleButton optBtn;
+
+    // The major version is e.g. used to decide when to trigger What's New windows
+    public static final int AlignWaysMajorVersion = 2;
+
+    public AlignWaysPlugin(PluginInformation info) {
+        super(info);
+        awMode = new AlignWaysMode(Main.map, "alignways", tr("Align Ways mode"));
+        btn = new IconToggleButton(awMode);
+        btn.setVisible(true);
+        Main.main.menu.toolsMenu.addSeparator();
+        awAction = new AlignWaysAction();
+        alignWaysMenuItem = MainMenu.add(Main.main.menu.toolsMenu, awAction);
+        awDialog = new AlignWaysDialog(awMode);
+    }
+
+    @Override
+    public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
+        if(newFrame != null) {
+            optBtn = newFrame.addToggleDialog(AlignWaysPlugin.getAwDialog());
+        }
+        if (Main.map != null) {
+            Main.map.addMapMode(btn);
+        }
+    }
+
+    /**
+     * @return the awAction
+     */
+    public static JosmAction getAwAction() {
+        return awAction;
+    }
+
+    /**
+     * @return the awMode
+     */
+    public static AlignWaysMode getAwMode() {
+        return awMode;
+    }
+
+    /**
+     * @return the awDialog
+     */
+    public static AlignWaysDialog getAwDialog() {
+        return awDialog;
+    }
+
+    /**
+     * @return the optBtn
+     */
+    public static IconToggleButton getOptBtn() {
+        return optBtn;
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysRefSegment.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysRefSegment.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysRefSegment.java	(revision 27348)
@@ -0,0 +1,27 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import java.awt.Color;
+import java.awt.Point;
+
+import org.openstreetmap.josm.gui.MapView;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com> The basic segment treated as reference.
+ * 
+ */
+public class AlignWaysRefSegment extends AlignWaysSegment {
+
+    // Note: segment may be null. This is normal.
+
+    public AlignWaysRefSegment(MapView mapview, Point p)
+    throws IllegalArgumentException {
+        super(mapview, p);
+        setSegment(getNearestWaySegment(p));
+        segmentColor = Color.GREEN;
+
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegment.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegment.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegment.java	(revision 27348)
@@ -0,0 +1,151 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.geom.Line2D;
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.MapViewPaintable;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ * 
+ */
+public class AlignWaysSegment implements MapViewPaintable {
+
+	protected WaySegment segment;
+	protected MapView mapview;
+	protected Color segmentColor = Color.WHITE;
+	protected Collection<Node> segmentEndPoints;
+
+	public AlignWaysSegment(MapView mapview, Point p) throws IllegalArgumentException {
+		if (mapview == null)
+			throw new IllegalArgumentException(tr(
+					"Parameter ''{0}'' must not be null", "mapview"));
+		if (p == null)
+			throw new IllegalArgumentException(tr(
+					"Parameter ''{0}'' must not be null", "p"));
+
+		this.mapview = mapview;
+	}
+
+	void setSegment(WaySegment segment) {
+		this.segment = segment;
+		if (segment != null) {
+			setSegmentEndpoints(segment);
+			mapview.addTemporaryLayer(this);
+		}
+	}
+
+
+	void setSegmentEndpoints(WaySegment segment) {
+		if (segment != null) {
+			Node node1 = segment.way.getNode(segment.lowerIndex);
+			Node node2 = segment.way.getNode(segment.lowerIndex + 1);
+
+			segmentEndPoints = new HashSet<Node>();
+			segmentEndPoints.add(node1);
+			segmentEndPoints.add(node2);
+
+		}
+	}
+
+	protected WaySegment getNearestWaySegment(Point p) {
+
+		return mapview.getNearestWaySegment(p, OsmPrimitive.isUsablePredicate);
+
+	}
+
+	public void destroy() {
+		if (segment != null) {
+			mapview.removeTemporaryLayer(this);
+		}
+	}
+
+	public WaySegment getSegment() {
+		return segment;
+	}
+
+	public Collection<Node> getSegmentEndPoints() {
+		return segmentEndPoints;
+	}
+
+	@Override
+	public void paint(Graphics2D g, MapView mv, Bounds bbox) {
+		highlightSegment(segmentColor, g, mv);
+	}
+
+	protected void highlightSegment(Color c, Graphics2D g, MapView mv) {
+
+		g.setColor(c);
+		g.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND,
+				BasicStroke.JOIN_ROUND));
+		drawSegment(g, mv);
+
+	}
+
+	protected void drawSegment(Graphics2D g, MapView mv) {
+		Node n1 = segment.way.getNode(segment.lowerIndex);
+		Node n2 = segment.way.getNode(segment.lowerIndex + 1);
+
+		Line2D newline = new Line2D.Double(mv.getPoint(n1), mv.getPoint(n2));
+		g.draw(newline);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	 @Override
+	 public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((segment == null) ? 0 : segment.hashCode());
+		result = prime * result
+				+ ((segmentColor == null) ? 0 : segmentColor.hashCode());
+		return result;
+	 }
+
+	 /*
+	  * (non-Javadoc)
+	  * 
+	  * @see java.lang.Object#equals(java.lang.Object)
+	  */
+	 @Override
+	 public boolean equals(Object obj) {
+		 if (this == obj)
+			 return true;
+		 if (obj == null)
+			 return false;
+		 if (!(obj instanceof AlignWaysSegment))
+			 return false;
+		 AlignWaysSegment other = (AlignWaysSegment) obj;
+		 if (segment == null) {
+			 if (other.segment != null)
+				 return false;
+		 } else if (!segment.equals(other.segment))
+			 return false;
+		 /* Segment colour is ignored in comparison
+        if (segmentColor == null) {
+            if (other.segmentColor != null)
+                return false;
+        } else if (!segmentColor.equals(other.segmentColor))
+            return false;
+		  */
+		 return true;
+	 }
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegmentMgr.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegmentMgr.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSegmentMgr.java	(revision 27348)
@@ -0,0 +1,161 @@
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Point;
+import java.util.Collection;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.gui.MapView;
+
+/**
+ * Should be a singleton class. The active alignee and reference objects
+ * manager. Can request alignee, reference segment updates and pivot updates on
+ * these.
+ * 
+ * @author tilusnet <tilusnet@gmail.com>
+ * 
+ */
+public class AlignWaysSegmentMgr {
+
+    private volatile static AlignWaysSegmentMgr singleton;
+    private AlignWaysRefSegment refSeg = null;
+    private AlignWaysAlgnSegment algnSeg = null;
+    private final MapView mv;
+
+    private AlignWaysSegmentMgr(MapView mapView) {
+        mv = mapView;
+    }
+
+    public static AlignWaysSegmentMgr getInstance(MapView mapView) {
+        if (singleton == null) {
+            synchronized (AlignWaysSegmentMgr.class) {
+                if (singleton == null) {
+                    singleton = new AlignWaysSegmentMgr(mapView);
+                }
+            }
+        }
+        return singleton;
+    }
+
+    /**
+     * @param clickedPoint
+     *            Point nearby where user probably clicked
+     * @return true, if alignee changed, false otherwise
+     */
+    public boolean algnUpdate(Point clickedPoint) {
+
+        if (algnSeg != null) {
+            // Check first if there is a pivot point nearby that needs selection
+            if (algnSeg.updatePivot(clickedPoint))
+                // Updated pivot, alignee reference unchanged
+                return false;
+        }
+
+        // Previous attempt of pivot update unsuccessful, check alignee update
+        AlignWaysAlgnSegment tmpAlgnSeg = new AlignWaysAlgnSegment(mv,
+                clickedPoint);
+        if (tmpAlgnSeg.getSegment() == null)
+            return false;
+        else {
+            // Found a segment
+            // It may happen that the new segment is identical with the already
+            // selected reference:
+            if ((refSeg != null) && (tmpAlgnSeg.equals(refSeg))) {
+                // This action is then ignored (we won't clear the reference
+                // segment)
+                JOptionPane.showMessageDialog(Main.parent,
+                        tr("Segment to be aligned cannot be the same with the reference segment.\n" +
+                        "Please choose a different segment to be aligned."),
+                        tr("AlignWayS message"), JOptionPane.WARNING_MESSAGE);
+                return false;
+            }
+            // This will be a new alignee, old alignee (if any) will be lost:
+            if (algnSeg != null) {
+                algnSeg.destroy();
+            }
+
+            // Update alignee
+            algnSeg = tmpAlgnSeg;
+
+            return true;
+        }
+
+    }
+
+    /**
+     * @param clickedPoint
+     *            Point nearby where user probably clicked
+     * @return true, if reference changed, false otherwise
+     */
+    public boolean refUpdate(Point clickedPoint) {
+
+        AlignWaysRefSegment tmpRefSeg = new AlignWaysRefSegment(mv,
+                clickedPoint);
+        // TODO Have to check what happens when refSeg wasn't null previously
+        if (tmpRefSeg.getSegment() == null)
+            return false;
+        else {
+            // Found a segment
+            // It may happen that the new segment is identical with the already
+            // selected alignee:
+            if ((algnSeg != null) && (tmpRefSeg.equals(algnSeg))) {
+                // This action is then ignored (we won't clear the alignee
+                // segment)
+                JOptionPane.showMessageDialog(Main.parent,
+                        tr("Reference segment cannot be the same with the segment to be aligned.\n" +
+                        "Please choose a different reference segment."),
+                        tr("AlignWayS message"), JOptionPane.WARNING_MESSAGE);
+                return false;
+            }
+            // This will be a new reference, old reference (if any) will be lost:
+            if (refSeg != null) {
+                refSeg.destroy();
+            }
+
+            // Update reference
+            refSeg = tmpRefSeg;
+            return true;
+
+        }
+
+    }
+
+    /**
+     * @return Collection of the nodes that belong to the selected alignee.
+     */
+    public Collection<Node> getSelectedNodes() {
+        if (algnSeg != null)
+            return algnSeg.getSegmentEndPoints();
+        return null;
+    }
+
+    /**
+     * Performs "clean-up" on the initialised segments
+     */
+    public void cleanupWays() {
+        if (algnSeg != null) {
+            algnSeg.destroy();
+            algnSeg = null;
+        }
+        if (refSeg != null) {
+            refSeg.destroy();
+            refSeg = null;
+        }
+    }
+
+    public AlignWaysAlgnSegment getAlgnSeg() {
+        return algnSeg;
+    }
+
+    /**
+     * @return the refSeg
+     */
+    public AlignWaysRefSegment getRefSeg() {
+        return refSeg;
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelAlgnState.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelAlgnState.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelAlgnState.java	(revision 27348)
@@ -0,0 +1,30 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import org.openstreetmap.josm.Main;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ * 
+ */
+public class AlignWaysSelAlgnState extends AlignWaysState {
+
+    @Override
+    public void leftClick(AlignWaysMode alignWaysMode) {
+        // No state change, nothing to do
+    }
+
+    @Override
+    public void ctrlLClick(AlignWaysMode alignWaysMode) {
+        alignWaysMode.setCurrentState(alignWaysMode.getBothSelected());
+    }
+
+    @Override
+    public void setHelpText() {
+        Main.map.statusLine
+                .setHelpText("Ctrl-Click: select reference way segment; Alt-click: Clear selection");
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelBothState.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelBothState.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelBothState.java	(revision 27348)
@@ -0,0 +1,31 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import org.openstreetmap.josm.Main;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ * 
+ */
+public class AlignWaysSelBothState extends AlignWaysState {
+
+    @Override
+    public void leftClick(AlignWaysMode alignWaysMode) {
+        // No state change, nothing to do
+    }
+
+    @Override
+    public void ctrlLClick(AlignWaysMode alignWaysMode) {
+        // No state change, nothing to do
+    }
+
+    @Override
+    public void setHelpText() {
+        Main.map.statusLine
+        .setHelpText(AlignWaysPlugin.getAwAction().getShortcut().getKeyText() +
+                ": Align segments; Alt-click: Clear selection");
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelNoneState.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelNoneState.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelNoneState.java	(revision 27348)
@@ -0,0 +1,33 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import org.openstreetmap.josm.Main;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ * 
+ */
+public class AlignWaysSelNoneState extends AlignWaysState {
+
+    @Override
+    public void leftClick(AlignWaysMode alignWaysMode) {
+        // Reference way segment selected successfully
+        alignWaysMode.setCurrentState(alignWaysMode.getAligneeSelected());
+
+    }
+
+    @Override
+    public void ctrlLClick(AlignWaysMode alignWaysMode) {
+        // Reference way segment selected successfully
+        alignWaysMode.setCurrentState(alignWaysMode.getReferenceSelected());
+    }
+
+    @Override
+    public void setHelpText() {
+        Main.map.statusLine
+        .setHelpText("Ctrl-click: select reference way segment; Click: select way segment to be aligned");
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelRefState.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelRefState.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysSelRefState.java	(revision 27348)
@@ -0,0 +1,30 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import org.openstreetmap.josm.Main;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ * 
+ */
+public class AlignWaysSelRefState extends AlignWaysState {
+
+    @Override
+    public void leftClick(AlignWaysMode alignWaysMode) {
+        alignWaysMode.setCurrentState(alignWaysMode.getBothSelected());
+    }
+
+    @Override
+    public void ctrlLClick(AlignWaysMode alignWaysMode) {
+        // No state change, nothing to do
+    }
+
+    @Override
+    public void setHelpText() {
+        Main.map.statusLine
+                .setHelpText("Click: select way segment to be aligned; Alt-click: Clear selection");
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysState.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysState.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysState.java	(revision 27348)
@@ -0,0 +1,26 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import org.openstreetmap.josm.Main;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ *
+ */
+public abstract class AlignWaysState {
+
+    public abstract void leftClick(AlignWaysMode alignWaysMode);
+
+    public abstract void ctrlLClick(AlignWaysMode alignWaysMode);
+
+    public abstract void setHelpText();
+
+    public void altLClick(AlignWaysMode alignWaysMode) {
+        alignWaysMode.setCurrentState(alignWaysMode.getNoneSelected());
+        Main.map.statusLine
+        .setHelpText("Ctrl-Click: select reference way segment; Click: select way segment to be aligned");
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysTipsPanel.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysTipsPanel.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysTipsPanel.java	(revision 27348)
@@ -0,0 +1,209 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Cursor;
+import java.awt.Dimension;
+
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingConstants;
+
+import org.jdesktop.layout.GroupLayout;
+import org.jdesktop.layout.LayoutStyle;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ *
+ */
+public class AlignWaysTipsPanel extends JPanel {
+
+    private static final long serialVersionUID = -8583989497599985140L;
+
+    public AlignWaysTipsPanel() {
+        initComponents();
+    }
+
+    private void initComponents() {
+
+        Title = new JPanel();
+        WelcomeTo = new JLabel();
+        Icon = new JLabel();
+        separator = new JSeparator();
+        Intro = new JPanel();
+        introText = new JLabel();
+        scrollableSteps = new JScrollPane();
+        steps = new JPanel();
+        step01 = new JLabel();
+        step02 = new JLabel();
+        step03 = new JLabel();
+        step04 = new JLabel();
+        lastHint = new JLabel();
+        dontShow = new JCheckBox();
+
+        setAutoscrolls(true);
+
+        WelcomeTo.setText("<html>\n<div style=\"font-family: \"sans-serif\"; font-weight: bold; font-style: italic;\">\n<span style=\"font-size: large;\">"
+                + tr("Welcome to the</span><br>\n<span style=\"font-size: xx-large;\">AlignWay<span style=\"color: rgb(204, 85, 0);\">S</span> Plugin<br>\n</span>"
+                        + "<span style=\"font-size: medium;\"><br>\n...or it rather should be called <br>\n<span style=\"font-size: large;\">AlignWayS(egments)</span> Plugin...")
+                        + "</span>\n</div>\n</html>");
+
+        WelcomeTo.setVerticalAlignment(SwingConstants.TOP);
+        WelcomeTo.setPreferredSize(new Dimension(400, 128));
+
+        Icon.setIcon(new ImageIcon(getClass().getResource("/images/tipsdialog/alignways128.png"))); // NOI18N
+        GroupLayout TitleLayout = new GroupLayout(Title);
+        Title.setLayout(TitleLayout);
+        TitleLayout.setHorizontalGroup(
+                TitleLayout.createParallelGroup(GroupLayout.LEADING)
+                .add(GroupLayout.TRAILING, TitleLayout.createSequentialGroup()
+                        .add(WelcomeTo, GroupLayout.DEFAULT_SIZE, 396, Short.MAX_VALUE)
+                        .addPreferredGap(LayoutStyle.RELATED)
+                        .add(Icon, GroupLayout.PREFERRED_SIZE, 132, GroupLayout.PREFERRED_SIZE))
+                );
+        TitleLayout.setVerticalGroup(
+                TitleLayout.createParallelGroup(GroupLayout.LEADING)
+                .add(TitleLayout.createSequentialGroup()
+                        .add(Icon)
+                        .addContainerGap())
+                        .add(WelcomeTo, GroupLayout.DEFAULT_SIZE, 146, Short.MAX_VALUE)
+                );
+
+        Intro.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+
+        introText.setText(tr("<html>\n<p style=\"font-family: sans-serif; font-weight: bold;\">AlignWays will\nhelp you to align two way segments. This can be handy when for instance\nyou sketch the outlines of a building and want its side to be parallel\nwith a street or road.<br>\n<br>\nSome tips may help before you start:\n</p>\n</html>\n\n"));
+        introText.setVerticalAlignment(SwingConstants.TOP);
+
+        scrollableSteps.setBorder(null);
+        scrollableSteps.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+
+        step01.setIcon(new ImageIcon(getClass().getResource("/images/tipsdialog/hlpRefSel.png"))); // NOI18N
+        step01.setText(tr("<html>\n<div style=\"font-family: sans-serif;\">\n<ul>\n<li><b>Select a reference segment.</b> You can do this by <b><i><span style=\"color:green\">Ctrl-click</span></i></b>ing\non a segment. The other, to be aligned segment will become parallel to\nthis one. </li>\n</ul>\n</div>\n</html>\n\n"));
+        step01.setVerticalAlignment(SwingConstants.TOP);
+
+        step02.setIcon(new ImageIcon(getClass().getResource("/images/tipsdialog/hlpAlgSel.png"))); // NOI18N
+        step02.setText(tr("<html>\n<div style=\"font-family:sans-serif\">\n<ul>\n  <li><b>Select the to be aligned segment.</b> You can do this by simply <b><i><span style=\"color:green\">click</span></i></b>ing on a different segment. \nThe rotation pivot will be highlighted by default in the centre of the segment.\n  </li>\n</ul>\n</div>\n</html>\n\n"));
+        step02.setVerticalAlignment(SwingConstants.TOP);
+
+        step03.setIcon(new ImageIcon(getClass().getResource("/images/tipsdialog/hlpPvtSel.png"))); // NOI18N
+        step03.setText(tr("<html>\n<div style=\"font-family:sans-serif\">\n<ul>\n  <li>Optionally <b>change the rotation pivot point</b>. In order to get parallel with the reference segment, the to be aligned segment will rotate around this point. You can choose the two extremities or the centre of the segment by <b><i><span style=\"color:green\">click</span></i></b>ing nearby. \n  </li>\n</ul>\n</div>\n</html>\n\n"));
+        step03.setVerticalAlignment(SwingConstants.TOP);
+
+        step04.setIcon(new ImageIcon(getClass().getResource("/images/tipsdialog/hlpAlgCmd.png"))); // NOI18N
+        step04.setText(tr("<html>\n<div style=\"font-family:sans-serif\">\n<ul>\n  <li><b>Align the segments.</b> Press <b><i><span style=\"color:green\">{0}"
+                + "</span></i></b>. Alternatively you''ll find the command in the <b>Tools</b>\n menu or may want to place the action on the <b>toolbar</b>.\n  </li>\n</ul>\n</div>\n</html>\n\n",
+                AlignWaysPlugin.awAction.getShortcut().getKeyText()));
+        step04.setVerticalAlignment(SwingConstants.TOP);
+
+        lastHint.setText(tr("<html>\n<div style=\"font-family:sans-serif\">\n<b>Last hint:</b> There is an easy way to start over your selections if you want: <b><i><span style=\"color:green\">Alt-Click</span></i></b> somewhere on the map.\n</div>\n</html>\n\n"));
+        lastHint.setVerticalAlignment(SwingConstants.TOP);
+
+        GroupLayout stepsLayout = new GroupLayout(steps);
+        steps.setLayout(stepsLayout);
+        stepsLayout.setHorizontalGroup(
+                stepsLayout.createParallelGroup(GroupLayout.LEADING)
+                .add(stepsLayout.createSequentialGroup()
+                        .addContainerGap()
+                        .add(stepsLayout.createParallelGroup(GroupLayout.TRAILING)
+                                .add(GroupLayout.LEADING, lastHint, 0, 0, Short.MAX_VALUE)
+                                .add(GroupLayout.LEADING, step04, 0, 0, Short.MAX_VALUE)
+                                .add(GroupLayout.LEADING, step03, 0, 0, Short.MAX_VALUE)
+                                .add(GroupLayout.LEADING, step02, 0, 0, Short.MAX_VALUE)
+                                .add(GroupLayout.LEADING, step01, GroupLayout.DEFAULT_SIZE, 496, Short.MAX_VALUE))
+                                .add(18, 18, 18))
+                );
+        stepsLayout.setVerticalGroup(
+                stepsLayout.createParallelGroup(GroupLayout.LEADING)
+                .add(stepsLayout.createSequentialGroup()
+                        .add(step01, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(LayoutStyle.RELATED)
+                        .add(step02, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(LayoutStyle.RELATED)
+                        .add(step03, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(LayoutStyle.RELATED)
+                        .add(step04, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(LayoutStyle.RELATED)
+                        .add(lastHint, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addContainerGap(22, Short.MAX_VALUE))
+                );
+
+        scrollableSteps.setViewportView(steps);
+
+        dontShow.setText(tr("Don''t show this again"));
+
+        GroupLayout IntroLayout = new GroupLayout(Intro);
+        Intro.setLayout(IntroLayout);
+        IntroLayout.setHorizontalGroup(
+                IntroLayout.createParallelGroup(GroupLayout.LEADING)
+                .add(IntroLayout.createSequentialGroup()
+                        .addContainerGap()
+                        .add(dontShow, GroupLayout.PREFERRED_SIZE, 245, GroupLayout.PREFERRED_SIZE)
+                        .addContainerGap(283, Short.MAX_VALUE))
+                        .add(scrollableSteps, GroupLayout.DEFAULT_SIZE, 534, Short.MAX_VALUE)
+                        .add(introText, GroupLayout.DEFAULT_SIZE, 534, Short.MAX_VALUE)
+                );
+        IntroLayout.setVerticalGroup(
+                IntroLayout.createParallelGroup(GroupLayout.LEADING)
+                .add(GroupLayout.TRAILING, IntroLayout.createSequentialGroup()
+                        .add(introText, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(LayoutStyle.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .add(scrollableSteps, GroupLayout.PREFERRED_SIZE, 209, GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(LayoutStyle.UNRELATED)
+                        .add(dontShow)
+                        .addContainerGap())
+                );
+
+        GroupLayout layout = new GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+                layout.createParallelGroup(GroupLayout.LEADING)
+                .add(GroupLayout.TRAILING, layout.createSequentialGroup()
+                        .addContainerGap()
+                        .add(layout.createParallelGroup(GroupLayout.TRAILING)
+                                .add(GroupLayout.LEADING, separator, GroupLayout.DEFAULT_SIZE, 534, Short.MAX_VALUE)
+                                .add(Title, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .add(Intro, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                                .addContainerGap())
+                );
+        layout.setVerticalGroup(
+                layout.createParallelGroup(GroupLayout.LEADING)
+                .add(layout.createSequentialGroup()
+                        .addContainerGap()
+                        .add(Title, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(LayoutStyle.UNRELATED)
+                        .add(separator, GroupLayout.PREFERRED_SIZE, 17, GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(LayoutStyle.RELATED)
+                        .add(Intro, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addContainerGap(45, Short.MAX_VALUE))
+                );
+    }
+
+
+    private JLabel Icon;
+    private JPanel Intro;
+    private JPanel Title;
+    private JLabel WelcomeTo;
+    private JCheckBox dontShow;
+    private JLabel introText;
+    private JLabel lastHint;
+    private JScrollPane scrollableSteps;
+    private JSeparator separator;
+    private JLabel step01;
+    private JLabel step02;
+    private JLabel step03;
+    private JLabel step04;
+    private JPanel steps;
+
+    public boolean isChkBoxSelected() {
+        return dontShow.isSelected();
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysWhatsNewPanel.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysWhatsNewPanel.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/AlignWaysWhatsNewPanel.java	(revision 27348)
@@ -0,0 +1,143 @@
+/**
+ * 
+ */
+package com.tilusnet.josm.plugins.alignways;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Desktop;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ *
+ */
+public class AlignWaysWhatsNewPanel extends JPanel {
+
+
+    private static final long serialVersionUID = 3691600157957492583L;
+
+    public AlignWaysWhatsNewPanel() {
+        initComponents();
+    }
+
+    /*** WARNING: The following code section is generated by/for Matisse. Do not modify! ***/
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">
+    private void initComponents() {
+
+        lblWhatsNew = new javax.swing.JLabel();
+        icnLogo = new javax.swing.JLabel();
+        jSeparator1 = new javax.swing.JSeparator();
+        newItem1 = new javax.swing.JLabel();
+        btnHelpItem1 = new javax.swing.JButton();
+        newItem2 = new javax.swing.JLabel();
+
+        lblWhatsNew.setText("<html><div style=\"font-family: sans-serif; font-weight: bold; font-style: italic;\"><span style=\"font-size: large;\"><span style=\"font-size: x-large;\">What's new...</span></div></html>");
+
+        icnLogo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/wndialog/alignways64.png"))); // NOI18N
+
+        newItem1.setText("<html><div style=\"font-family: sans-serif;\"><ul style=\"margin-left: 20px;\"><li>Added <b>angle preserving</b> aligning mode</li></ul></div></html>");
+
+        btnHelpItem1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/wndialog/extlink10.png"))); // NOI18N
+        btnHelpItem1.setText("More Info");
+        btnHelpItem1.setToolTipText("Preserving angle aligning");
+        btnHelpItem1.setBorder(null);
+        btnHelpItem1.setBorderPainted(false);
+        btnHelpItem1.setFocusPainted(false);
+        btnHelpItem1.setFocusable(false);
+        btnHelpItem1.setIconTextGap(6);
+        btnHelpItem1.setOpaque(false);
+        btnHelpItem1.setPreferredSize(new java.awt.Dimension(69, 25));
+        btnHelpItem1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                btnHelpItem1ActionPerformed(evt);
+            }
+        });
+
+        newItem2.setText("<html><div style=\"font-family: sans-serif;\"><ul style=\"margin-left: 20px;\"><li>Various improvements and bugfixes</li></ul></div></html>");
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 349, Short.MAX_VALUE)
+                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                        .addComponent(lblWhatsNew, javax.swing.GroupLayout.DEFAULT_SIZE, 267, Short.MAX_VALUE)
+                        .addGap(18, 18, 18)
+                        .addComponent(icnLogo))
+                    .addGroup(layout.createSequentialGroup()
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                            .addComponent(newItem2, javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(newItem1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 249, Short.MAX_VALUE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(btnHelpItem1, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(icnLogo)
+                    .addComponent(lblWhatsNew, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addGap(20, 20, 20)
+                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(newItem1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(btnHelpItem1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(newItem2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(23, Short.MAX_VALUE))
+        );
+    }// </editor-fold>
+
+	private void btnHelpItem1ActionPerformed(java.awt.event.ActionEvent evt) {
+	   openURI();
+	}
+
+    // Variables declaration - do not modify
+    private javax.swing.JButton btnHelpItem1;
+    private javax.swing.JLabel icnLogo;
+    private javax.swing.JSeparator jSeparator1;
+    private javax.swing.JLabel lblWhatsNew;
+    private javax.swing.JLabel newItem1;
+    private javax.swing.JLabel newItem2;
+    // End of variables declaration
+
+
+    private void openURI()  {
+        if (Desktop.isDesktopSupported()) {
+          try {
+            URI uri = new URI("http://wiki.openstreetmap.org/wiki/JOSM/Plugins/AlignWayS#Preserving_angles");
+            Desktop.getDesktop().browse(uri);
+          } catch (URISyntaxException ex) {
+                Logger.getLogger(AlignWaysWhatsNewPanel.class.getName()).log(Level.SEVERE, null, ex);
+          } catch (IOException e) { 
+              JOptionPane.showMessageDialog(this, e, "Errr...", JOptionPane.WARNING_MESSAGE);
+          }
+        } else { 
+             JOptionPane.showMessageDialog(this, "Browser not supported.", "Errr...", JOptionPane.WARNING_MESSAGE);
+        }
+    }
+    
+    /*** End of Matisse generated code section ***/
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/geometry/AlignWaysGeomLine.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/geometry/AlignWaysGeomLine.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/geometry/AlignWaysGeomLine.java	(revision 27348)
@@ -0,0 +1,182 @@
+package com.tilusnet.josm.plugins.alignways.geometry;
+
+
+/**
+ * @author tilusnet <tilusnet@gmail.com>
+ *
+ */
+public class AlignWaysGeomLine {
+
+	double coef_a, coef_b, coef_c;
+
+    public enum IntersectionStatus {
+        UNDEFINED,
+        INTERSECT_POINT,
+        LINES_PARALLEL,
+        LINES_OVERLAP
+    }
+
+    IntersectionStatus isectStat = IntersectionStatus.UNDEFINED;
+
+
+
+    /**
+     * Constructor defining the line with the coordinates of two points.
+     * @param x1 x coordinate of point 1.
+     * @param y1 y coordinate of point 1.
+     * @param x2 x coordinate of point 2.
+     * @param y2 y coordinate of point 2.
+     */
+    public AlignWaysGeomLine(double x1, double y1, double x2, double y2) {
+        // ax + by + c = 0
+        //
+        //     y2 - y1
+        // a = ------- (the slope);  b = -1; c = y1 - a*x1
+        //     x2 - x1
+        //
+        // See conversion guidelines: http://www.webmath.com/equline1.html
+        if (x1 == x2) {
+            // Vertical line (would result div by zero if equation applied)
+            coef_a = 1;
+            coef_b = 0;
+            coef_c = -x1;
+        } else {
+            coef_a = ((y2 - y1)/(x2 - x1));
+            coef_b = -1;
+            coef_c = y1 - coef_a * x1;
+        }
+    }
+
+    /**
+     * Constructor defining the line with the 3 coefficients of its equation, i.e. ax + by + c = 0.
+     * @param a Coefficient a.
+     * @param b Coefficient b.
+     * @param c Coefficient c.
+     */
+    public AlignWaysGeomLine(double a, double b, double c) {
+        coef_a = a;
+        coef_b = b;
+        coef_c = c;
+    }
+
+    /**
+     * Constructor defining the line with the slope m and the y-intercept b, i.e. y = mx + b;
+     * @param m Slope.
+     * @param b Y-intercept.
+     */
+    public AlignWaysGeomLine(double m, double b) {
+        coef_a = m;
+        coef_b = -1;
+        coef_c = b;
+    }
+
+    public AlignWaysGeomLine(AlignWaysGeomLine line) {
+        this(line.coef_a, line.coef_b, line.coef_c);
+    }
+
+    /**
+     * Returns the intersection point the line with another line.
+     * If the lines are parallel or overlap, returns null.
+     * Use getIntersectionStatus() to determine the case.
+     * @param other_line The other line.
+     * @return The intersection point of the lines.
+     */
+    public AlignWaysGeomPoint getIntersection(AlignWaysGeomLine other_line) {
+        AlignWaysGeomPoint result = null;
+
+        // Use Cramer-rule, i.e.:
+        // - if (det1 != 0), there is an intersection in a point
+        // - if (det1 == 0, det2 == 0, det3 == 0), the lines overlap
+        // - if (det1 == 0) and any of det2 or det3 != 0, the lines are parallel
+
+        // See: http://www.mathwizz.com/algebra/help/help21.htm
+        //  and http://en.wikipedia.org/wiki/Cramers_rule
+
+
+        double det1 = (coef_a * other_line.coef_b) - (other_line.coef_a * coef_b);
+        double det2 = (-coef_c * other_line.coef_b) - (-other_line.coef_c * coef_b);
+        double det3 = (coef_a * -other_line.coef_c) - (other_line.coef_a * -coef_c);
+
+        if (Math.abs(det1) < 0.01) {
+            if ((Math.abs(det2) < 0.01) && (Math.abs(det3) < 0.01)) {
+                // Lines overlap
+                isectStat = IntersectionStatus.LINES_OVERLAP;
+            } else {
+                // Lines are parallel
+                isectStat = IntersectionStatus.LINES_PARALLEL;
+            }
+        } else {
+            // Lines intersect in a point
+            result = new AlignWaysGeomPoint(det2/det1, det3/det1);
+            isectStat = IntersectionStatus.INTERSECT_POINT;
+        }
+
+        return result;
+    }
+
+
+    /**
+     * Return the last result of getIntersection(), therefore use in conjuction with getIntersection().
+     * If getIntersection() was never  called before, it returns IntersectionStatus.UNDEFINED.
+     * @return The last result of getIntersection().
+     */
+    public IntersectionStatus getIntersectionStatus() {
+        return isectStat;
+    }
+
+    /**
+     * Get the Y coordinate on the line of a point with the given X coordinate.
+     * 
+     * @param X The x-coordinate of the given point.
+     * @return The calculated y-coordinate or Double.NaN if the line is vertical.
+     */
+    public Double getYonLine(double X) {
+
+        Double Y = new Double((-coef_a*X - coef_c)/coef_b);
+
+        if (Y.isInfinite() || Y.isNaN())
+            // Vertical line
+            return Double.NaN;
+        else
+            return Y;
+
+    }
+
+
+    /**
+     * Get the X coordinate on the line of a point with the given Y coordinate.
+     * 
+     * @param Y The y-coordinate of the given point.
+     * @return The calculated x-coordinate or Double.NaN if the line is horizontal.
+     */
+    public Double getXonLine(double Y) {
+
+        Double X = new Double((-coef_b*Y - coef_c)/coef_a);
+
+        if (X.isInfinite() || X.isNaN())
+            // Horizontal line
+            return Double.NaN;
+        else
+            return X;
+
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (!(obj instanceof AlignWaysGeomLine))
+            return false;
+        AlignWaysGeomLine other = (AlignWaysGeomLine) obj;
+
+        if (Math.abs(this.coef_a - other.coef_a) < 0.01 &&
+                Math.abs(this.coef_b - other.coef_b) < 0.01 &&
+                Math.abs(this.coef_c - other.coef_c) < 0.01)
+            return true;
+        else
+            return false;
+    }
+
+}
Index: applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/geometry/AlignWaysGeomPoint.java
===================================================================
--- applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/geometry/AlignWaysGeomPoint.java	(revision 27348)
+++ applications/editors/josm/plugins/alignways/src/com/tilusnet/josm/plugins/alignways/geometry/AlignWaysGeomPoint.java	(revision 27348)
@@ -0,0 +1,28 @@
+package com.tilusnet.josm.plugins.alignways.geometry;
+
+public class AlignWaysGeomPoint {
+    double x;
+    double y;
+
+    public AlignWaysGeomPoint(double x, double y) {
+        setX(x);
+        setY(y);
+    }
+
+    public double getX() {
+        return x;
+    }
+
+    public double getY() {
+        return y;
+    }
+
+    public void setX(double x) {
+        this.x = x;
+    }
+
+    public void setY(double y) {
+        this.y = y;
+    }
+
+}
