Index: /applications/editors/josm/plugins/CommandLine/LICENSE
===================================================================
--- /applications/editors/josm/plugins/CommandLine/LICENSE	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/LICENSE	(revision 25037)
@@ -0,0 +1,345 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+	51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: /applications/editors/josm/plugins/CommandLine/build.xml
===================================================================
--- /applications/editors/josm/plugins/CommandLine/build.xml	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/build.xml	(revision 25037)
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="CommandLine" default="dist" basedir=".">
+
+    <!-- enter the SVN commit message -->
+    <property name="commit.message" value="Initial commit" />
+    <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
+    <property name="plugin.main.version" value="3751" />
+
+
+    <!--
+      ************************************************
+      ** should not be necessary to change the following properties
+     -->
+    <property name="josm"                   location="../../core/dist/josm-custom.jar"/>
+    <property name="plugin.build.dir"       value="build"/>
+    <property name="plugin.src.dir"         value="src"/>
+    <!-- this is the directory where the plugin jar is copied to -->
+    <property name="plugin.dist.dir"        value="../../dist"/>
+    <property name="ant.build.javac.target" value="1.5"/>
+    <property name="plugin.dist.dir"        value="../../dist"/>
+    <property name="plugin.jar"             value="${plugin.dist.dir}/${ant.project.name}.jar"/>
+
+    <!--
+    **********************************************************
+    ** init - initializes the build
+    **********************************************************
+    -->
+    <target name="init">
+        <mkdir dir="${plugin.build.dir}"/>
+    </target>
+
+    <!--
+    **********************************************************
+    ** compile - complies the source tree
+    **********************************************************
+    -->
+    <target name="compile" depends="init">
+        <echo message="compiling sources for  ${plugin.jar} ... "/>
+        <javac srcdir="src" classpath="${josm}" debug="true" destdir="${plugin.build.dir}">
+            <compilerarg value="-Xlint:deprecation"/>
+            <compilerarg value="-Xlint:unchecked"/>
+        </javac>
+    </target>
+
+    <!--
+    **********************************************************
+    ** dist - creates the plugin jar
+    **********************************************************
+    -->
+    <target name="dist" depends="compile,revision">
+        <echo message="creating ${ant.project.name}.jar ... "/>
+        <copy todir="${plugin.build.dir}/resources">
+            <fileset dir="resources"/>
+        </copy>
+        <copy todir="${plugin.build.dir}/images">
+            <fileset dir="images"/>
+        </copy>
+        <copy todir="${plugin.build.dir}">
+            <fileset dir=".">
+                <include name="README" />
+                <include name="LICENSE" />
+            </fileset>
+        </copy>
+        <jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
+            <!--
+        ************************************************
+        ** configure these properties. Most of them will be copied to the plugins
+        ** manifest file. Property values will also show up in the list available
+        ** plugins: http://josm.openstreetmap.de/wiki/Plugins.
+        **
+        ************************************************
+    -->
+            <manifest>
+                <attribute name="Author" value="Hind"/>
+                <attribute name="Plugin-Class" value="CommandLine.CommandLine"/>
+                <attribute name="Plugin-Date" value="${version.entry.commit.date}"/>
+                <attribute name="Plugin-Description" value="Implements a command line and enables to create your commands. See link for standard commands (arc, circle etc.)"/>
+                <attribute name="ru_Plugin-Description" value="Реализует командную строку с возможностью создания своих команд. Стандартные команды можно скачать по ссылке."/>
+                <attribute name="Plugin-Icon" value="images/commandline.png"/>
+                <attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/wiki/JOSM/Plugins/CommandLine"/>
+                <attribute name="ru_Plugin-Link" value="http://wiki.openstreetmap.org/wiki/RU:JOSM/Plugins/CommandLine"/>
+                <attribute name="Plugin-Mainversion" value="${plugin.main.version}"/>
+                <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
+            </manifest>
+        </jar>
+    </target>
+
+    <!--
+    **********************************************************
+    ** revision - extracts the current revision number for the
+    **    file build.number and stores it in the XML property
+    **    version.*
+    **********************************************************
+    -->
+    <target name="revision">
+
+        <exec append="false" output="REVISION" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="info"/>
+            <arg value="--xml"/>
+            <arg value="."/>
+        </exec>
+        <xmlproperty file="REVISION" prefix="version" keepRoot="false" collapseAttributes="true"/>
+        <delete file="REVISION"/>
+    </target>
+
+    <!--
+    **********************************************************
+    ** clean - clean up the build environment
+    **********************************************************
+    -->
+    <target name="clean">
+        <delete dir="${plugin.build.dir}"/>
+        <delete file="${plugin.jar}"/>
+    </target>
+
+    <!--
+    **********************************************************
+    ** install - install the plugin in your local JOSM installation
+    **********************************************************
+    -->
+    <target name="install" depends="dist">
+        <property environment="env"/>
+        <condition property="josm.plugins.dir" value="${env.APPDATA}/JOSM/plugins" else="${user.home}/.josm/plugins">
+            <and>
+                <os family="windows"/>
+            </and>
+        </condition>
+        <copy file="${plugin.jar}" todir="${josm.plugins.dir}"/>
+    </target>
+
+
+    <!--
+    ************************** Publishing the plugin *********************************** 
+    -->
+    <!--
+        ** extracts the JOSM release for the JOSM version in ../core and saves it in the 
+        ** property ${coreversion.info.entry.revision}
+        **
+        -->
+    <target name="core-info">
+        <exec append="false" output="core.info.xml" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="info"/>
+            <arg value="--xml"/>
+            <arg value="../../core"/>
+        </exec>
+        <xmlproperty file="core.info.xml" prefix="coreversion" keepRoot="true" collapseAttributes="true"/>
+        <echo>Building against core revision ${coreversion.info.entry.revision}.</echo>
+        <echo>Plugin-Mainversion is set to ${plugin.main.version}.</echo>
+        <delete file="core.info.xml" />
+    </target>
+
+    <!--
+        ** commits the source tree for this plugin
+        -->
+    <target name="commit-current">
+        <echo>Commiting the plugin source with message '${commit.message}' ...</echo>
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="commit"/>
+            <arg value="-m '${commit.message}'"/>
+            <arg value="."/>
+        </exec>
+    </target>
+
+    <!--
+        ** updates (svn up) the source tree for this plugin
+        -->
+    <target name="update-current">
+        <echo>Updating plugin source ...</echo>
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="up"/>
+            <arg value="."/>
+        </exec>
+        <echo>Updating ${plugin.jar} ...</echo>
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="up"/>
+            <arg value="../dist/${plugin.jar}"/>
+        </exec>
+    </target>
+
+    <!--
+        ** commits the plugin.jar 
+        -->
+    <target name="commit-dist">
+        <echo>
+    ***** Properties of published ${plugin.jar} *****
+    Commit message    : '${commit.message}'                    
+    Plugin-Mainversion: ${plugin.main.version}
+    JOSM build version: ${coreversion.info.entry.revision}
+    Plugin-Version    : ${version.entry.commit.revision}
+    ***** / Properties of published ${plugin.jar} *****                    
+                        
+    Now commiting ${plugin.jar} ...
+    </echo>
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="-m '${commit.message}'"/>
+            <arg value="commit"/>
+            <arg value="${plugin.jar}"/>
+        </exec>
+    </target>
+
+    <!-- ** make sure svn is present as a command line tool ** -->
+    <target name="ensure-svn-present">
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false" failonerror="false" resultproperty="svn.exit.code">
+            <env key="LANG" value="C" />
+            <arg value="--version" />
+        </exec>
+        <fail message="Fatal: command 'svn --version' failed. Please make sure svn is installed on your system.">
+            <!-- return code not set at all? Most likely svn isn't installed -->
+            <condition>
+                <not>
+                    <isset property="svn.exit.code" />
+                </not>
+            </condition>
+        </fail>
+        <fail message="Fatal: command 'svn --version' failed. Please make sure a working copy of svn is installed on your system.">
+            <!-- error code from SVN? Most likely svn is not what we are looking on this system -->
+            <condition>
+                <isfailure code="${svn.exit.code}" />
+            </condition>
+        </fail>
+    </target>
+
+    <target name="publish" depends="ensure-svn-present,core-info,commit-current,update-current,clean,dist,commit-dist">
+    </target>
+</project>
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/AnyAction.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/AnyAction.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/AnyAction.java	(revision 25037)
@@ -0,0 +1,173 @@
+/*
+ *      AnyAction.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.AWTEvent;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.event.AWTEventListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class AnyAction extends MapMode implements AWTEventListener {
+	private CommandLine parentPlugin;
+    final private Cursor cursorNormal, cursorActive;
+    private Cursor currentCursor;
+    private Point mousePos;
+    private OsmPrimitive nearestPrimitive;
+    private boolean isCtrlDown;
+
+	public AnyAction(MapFrame mapFrame, CommandLine parentPlugin) {
+		super(null, "addsegment.png", null, mapFrame, ImageProvider.getCursor("normal", "selection"));
+		this.parentPlugin = parentPlugin;
+	cursorNormal = ImageProvider.getCursor("normal", "selection");
+	cursorActive = ImageProvider.getCursor("normal", "joinnode");
+        currentCursor = cursorNormal;
+        nearestPrimitive = null;
+	}
+
+	@Override public void enterMode() {
+		super.enterMode();
+        currentCursor = cursorNormal;
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+        try {
+            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+        } catch (SecurityException ex) {
+        }
+	}
+
+	@Override public void exitMode() {
+		super.exitMode();
+		Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        try {
+            Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+        } catch (SecurityException ex) {
+        }
+	}
+
+    @Override
+    public void mouseMoved(MouseEvent e) {
+        if (!Main.map.mapView.isActiveLayerDrawable())
+            return;
+        processMouseEvent(e);
+        updCursor();
+        Main.map.mapView.repaint();
+        super.mouseMoved(e);
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e) {
+        if (!Main.map.mapView.isActiveLayerDrawable())
+            return;
+        processMouseEvent(e);
+        if (nearestPrimitive != null) {
+			if (isCtrlDown) {
+				Main.main.getCurrentDataSet().clearSelection(nearestPrimitive);
+				Main.map.mapView.repaint();
+			}
+			else {
+				int maxInstances = parentPlugin.currentCommand.parameters.get(parentPlugin.currentCommand.currentParameterNum).maxInstances;
+				switch (maxInstances) {
+				case 0:
+					Main.main.getCurrentDataSet().addSelected(nearestPrimitive);
+					Main.map.mapView.repaint();
+					break;
+				case 1:
+					Main.main.getCurrentDataSet().addSelected(nearestPrimitive);
+					Main.map.mapView.repaint();
+					parentPlugin.loadParameter(nearestPrimitive, true);
+					exitMode();
+					break;
+				default:
+					if (Main.main.getCurrentDataSet().getSelected().size() < maxInstances) {
+						Main.main.getCurrentDataSet().addSelected(nearestPrimitive);
+						Main.map.mapView.repaint();
+					}
+					else
+						System.out.println("Maximum instances!");
+				}
+			}
+		}
+        super.mousePressed(e);
+    }
+
+	public void eventDispatched(AWTEvent arg0) {
+		if (!(arg0 instanceof KeyEvent))
+			return;
+		KeyEvent ev = (KeyEvent) arg0;
+        isCtrlDown = (ev.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0;
+        if (ev.getKeyCode() == KeyEvent.VK_ESCAPE && ev.getID() == KeyEvent.KEY_PRESSED) {
+            ev.consume();
+            cancelDrawing();
+        }
+    }
+
+    private void updCursor() {
+        if (mousePos != null) {
+			if (!Main.isDisplayingMapView())
+				return;
+			nearestPrimitive = Main.map.mapView.getNearest(mousePos, OsmPrimitive.isUsablePredicate); // Deprecated
+			if (nearestPrimitive != null) {
+				setCursor(cursorActive);
+			}
+			else {
+				setCursor(cursorNormal);
+			}
+		}
+    }
+
+	private void processMouseEvent(MouseEvent e) {
+		if (e != null) { mousePos = e.getPoint(); }
+	}
+
+    private void setCursor(final Cursor c) {
+        if (currentCursor.equals(c))
+            return;
+        try {
+            // We invoke this to prevent strange things from happening
+            EventQueue.invokeLater(new Runnable() {
+                public void run() {
+                    // Don't change cursor when mode has changed already
+                    if (!(Main.map.mapMode instanceof AnyAction))
+                        return;
+                    Main.map.mapView.setCursor(c);
+                }
+            });
+            currentCursor = c;
+        } catch (Exception e) {
+        }
+    }
+
+    public void cancelDrawing() {
+        if (Main.map == null || Main.map.mapView == null)
+            return;
+        Main.map.statusLine.setHeading(-1);
+        Main.map.statusLine.setAngle(-1);
+        Main.map.mapView.repaint();
+        updateStatusLine();
+        parentPlugin.endInput();
+    }
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/Command.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/Command.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/Command.java	(revision 25037)
@@ -0,0 +1,204 @@
+/*
+ *      Command.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+
+package commandline;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.*;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.DataSet;
+
+public class Command {
+	public String name;						// Command name
+	public String run;						// Executable file with arguments ("nya.exe {arg1} {arg2} ... {argn}")
+	public ArrayList<Parameter> parameters;	// Required parameters list
+	public ArrayList<Parameter> optParameters;	// Optional parameters list
+	public int currentParameterNum;
+	public boolean tracks;
+	
+	public Command () {	parameters = new ArrayList<Parameter>(); optParameters = new ArrayList<Parameter>(); currentParameterNum = 0; tracks = false; }
+
+	public boolean loadObject(Object obj) {
+		Parameter currentParameter = parameters.get(currentParameterNum);
+		//System.out.println("Parameter " + String.valueOf(currentParameterNum) + " (" + currentParameter.name + ")");
+		if (currentParameter.maxInstances == 1) {
+			//System.out.println("mI = 1");
+			//System.out.println("Candidate: " + String.valueOf(obj));
+			if (isPair(obj, currentParameter)) {
+				currentParameter.setValue(obj);
+				//System.out.println("Accepted");
+				return true;
+			}
+		}
+		else {
+			//System.out.println("mI = " + String.valueOf(currentParameter.maxInstances));
+			ArrayList<OsmPrimitive> multiValue = currentParameter.getValueList();
+			if (obj instanceof Collection) {
+				if ( ((Collection)obj).size() > currentParameter.maxInstances && currentParameter.maxInstances != 0)
+					return false;
+				//System.out.println("Candidate (selected) accepted");
+				multiValue.clear();
+				multiValue.addAll((Collection<OsmPrimitive>)obj);
+				return true;
+			}
+			else if (obj instanceof OsmPrimitive) {
+				if (multiValue.size() < currentParameter.maxInstances || currentParameter.maxInstances == 0) {
+					//System.out.println("Candidate: " + String.valueOf(obj));
+					if (isPair(obj, currentParameter)) {
+						multiValue.add((OsmPrimitive)obj);
+						//System.out.println("Accepted, added to list");
+						return true;
+					}
+					else {
+						if (nextParameter() && multiValue.size() > 0) {
+							//System.out.println("Not accepted but considering for next Parameter");
+							return loadObject(obj);
+						}
+					}
+				}
+				else {
+					if (nextParameter()) {
+						//System.out.println("Not accepted but considering for next Parameter");
+						return loadObject(obj);
+					}
+				}
+			}
+			else if (obj instanceof String) {
+				//System.out.println("Candidate: " + (String)obj);
+				if (isPair(obj, currentParameter)) {
+					currentParameter.setValue(obj);
+					//System.out.println("Accepted");
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	public boolean nextParameter() {
+		currentParameterNum++;
+		return (currentParameterNum < parameters.size()) ? true : false;
+	}
+
+	public boolean hasNextParameter() {
+		return ((currentParameterNum + 1) < parameters.size()) ? true : false;
+	}
+
+	public void resetLoading() {
+		currentParameterNum = 0;
+		for (Parameter parameter : parameters) {
+			if (parameter.maxInstances != 1)
+				parameter.getValueList().clear();
+		}
+	}
+
+	private static boolean isPair(Object obj, Parameter parameter) {
+		switch (parameter.type) {
+			case POINT:
+				if (obj instanceof String) {
+					Pattern p = Pattern.compile("(-?\\d*\\.?\\d*,-?\\d*\\.?\\d*;?)*");
+					Matcher m = p.matcher((String)obj);
+					return m.matches();
+				}
+				break;
+			case NODE:
+				if (obj instanceof Node) return true;
+				break;
+			case WAY:
+				if (obj instanceof Way) return true;
+				break;
+			case RELATION:
+				if (obj instanceof Relation) return true;
+				break;
+			case ANY:
+				if (obj instanceof Node || obj instanceof Way || obj instanceof Relation) return true;
+				break;
+			case LENGTH:
+				if (obj instanceof String) {
+					Pattern p = Pattern.compile("\\d*\\.?\\d*");
+					Matcher m = p.matcher((String)obj);
+					if (m.matches()) {
+						Float value = Float.parseFloat((String)obj);
+						if (parameter.minVal != 0 && value < parameter.minVal)
+							break;
+						if (parameter.maxVal != 0 && value > parameter.maxVal)
+							break;
+						return true;
+					}
+				}
+				break;
+			case NATURAL:
+				if (obj instanceof String) {
+					Pattern p = Pattern.compile("\\d*");
+					Matcher m = p.matcher((String)obj);
+					if (m.matches()) {
+						Integer value = Integer.parseInt((String)obj);
+						if (parameter.minVal != 0 && value < parameter.minVal)
+							break;
+						if (parameter.maxVal != 0 && value > parameter.maxVal)
+							break;
+						return true;
+					}
+				}
+				break;
+			case STRING:
+				if (obj instanceof String) return true;
+				break;
+			case RELAY:
+				if (obj instanceof String) {
+					if (parameter.getRawValue() instanceof Relay) {
+						if ( ((Relay)(parameter.getRawValue())).isCorrectValue((String)obj) )
+							return true;
+					}
+				}
+				break;
+		}
+		return false;
+	}
+
+	public Collection<OsmPrimitive> getDepsObjects() {
+		ArrayList<OsmPrimitive> depsObjects = new ArrayList<OsmPrimitive>();
+		for (Parameter parameter : parameters) {
+			if (!parameter.isOsm())
+						continue;
+			if (parameter.maxInstances == 1) {
+				depsObjects.addAll(getDepsObjects(depsObjects, (OsmPrimitive)parameter.getRawValue()));
+			}
+			else {
+				for (OsmPrimitive primitive : parameter.getValueList()) {
+					depsObjects.addAll(getDepsObjects(depsObjects, primitive));
+				}
+			}
+		}
+		return depsObjects;
+	}
+
+	public Collection<OsmPrimitive> getDepsObjects(Collection<OsmPrimitive> currentObjects, OsmPrimitive primitive) {
+		ArrayList<OsmPrimitive> depsObjects = new ArrayList<OsmPrimitive>();
+		if (!currentObjects.contains(primitive)) {
+			if (primitive instanceof Way) {
+				depsObjects.addAll(((Way)primitive).getNodes());
+			}
+			else if (primitive instanceof Relation) {
+				Collection<OsmPrimitive> relationMembers = ((Relation)primitive).getMemberPrimitives();
+				for (OsmPrimitive member : relationMembers) {
+					if (!currentObjects.contains(member)) {
+						depsObjects.add(member);
+						depsObjects.addAll(getDepsObjects(currentObjects, member));
+					}
+				}
+			}
+		}
+		return depsObjects;
+	}
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/CommandLine.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/CommandLine.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/CommandLine.java	(revision 25037)
@@ -0,0 +1,532 @@
+/*
+ *      CommandLine.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *      
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *      
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ */
+
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.Cursor;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.regex.*;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.command.MoveCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.DataSetMerger;
+import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.WayPoint;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.MainMenu;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.io.OsmWriter;
+import org.openstreetmap.josm.io.GpxWriter;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+public class CommandLine extends Plugin {
+	protected JTextField textField;
+	private String prefix;
+	private Mode mode;
+	private ArrayList<Command> commands;
+	protected Command currentCommand;
+	protected String commandSymbol;
+	private History history;
+	private MapFrame currentMapFrame;
+	private MapMode previousMode;
+
+	public CommandLine(PluginInformation info) {
+		super(info);
+		commandSymbol = ": ";
+		history = new History(100);
+		textField = new JTextField() {
+			@Override
+			protected void processKeyEvent(KeyEvent e) {
+				if (e.getID() == KeyEvent.KEY_PRESSED) {
+					String text = textField.getText();
+					int code = e.getKeyCode();
+					if (code == KeyEvent.VK_ENTER) {
+						String commandText = textField.getText().substring(prefix.length());
+						switch (mode) {
+							case IDLE:
+								if (commandText.isEmpty()) {
+									commandText = history.getLastItem();
+								}
+								else {
+									history.addItem(commandText);
+								}
+								Command command = findCommand(commandText, true);
+								if (command != null) {
+									currentCommand = command;
+									currentCommand.resetLoading();
+									parseSelection(Main.main.getCurrentDataSet().getSelected());
+									previousMode = Main.map.mapMode;
+									if (currentCommand.currentParameterNum < currentCommand.parameters.size())
+										setMode(Mode.SELECTION);
+									else
+										runTool();
+								}
+								else
+									setMode(Mode.IDLE);
+								break;
+							case SELECTION:
+								if (currentMapFrame.mapMode instanceof WayAction || currentMapFrame.mapMode instanceof NodeAction || currentMapFrame.mapMode instanceof RelationAction || currentMapFrame.mapMode instanceof AnyAction) {
+										Collection<OsmPrimitive> selected = Main.main.getCurrentDataSet().getSelected();
+										if (selected.size() > 0)
+											loadParameter(selected, true);
+								}
+								else {
+									loadParameter(commandText, currentCommand.parameters.get(currentCommand.currentParameterNum).maxInstances == 1);
+								}
+								break;
+							case ADJUSTMENT:
+								break;
+						}
+						e.consume();
+					}
+					else if (code == KeyEvent.VK_UP) {
+						textField.setText(prefix + history.getPrevItem());
+						e.consume();
+					}
+					else if (code == KeyEvent.VK_DOWN) {
+						textField.setText(prefix + history.getNextItem());
+						e.consume();
+					}
+					else if (code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_LEFT) {
+						if (textField.getCaretPosition() <= prefix.length())
+							e.consume();
+					}
+					else if (code == KeyEvent.VK_HOME) {
+						setCaretPosition(prefix.length());
+						e.consume();
+					}
+					else if (code == KeyEvent.VK_ESCAPE) {
+						if (textField.getText().length() == prefix.length() && mode == Mode.IDLE)
+							deactivate();
+						else
+							endInput();
+						e.consume();
+					}
+					else if (code == KeyEvent.VK_DELETE || code == KeyEvent.VK_RIGHT || code == KeyEvent.VK_END) {
+					}
+					else {
+						e.consume();
+					}
+					if (textField.getCaretPosition() < prefix.length() || (textField.getSelectionStart() < prefix.length() && textField.getSelectionStart() > 0) )
+						e.consume();
+					}
+					if (e.getID() == KeyEvent.KEY_TYPED)
+						if (textField.getCaretPosition() < prefix.length() || (textField.getSelectionStart() < prefix.length() && textField.getSelectionStart() > 0) )
+							e.consume();
+					super.processKeyEvent(e);
+					if (textField.getText().length() < prefix.length()) { // Safe
+						setMode(mode);
+				}
+				if (e.getID() == KeyEvent.KEY_TYPED) {
+					if (e.getKeyChar() > 'A' && e.getKeyChar() < 'z') {
+						Command command = findCommand(textField.getText().substring(prefix.length()), false);
+						if (command != null) {
+							int currentPos = textField.getSelectionStart() == 0 ? textField.getCaretPosition() : textField.getSelectionStart();
+							textField.setText(prefix + command.name);
+							textField.setCaretPosition(currentPos);
+							textField.select(currentPos, prefix.length() + command.name.length());
+						}
+					}
+				}
+			}
+			@Override
+			protected void processMouseEvent(MouseEvent e) {
+				super.processMouseEvent(e);
+				if (e.getButton() == MouseEvent.BUTTON1 && e.getID() == MouseEvent.MOUSE_RELEASED) {
+					if (textField.getSelectionStart() > 0 && textField.getSelectionStart() < prefix.length())
+						textField.setSelectionStart(prefix.length());
+					else if (textField.getCaretPosition() < prefix.length())
+						textField.setCaretPosition(prefix.length());
+				}
+			}
+		};
+
+		MainMenu.add(Main.main.menu.toolsMenu, new CommandLineAction(this));
+		loadCommands();
+		setMode(Mode.IDLE);
+	}
+
+	public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame)
+	{
+		if (oldFrame==null && newFrame!=null) {
+			currentMapFrame = newFrame;
+			currentMapFrame.add(textField,BorderLayout.NORTH);
+		}
+	}
+
+	private void loadCommands() {
+		Loader loader = new Loader(getPluginDir());
+		commands = loader.load(); // lol
+	}
+
+	private Command findCommand(String text, boolean strict) {
+		for (int i = 0; i < commands.size(); i++) {
+			if (strict) {
+				if ( commands.get(i).name.equalsIgnoreCase(text) ) {
+					return commands.get(i);
+				}
+			}
+			else {
+				if ( commands.get(i).name.toLowerCase().startsWith( text.toLowerCase() ) && text.length() > 1 ) {
+					return commands.get(i);
+				}
+			}
+		}
+		return null;
+	}
+	
+	private void setMode(Mode targetMode) {
+		DataSet currentDataSet = Main.main.getCurrentDataSet();
+		if (currentDataSet != null) {
+			currentDataSet.clearSelection();
+			Main.map.mapView.repaint();
+		}
+		if (targetMode == Mode.IDLE) {
+			mode = Mode.IDLE;
+			currentCommand = null;
+			prefix = tr("Command") + commandSymbol;
+			textField.setText(prefix);
+		}
+		else if (targetMode == Mode.SELECTION) {
+			mode = Mode.SELECTION;
+			Parameter currentParameter = currentCommand.parameters.get(currentCommand.currentParameterNum);
+			prefix = tr(currentParameter.description);
+			if (currentParameter.getRawValue() instanceof Relay)
+				prefix = prefix + " (" + ((Relay)(currentParameter.getRawValue())).getOptionsString() + ")";
+			prefix += commandSymbol;
+			String value = currentParameter.getValue();
+			textField.setText(prefix + value);
+			Type currentType = currentParameter.type;
+			MapMode action = null;
+			switch (currentType) {
+				case POINT:
+					action = new PointAction(currentMapFrame, this);
+					break;
+				case WAY:
+					action = new WayAction(currentMapFrame, this);
+					break;
+				case NODE:
+					action = new NodeAction(currentMapFrame, this);
+					break;
+				case RELATION:
+					action = new RelationAction(currentMapFrame, this);
+					break;
+				case ANY:
+					action = new AnyAction(currentMapFrame, this);
+					break;
+				case LENGTH:
+					action = new LengthAction(currentMapFrame, this);
+					break;
+				default:
+					action = new DummyAction(currentMapFrame, this);
+					break;
+			}
+			currentMapFrame.selectMapMode(action);
+			activate();
+			textField.select(prefix.length(), textField.getText().length());
+		}
+		else if (targetMode == Mode.PROCESSING) {
+			mode = Mode.PROCESSING;
+			prefix = tr("Processing...");
+			textField.setText(prefix);
+		}
+	}
+
+	public void activate() {
+		textField.requestFocus();
+		textField.setCaretPosition(textField.getText().length());
+	}
+
+	public void deactivate() {
+		Main.map.mapView.requestFocus();
+	}
+
+	public void endInput() {
+		setMode(Mode.IDLE);
+		//System.out.print(String.valueOf());
+		Main.map.selectMapMode(previousMode);
+		Main.map.mapView.repaint();
+	}
+
+	public void loadParameter(Object obj, boolean next) {
+		if (currentCommand.loadObject(obj)) {
+			if (currentCommand.hasNextParameter()) {
+				if (next) {
+					currentCommand.nextParameter();
+					setMode(Mode.SELECTION);
+				}
+			}
+			else {
+				runTool();
+			}
+		}
+		else {
+			System.out.println("Invalid argument");
+			endInput();
+		}
+	}
+
+	private void parseSelection(Collection<OsmPrimitive> selection) {
+		boolean ok = false;
+		for (OsmPrimitive obj : selection) {
+			ok = currentCommand.loadObject(obj);
+			if (!ok)
+				break;
+		}
+		if (ok) {
+			currentCommand.nextParameter();
+		}
+		else {
+			currentCommand.resetLoading();
+		}
+		System.out.println("Selected before " + String.valueOf(currentCommand.currentParameterNum) + "\n");
+	}
+
+	private class ToolProcess {
+		public Process process;
+		public volatile boolean running;
+	}
+
+	// Thanks to Upliner
+	public void runTool() {
+		setMode(Mode.PROCESSING);
+		Main.map.mapView.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+		String commandToRun = currentCommand.run;
+
+		for (Parameter parameter : currentCommand.parameters) {
+			commandToRun = commandToRun.replace("{" + parameter.name + "}", parameter.getValue());
+		}
+		for (Parameter parameter : currentCommand.optParameters) {
+			commandToRun = commandToRun.replace("{" + parameter.name + "}", parameter.getValue());
+		}
+		String[] listToRun = commandToRun.split(" ");
+
+		// create the process
+		final Object syncObj = new Object();
+
+		ProcessBuilder builder;
+		builder = new ProcessBuilder(listToRun);
+		builder.directory(new File(getPluginDir()));
+
+		final StringBuilder debugstr = new StringBuilder();
+
+		// debug: print resulting cmdline
+		for (String s : builder.command())
+			debugstr.append(s + " ");
+		debugstr.append("\n");
+		System.out.print(debugstr.toString());
+
+		final ToolProcess tp = new ToolProcess();
+		try {
+			tp.process = builder.start();
+		} catch (final IOException e) {
+			e.printStackTrace();
+			synchronized (debugstr) {
+				System.out.print(
+						tr("Error executing the script: ") +
+						debugstr.toString() + e.getMessage() + "\n" + e.getStackTrace());
+			}
+			return;
+		}
+		tp.running = true;
+
+		// redirect child process's stderr to JOSM stderr
+		new Thread(new Runnable() {
+			public void run() {
+				try {
+					byte[] buffer = new byte[1024];
+					InputStream errStream = tp.process.getErrorStream();
+					int len;
+					while ((len = errStream.read(buffer)) > 0) {
+						synchronized (debugstr) {
+							debugstr.append(new String(buffer, 0, len));
+						}
+						System.err.write(buffer, 0, len);
+					}
+				} catch (IOException e) {
+				}
+			}
+		}).start();
+
+		// Write stdin stream
+		Thread osmWriteThread = new Thread(new Runnable() {
+			public void run() {
+				BBox bbox = null;
+				final OutputStream outputStream = tp.process.getOutputStream();
+				PrintWriter printWriter = null;
+				try { printWriter = new PrintWriter(new OutputStreamWriter(outputStream, "utf-8")); }
+				catch (Exception e) {e.printStackTrace();}
+				final OsmWriter osmWriter = new OsmWriter(printWriter, true, null);
+				Collection<OsmPrimitive> refObjects = currentCommand.getDepsObjects();
+				Collection<OsmPrimitive> pObjects;
+				osmWriter.header();
+				for (OsmPrimitive primitive : refObjects) {
+					if (primitive instanceof Node) 
+						osmWriter.visit((Node)primitive);
+					else if (primitive instanceof Way) 
+						osmWriter.visit((Way)primitive);	
+					else if (primitive instanceof Relation) 
+						osmWriter.visit((Relation)primitive);
+					if (bbox == null)
+						bbox = new BBox(primitive.getBBox());
+					else
+						bbox.addPrimitive(primitive, 0.0);
+				}
+				osmWriter.footer();
+				osmWriter.flush();
+				for (Parameter parameter : currentCommand.parameters) {
+					if (!parameter.isOsm())
+						continue;
+					osmWriter.header();
+					pObjects = parameter.getParameterObjects();
+					for (OsmPrimitive primitive : pObjects) {
+						if (primitive instanceof Node) 
+							osmWriter.visit((Node)primitive);
+						else if (primitive instanceof Way) 
+							osmWriter.visit((Way)primitive);	
+						else if (primitive instanceof Relation) 
+							osmWriter.visit((Relation)primitive);
+						if (bbox == null)
+							bbox = new BBox(primitive.getBBox());
+						else
+							bbox.addPrimitive(primitive, 0.0);
+					}
+					osmWriter.footer();
+					osmWriter.flush();
+				}
+				if (currentCommand.tracks) {
+					final GpxWriter gpxWriter = new GpxWriter(printWriter);
+					GpxFilter gpxFilter = new GpxFilter();
+					gpxFilter.initBboxFilter(bbox);
+					List<GpxLayer> gpxLayers = Main.map.mapView.getLayersOfType(GpxLayer.class);
+					for (GpxLayer gpxLayer : gpxLayers) {
+						gpxFilter.addGpxData(gpxLayer.data);
+					}
+					gpxWriter.write(gpxFilter.getGpxData());
+				}
+				osmWriter.close();
+				synchronized (syncObj) {
+					tp.running = false;
+					syncObj.notifyAll();
+				}
+			}
+
+		});
+
+		// Read stdout stream
+		Thread osmParseThread = new Thread(new Runnable() {
+			public void run() {
+				try {
+					String commandName = currentCommand.name;
+					HashMap<Long, Long> inexiDMap = new HashMap<Long, Long>();
+					final InputStream inputStream = tp.process.getInputStream();
+					final List<org.openstreetmap.josm.command.Command> cmdlist = new OsmToCmd(Main.main.getCurrentDataSet(), inputStream).getCommandList();
+					//OsmReaderMod.deleteInexiDMap();
+					if (!cmdlist.isEmpty()) {
+						SequenceCommand cmd = new SequenceCommand(commandName, cmdlist);
+						Main.main.undoRedo.add(cmd);
+					}
+				}
+				catch (Exception e) {}
+				finally {
+					synchronized (syncObj) {
+						tp.running = false;
+						syncObj.notifyAll();
+					}
+				}
+			}
+
+		});
+
+		osmParseThread.start();
+		osmWriteThread.start();
+
+		synchronized (syncObj) {
+			try {
+				syncObj.wait(10000);
+			} catch (InterruptedException e) {
+			}
+		}
+		if (tp.running) {
+			new Thread(new PleaseWaitRunnable(currentCommand.name) {
+				@Override
+				protected void realRun() {
+					try {
+						progressMonitor.indeterminateSubTask(null);
+						synchronized (syncObj) {
+							if (tp.running)
+								syncObj.wait();
+						}
+					} catch (InterruptedException e) {
+					}
+				}
+
+				@Override
+				protected void cancel() {
+					synchronized (syncObj) {
+						tp.running = false;
+						tp.process.destroy();
+						syncObj.notifyAll();
+						endInput();
+					}
+				}
+
+				@Override
+				protected void finish() {
+				}
+			}).start();
+		}
+		endInput();
+	}
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/CommandLineAction.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/CommandLineAction.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/CommandLineAction.java	(revision 25037)
@@ -0,0 +1,50 @@
+/*
+ *      CommandLineAction.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+ 
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.Cursor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+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.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.tools.Pair;
+import org.openstreetmap.josm.tools.Shortcut;
+
+public class CommandLineAction extends JosmAction {
+	private CommandLine parentPlugin;
+	
+	public CommandLineAction(CommandLine parentPlugin) {
+		super(tr("Command line"), "simplify", tr("Set input focus to the command line."),
+		Shortcut.registerShortcut("edit:simplifyArea", tr("Tool: {0}", tr("Command line")), KeyEvent.VK_ENTER, Shortcut.GROUP_DIRECT, 0), true);
+		this.parentPlugin = parentPlugin;
+	}
+
+    public void actionPerformed(ActionEvent e) {
+		parentPlugin.activate();
+    }
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/DummyAction.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/DummyAction.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/DummyAction.java	(revision 25037)
@@ -0,0 +1,60 @@
+/*
+ *      DummyAction.java
+ *
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *
+ */
+
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.AWTEvent;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.event.AWTEventListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class DummyAction extends MapMode implements AWTEventListener {
+	private CommandLine parentPlugin;
+
+	public DummyAction(MapFrame mapFrame, CommandLine parentPlugin) {
+		super(null, "addsegment.png", null, mapFrame, ImageProvider.getCursor("normal", null));
+		this.parentPlugin = parentPlugin;
+	}
+
+	public void eventDispatched(AWTEvent arg0) {
+		if (!(arg0 instanceof KeyEvent))
+			return;
+		KeyEvent ev = (KeyEvent) arg0;
+        if (ev.getKeyCode() == KeyEvent.VK_ESCAPE && ev.getID() == KeyEvent.KEY_PRESSED) {
+            ev.consume();
+            cancelDrawing();
+        }
+    }
+
+    public void cancelDrawing() {
+        if (Main.map == null || Main.map.mapView == null)
+            return;
+        Main.map.statusLine.setHeading(-1);
+        Main.map.statusLine.setAngle(-1);
+        Main.map.mapView.repaint();
+        updateStatusLine();
+        parentPlugin.endInput();
+    }
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/GpxFilter.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/GpxFilter.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/GpxFilter.java	(revision 25037)
@@ -0,0 +1,69 @@
+/*
+ *      GpxFilter.java
+ *      
+ *      Copyright 2011 Hind <foxhind@gmail.com>
+ *      
+ */
+
+package commandline;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
+import org.openstreetmap.josm.data.gpx.ImmutableGpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.WayPoint;
+
+public class GpxFilter {
+	private BBox bbox;
+	private GpxData data;
+
+	public GpxFilter() {
+		bbox = new BBox(0.0, 0.0, 0.0, 0.0);
+		data = new GpxData();
+	}
+
+	public void initBboxFilter(BBox bbox) {
+		this.bbox = bbox;
+	}
+
+	public void addGpxData(GpxData data) {
+		Collection<Collection<WayPoint>> currentTrack;
+		Collection<WayPoint> currentSegment;
+		for (GpxTrack track : data.tracks) {
+			//System.out.println("New track");
+			currentTrack = new ArrayList<Collection<WayPoint>>();
+			for (GpxTrackSegment segment : track.getSegments()) {
+				//System.out.println("New segment");
+				currentSegment = new ArrayList<WayPoint>();
+				for (WayPoint wp : segment.getWayPoints()) {
+					//System.out.println("Point " + String.valueOf(wp.getCoor().getX()) + ", " + String.valueOf(wp.getCoor().getY()) + " situaded in bbox? " + String.valueOf(bbox.bounds(wp.getCoor())) );
+					if ( bbox.bounds(wp.getCoor()) ) {
+						currentSegment.add(wp);
+					} else {
+						if (currentSegment.size() > 1) {
+							currentTrack.add(currentSegment);
+							currentSegment = new ArrayList<WayPoint>();
+						}
+					}
+				}
+				if (currentSegment.size() > 1) {
+					currentTrack.add(currentSegment);
+					currentSegment = new ArrayList<WayPoint>();
+				}
+			}
+			this.data.tracks.add( new ImmutableGpxTrack( currentTrack, Collections.<String, Object>emptyMap()) );
+		}
+	}
+
+	public GpxData getGpxData() {
+		return data;
+	}
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/History.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/History.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/History.java	(revision 25037)
@@ -0,0 +1,67 @@
+/*
+ *      History.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+ 
+package commandline;
+
+import java.util.LinkedList;
+
+public class History {
+	private LinkedList<String> historyList;
+	private int maxLen;
+	private int num;
+	
+	public History(int len) {
+		num = 0;
+		maxLen = len;
+		historyList = new LinkedList<String>();
+	}
+	
+	public void addItem(String item) {
+		if (!item.equals("")) {
+			String prevItem = historyList.peekFirst();
+			if (prevItem == null) {
+				historyList.addFirst(item);
+			}
+			else {
+				if (!prevItem.equalsIgnoreCase(item))
+					historyList.addFirst(item);
+			}
+			if (historyList.size() > maxLen) {
+				historyList.removeLast();
+			}
+		}
+		num = -1;
+	}
+	
+	public String getPrevItem() {
+		num += 1;
+		if (num >= historyList.size()) {
+			num = historyList.size() - 1;
+		}
+		if (num < 0) {
+			num = -1;
+			return "";
+		}
+		return historyList.get(num);
+	}
+	
+	public String getLastItem() {
+		if (historyList.size() > 0)
+			return historyList.get(0);
+		return "";
+	}
+
+	public String getNextItem() {
+		num -= 1;
+		if (num < 0) {
+			num = -1;
+			return "";
+		}
+		return historyList.get(num);
+	}
+}
+
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/LengthAction.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/LengthAction.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/LengthAction.java	(revision 25037)
@@ -0,0 +1,256 @@
+/*
+ *	  LengthAction.java
+ *
+ *	  Copyright 2010 Hind <foxhind@gmail.com>
+ *
+ */
+
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.AWTEvent;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
+import java.awt.event.AWTEventListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.geom.GeneralPath;
+import java.awt.image.BufferedImage;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.SelectionChangedListener;
+import org.openstreetmap.josm.data.coor.*;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.MapViewPaintable;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Shortcut;
+
+public class LengthAction extends MapMode implements MapViewPaintable, AWTEventListener {
+	private CommandLine parentPlugin;
+	final private Cursor cursorCrosshair;
+	final private Cursor cursorJoinNode;
+	private Cursor currentCursor;
+	private Color selectedColor;
+	private Point drawStartPos;
+	private Point drawEndPos;
+	private LatLon startCoor;
+	private LatLon endCoor;
+	private Point mousePos;
+	private Node nearestNode;
+	private boolean drawing;
+
+	public LengthAction(MapFrame mapFrame, CommandLine parentPlugin) {
+		super(null, "building", null, mapFrame, ImageProvider.getCursor("crosshair", null));
+		this.parentPlugin = parentPlugin;
+		selectedColor = Main.pref.getColor(marktr("selected"), Color.red);
+		cursorCrosshair = ImageProvider.getCursor("crosshair", null);
+		cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");
+		currentCursor = cursorCrosshair;
+		nearestNode = null;
+	}
+
+	@Override
+	public void enterMode() {
+		super.enterMode();
+		Main.map.mapView.addMouseListener(this);
+		Main.map.mapView.addMouseMotionListener(this);
+		Main.map.mapView.addTemporaryLayer(this);
+		try {
+			Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+		} catch (SecurityException ex) {
+		}
+	}
+
+	@Override
+	public void exitMode() {
+		super.exitMode();
+		Main.map.mapView.removeMouseListener(this);
+		Main.map.mapView.removeMouseMotionListener(this);
+		Main.map.mapView.removeTemporaryLayer(this);
+		try {
+			Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+		} catch (SecurityException ex) {
+		}
+		if (drawing)
+			Main.map.mapView.repaint();
+	}
+
+	public void cancelDrawing() {
+		if (Main.map == null || Main.map.mapView == null)
+			return;
+		Main.map.statusLine.setHeading(-1);
+		Main.map.statusLine.setAngle(-1);
+		updateStatusLine();
+		parentPlugin.endInput();
+	}
+
+	public void eventDispatched(AWTEvent arg0) {
+		if (!(arg0 instanceof KeyEvent))
+			return;
+		KeyEvent ev = (KeyEvent) arg0;
+		if (ev.getKeyCode() == KeyEvent.VK_ESCAPE && ev.getID() == KeyEvent.KEY_PRESSED) {
+			if (drawing)
+				ev.consume();
+			cancelDrawing();
+		}
+	}
+
+	private void processMouseEvent(MouseEvent e) {
+		if (e != null) {
+			mousePos = e.getPoint();
+		}
+	}
+
+	public void paint(Graphics2D g, MapView mv, Bounds bbox) {
+		if (!drawing)
+			return;
+
+		g.setColor(selectedColor);
+		g.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+
+		GeneralPath b = new GeneralPath();
+		Point pp1 = drawStartPos;
+		Point pp2 = drawEndPos;
+
+		b.moveTo(pp1.x, pp1.y);
+		b.lineTo(pp2.x, pp2.y);
+		g.draw(b);
+
+		g.setStroke(new BasicStroke(1));
+	}
+
+	private void drawingStart(MouseEvent e) {
+		mousePos = e.getPoint();
+		if (nearestNode != null) {
+			drawStartPos = Main.map.mapView.getPoint(nearestNode.getCoor());
+		} else {
+			drawStartPos = mousePos;
+		}
+		drawEndPos = drawStartPos;
+		startCoor = Main.map.mapView.getLatLon(drawStartPos.x, drawStartPos.y);
+		endCoor = startCoor;
+		drawing = true;
+		updateStatusLine();
+	}
+
+	private void drawingFinish() {
+		parentPlugin.loadParameter(String.valueOf(startCoor.greatCircleDistance(endCoor)), true);
+		drawStartPos = null;
+		drawing = false;
+		exitMode();
+	}
+
+	@Override
+	public void mousePressed(MouseEvent e) {
+		if (e.getButton() == MouseEvent.BUTTON1) {
+		  if (!Main.map.mapView.isActiveLayerDrawable())
+			return;
+		  drawingStart(e);
+		}
+		else
+		  drawing = false;
+	}
+
+	@Override
+	public void mouseReleased(MouseEvent e) {
+	  if (e.getButton() != MouseEvent.BUTTON1)
+		  return;
+	  if (!Main.map.mapView.isActiveLayerDrawable())
+		  return;
+	  boolean dragged = true;
+	  if (drawStartPos != null)
+		  dragged = drawEndPos.distance(drawStartPos) > 10;
+	  if (drawing && dragged)
+		drawingFinish();
+	  drawing = false;
+	}
+
+	@Override
+	public void mouseDragged(MouseEvent e) {
+		processMouseEvent(e);
+		updCursor();
+		if (nearestNode != null)
+			drawEndPos = Main.map.mapView.getPoint(nearestNode.getCoor());
+		else
+			drawEndPos = mousePos;
+		endCoor = Main.map.mapView.getLatLon(drawEndPos.x, drawEndPos.y);
+    if (drawing) {
+      Main.map.statusLine.setDist(startCoor.greatCircleDistance(endCoor));
+			Main.map.mapView.repaint();
+    }
+	}
+
+	@Override
+	public void mouseMoved(MouseEvent e) {
+		if (!Main.map.mapView.isActiveLayerDrawable())
+			return;
+		processMouseEvent(e);
+		updCursor();
+		if (drawing)
+			Main.map.mapView.repaint();
+	}
+
+	@Override
+	public String getModeHelpText() {
+		if (drawing)
+			return tr("Point on the start");
+		else
+			return tr("Point on the end");
+	}
+
+	@Override
+	public boolean layerIsSupported(Layer l) {
+		return l instanceof OsmDataLayer;
+	}
+
+	private void updCursor() {
+		if (mousePos != null) {
+			if (!Main.isDisplayingMapView())
+				return;
+			nearestNode = Main.map.mapView.getNearestNode(mousePos, OsmPrimitive.isUsablePredicate);
+			if (nearestNode != null) {
+				setCursor(cursorJoinNode);
+			}
+			else {
+				setCursor(cursorCrosshair);
+			}
+		}
+	}
+
+	private void setCursor(final Cursor c) {
+		if (currentCursor.equals(c))
+			return;
+		try {
+			// We invoke this to prevent strange things from happening
+			EventQueue.invokeLater(new Runnable() {
+				public void run() {
+					// Don't change cursor when mode has changed already
+					if (!(Main.map.mapMode instanceof LengthAction))
+						return;
+					Main.map.mapView.setCursor(c);
+				}
+			});
+			currentCursor = c;
+		} catch (Exception e) {
+		}
+	}
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/Loader.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/Loader.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/Loader.java	(revision 25037)
@@ -0,0 +1,170 @@
+/*
+ *	  Loader.java
+ *	  
+ *	  Copyright 2010 Hind <foxhind@gmail.com>
+ *	  
+ */
+ 
+package commandline;
+
+import java.util.ArrayList;
+import java.io.File;
+import java.util.List;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class Loader extends DefaultHandler {
+	private String dirToScan;
+	private String currentFile; // For debug XML-files
+	private String currentTag;
+	private Command currentCommand;
+	private Parameter currentParameter;
+	private ArrayList<Command> loadingCommands;
+
+	public Loader (String dir) {
+		dirToScan = dir;
+		currentTag = "";
+		loadingCommands = new ArrayList<Command>();
+	}
+
+	public ArrayList<Command> load() {
+		try {
+			// Creating parser
+			SAXParserFactory spf = SAXParserFactory.newInstance();
+			SAXParser sp = spf.newSAXParser();
+			
+			// Files loading
+			File path = new File(dirToScan + "/");
+			String[] list;
+			list = path.list();
+			for(int i = 0; i < list.length; i++)
+				if (list[i].endsWith(".xml")) {
+					currentFile = dirToScan + "/" + list[i];
+					loadFile(sp, currentFile);
+				}
+		}
+		catch (Exception e) {
+			System.err.println(e);
+		}
+		return loadingCommands;
+	}
+
+	private void loadFile(SAXParser parser, String fileName) {
+		try {
+			parser.parse(fileName, this);
+		}
+		catch (Exception e) {
+			System.err.println(e);
+		}
+		// TODO: Create links for each argument
+	}
+
+	public void startElement(String namespaceURI, String localName, String rawName, Attributes attrs) {
+		int len = attrs.getLength();
+		String Name, Value;
+		currentTag = rawName;
+
+		if (rawName.equals("command")) {
+			currentCommand = new Command();
+			for (int i = 0; i < len; i++) {
+				Name = attrs.getQName(i);
+				Value = attrs.getValue(i);
+				if (Name.equals("name"))
+					currentCommand.name = Value;
+				else if (Name.equals("run"))
+					currentCommand.run = Value;
+				else if (Name.equals("tracks"))
+					if (Value.equals("bbox"))
+						currentCommand.tracks = true;
+			}
+		}
+		else if (rawName.equals("parameter")) {
+			currentParameter = new Parameter();
+			for (int i = 0; i < len; i++) {
+				Name = attrs.getQName(i);
+				Value = attrs.getValue(i);
+				if (Name.equals("required")) {
+					currentParameter.required = Value.equals("true") ? true : false;
+				}
+				else if (Name.equals("type")) {
+					if (Value.equals("node")) currentParameter.type = Type.NODE;
+					else if (Value.equals("way")) currentParameter.type = Type.WAY;
+					else if (Value.equals("relation")) currentParameter.type = Type.RELATION;
+					else if (Value.equals("point")) currentParameter.type = Type.POINT;
+					else if (Value.equals("length")) currentParameter.type = Type.LENGTH;
+					else if (Value.equals("natural")) currentParameter.type = Type.NATURAL;
+					else if (Value.equals("any")) currentParameter.type = Type.ANY;
+					else if (Value.equals("string")) currentParameter.type = Type.STRING;
+					else if (Value.equals("relay")) currentParameter.type = Type.RELAY;
+				}
+				else if (Name.equals("maxinstances")) {
+					currentParameter.maxInstances = Integer.parseInt(Value);
+				}
+				else if (Name.equals("maxvalue")) {
+					currentParameter.maxVal = Float.parseFloat(Value);
+				}
+				else if (Name.equals("minvalue")) {
+					currentParameter.minVal = Float.parseFloat(Value);
+				}
+			}
+		}
+	}
+
+	public void characters(char ch[], int start, int length) 
+	{
+		String text = (new String(ch, start, length)).trim();
+		if (currentParameter != null) {
+			if (currentTag.equals("name")) {
+				currentParameter.name = text;
+			}
+			else if (currentTag.equals("description")) {
+				currentParameter.description = text;
+			}
+			else if (currentTag.equals("value")) {
+				if (currentParameter.type == Type.RELAY) {
+					if (!(currentParameter.getRawValue() instanceof Relay))
+						currentParameter.setValue(new Relay());
+					((Relay)(currentParameter.getRawValue())).addValue(text);
+				}
+				else {
+					currentParameter.setValue(text);
+				}
+			}
+		}
+	}
+
+	public void endElement(String namespaceURI, String localName, String rawName) {
+		if (rawName.equals("command")) {
+			loadingCommands.add(currentCommand);
+			currentCommand = null;
+		}
+		else if (rawName.equals("parameter")) {
+			if(currentParameter.required)
+				currentCommand.parameters.add(currentParameter);
+			else
+				currentCommand.optParameters.add(currentParameter);
+			currentParameter = null;
+		}
+		else {
+			currentTag = "";
+		}
+	}
+
+	public void warning(SAXParseException ex) {
+	  System.err.println("Warning in command xml file " + currentFile + ": " + ex.getMessage());
+	}
+
+	public void error(SAXParseException ex) {
+	  System.err.println("Error in command xml file " + currentFile + ": " + ex.getMessage());
+	}
+
+	public void fatalError(SAXParseException ex) throws SAXException {
+	  System.err.println("Error in command xml file " + currentFile + ": " + ex.getMessage());
+	  throw ex;
+	}
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/Mode.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/Mode.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/Mode.java	(revision 25037)
@@ -0,0 +1,24 @@
+/*
+ *      Mode.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *      
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *      
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ */
+ 
+package commandline;
+
+public enum Mode { IDLE, SELECTION, ADJUSTMENT, PROCESSING }
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/NodeAction.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/NodeAction.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/NodeAction.java	(revision 25037)
@@ -0,0 +1,174 @@
+/*
+ *      NodeAction.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.AWTEvent;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.event.AWTEventListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class NodeAction extends MapMode implements AWTEventListener {
+	private CommandLine parentPlugin;
+    final private Cursor cursorNormal, cursorActive;
+    private Cursor currentCursor;
+    private Point mousePos;
+    private Node nearestNode;
+    private boolean isCtrlDown;
+    // private Type type;
+
+	public NodeAction(MapFrame mapFrame, CommandLine parentPlugin) {
+		super(null, "addsegment.png", null, mapFrame, ImageProvider.getCursor("normal", "selection"));
+		this.parentPlugin = parentPlugin;
+		cursorNormal = ImageProvider.getCursor("normal", "selection");
+		cursorActive = ImageProvider.getCursor("normal", "joinnode");
+        currentCursor = cursorNormal;
+        nearestNode = null;
+	}
+
+	@Override public void enterMode() {
+		super.enterMode();
+        currentCursor = cursorNormal;
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+        try {
+            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+        } catch (SecurityException ex) {
+        }
+	}
+
+	@Override public void exitMode() {
+		super.exitMode();
+		Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        try {
+            Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+        } catch (SecurityException ex) {
+        }
+	}
+
+    @Override
+    public void mouseMoved(MouseEvent e) {
+        if (!Main.map.mapView.isActiveLayerDrawable())
+            return;
+        processMouseEvent(e);
+        updCursor();
+        Main.map.mapView.repaint();
+        super.mouseMoved(e);
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e) {
+        if (!Main.map.mapView.isActiveLayerDrawable())
+            return;
+        processMouseEvent(e);
+        if (nearestNode != null) {
+			if (isCtrlDown) {
+				Main.main.getCurrentDataSet().clearSelection(nearestNode);
+				Main.map.mapView.repaint();
+			}
+			else {
+				int maxInstances = parentPlugin.currentCommand.parameters.get(parentPlugin.currentCommand.currentParameterNum).maxInstances;
+				switch (maxInstances) {
+				case 0:
+					Main.main.getCurrentDataSet().addSelected(nearestNode);
+					Main.map.mapView.repaint();
+					break;
+				case 1:
+					Main.main.getCurrentDataSet().addSelected(nearestNode);
+					Main.map.mapView.repaint();
+					parentPlugin.loadParameter(nearestNode, true);
+					exitMode();
+					break;
+				default:
+					if (Main.main.getCurrentDataSet().getSelected().size() < maxInstances) {
+						Main.main.getCurrentDataSet().addSelected(nearestNode);
+						Main.map.mapView.repaint();
+					}
+					else
+						System.out.println("Maximum instances!");
+				}
+			}
+		}
+        super.mousePressed(e);
+    }
+
+	public void eventDispatched(AWTEvent arg0) {
+		if (!(arg0 instanceof KeyEvent))
+			return;
+		KeyEvent ev = (KeyEvent) arg0;
+        isCtrlDown = (ev.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0;
+        if (ev.getKeyCode() == KeyEvent.VK_ESCAPE && ev.getID() == KeyEvent.KEY_PRESSED) {
+            ev.consume();
+            cancelDrawing();
+        }
+    }
+
+    private void updCursor() {
+        if (mousePos != null) {
+			if (!Main.isDisplayingMapView())
+				return;
+			nearestNode = Main.map.mapView.getNearestNode(mousePos, OsmPrimitive.isUsablePredicate);
+			if (nearestNode != null) {
+				setCursor(cursorActive);
+			}
+			else {
+				setCursor(cursorNormal);
+			}
+		}
+    }
+
+	private void processMouseEvent(MouseEvent e) {
+		if (e != null) { mousePos = e.getPoint(); }
+	}
+
+    private void setCursor(final Cursor c) {
+        if (currentCursor.equals(c))
+            return;
+        try {
+            // We invoke this to prevent strange things from happening
+            EventQueue.invokeLater(new Runnable() {
+                public void run() {
+                    // Don't change cursor when mode has changed already
+                    if (!(Main.map.mapMode instanceof NodeAction))
+                        return;
+                    Main.map.mapView.setCursor(c);
+                }
+            });
+            currentCursor = c;
+        } catch (Exception e) {
+        }
+    }
+
+    public void cancelDrawing() {
+        if (Main.map == null || Main.map.mapView == null)
+            return;
+        Main.map.statusLine.setHeading(-1);
+        Main.map.statusLine.setAngle(-1);
+        Main.map.mapView.repaint();
+        updateStatusLine();
+        parentPlugin.endInput();
+    }
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/OsmToCmd.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/OsmToCmd.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/OsmToCmd.java	(revision 25037)
@@ -0,0 +1,361 @@
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.ChangeNodesCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.DeleteCommand;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.*;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.io.OsmDataParsingException;
+import org.openstreetmap.josm.io.UTFInputStreamReader;
+import org.openstreetmap.josm.tools.DateUtils;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+final class OsmToCmd {
+	private final DataSet targetDataSet;
+	private final LinkedList<Command> cmds = new LinkedList<Command>();
+	private HashMap<PrimitiveId, OsmPrimitive> externalIdMap; // Maps external ids to internal primitives
+	
+	public OsmToCmd(DataSet targetDataSet, InputStream stream) throws IllegalDataException {
+		this.targetDataSet = targetDataSet;
+		externalIdMap = new HashMap<PrimitiveId, OsmPrimitive>();
+		parseStream(stream);
+	}
+
+	private void parseStream(InputStream stream) throws IllegalDataException {
+		try {
+			InputSource inputSource = new InputSource(UTFInputStreamReader.create(stream, "UTF-8"));
+			SAXParserFactory.newInstance().newSAXParser().parse(inputSource, new Parser());
+		} catch(ParserConfigurationException e) {
+			throw new IllegalDataException(e.getMessage(), e);
+		} catch (SAXParseException e) {
+			throw new IllegalDataException(tr("Line {0} column {1}: ", e.getLineNumber(), e.getColumnNumber()) + e.getMessage(), e);
+		} catch(SAXException e) {
+			throw new IllegalDataException(e.getMessage(), e);
+		} catch(Exception e) {
+			throw new IllegalDataException(e);
+		}
+	}
+
+	public LinkedList<Command> getCommandList() {
+		return cmds;
+	}
+	
+	private class Parser extends DefaultHandler {
+		private Locator locator;
+		
+		@Override
+		public void setDocumentLocator(Locator locator) {
+			this.locator = locator;
+		}
+
+		protected void throwException(String msg) throws OsmDataParsingException {
+			throw new OsmDataParsingException(msg).rememberLocation(locator);
+		}
+
+		private OsmPrimitive currentPrimitive;
+		private long currentExternalId;
+		private List<Node> currentWayNodes = new ArrayList<Node>();
+		private List<RelationMember> currentRelationMembers = new ArrayList<RelationMember>();
+
+		@Override
+		public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+			try {
+				if (qName.equals("osm")) {
+					if (atts == null) {
+						throwException(tr("Missing mandatory attribute ''{0}'' of XML element {1}.", "version", "osm"));
+					}
+					String v = atts.getValue("version");
+					if (v == null) {
+						throwException(tr("Missing mandatory attribute ''{0}''.", "version"));
+					}
+					if ( !(v.equals("0.6")) ) {
+						throwException(tr("Unsupported version: {0}", v));
+					}
+
+					// ---- PARSING NODES AND WAYS ----
+
+				} else if (qName.equals("node")) {
+					Node n = new Node();
+					NodeData source = new NodeData();
+					source.setCoor(new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon")));
+					readCommon(atts, source);
+					Node target = (Node)targetDataSet.getPrimitiveById( source.getUniqueId(), source.getType() );
+					
+					if (target == null || !(source.isModified() || source.isDeleted()) )
+						n.load(source);
+					else {
+						n.cloneFrom(target);
+						n.load(source);
+					}
+					
+					currentPrimitive = n;
+					externalIdMap.put(source.getPrimitiveId(), (OsmPrimitive)n);
+					//System.out.println("NODE " + String.valueOf(source.getUniqueId()) + " HAS MAPPED TO INNER " + String.valueOf(n.getUniqueId()) );
+				}
+				else if (qName.equals("way")) {
+					Way w = new Way();
+					WayData source = new WayData();
+					readCommon(atts, source);
+					Way target = (Way)targetDataSet.getPrimitiveById( source.getUniqueId(), source.getType() );
+					
+					if (target == null || !(source.isModified() || source.isDeleted()) )
+						w.load(source);
+					else {
+						w.cloneFrom(target);
+						w.load(source);
+					}
+					
+					currentPrimitive = w;
+					currentWayNodes.clear();
+					externalIdMap.put(source.getPrimitiveId(), (OsmPrimitive)w);
+					//System.out.println("WAY " + String.valueOf(source.getUniqueId()) + " HAS MAPPED TO INNER " + String.valueOf(w.getUniqueId()) );
+				}
+				else if (qName.equals("nd")) {
+					if (atts.getValue("ref") == null)
+						throwException(tr("Missing mandatory attribute ''{0}'' on <nd> of way {1}.", "ref", currentPrimitive.getUniqueId()));
+					long id = getLong(atts, "ref");
+					if (id == 0)
+						throwException(tr("Illegal value of attribute ''ref'' of element <nd>. Got {0}.", id) );
+					//System.out.println("NODE " + String.valueOf(id) + " HAS ADDED TO WAY " + String.valueOf(currentPrimitive.getUniqueId()));
+					Node node = (Node)externalIdMap.get(new SimplePrimitiveId(id, OsmPrimitiveType.NODE));
+					if (node == null || node.isModified()) {
+						node = (Node)targetDataSet.getPrimitiveById( new SimplePrimitiveId(id, OsmPrimitiveType.NODE) );
+						if (node == null)
+							throwException(tr("Missing definition of new object with id {0}.", id));
+					}
+					currentWayNodes.add(node);
+				}
+					// ---- PARSING RELATIONS ----
+
+				else if (qName.equals("relation")) {
+					Relation r = new Relation();
+					RelationData source = new RelationData();
+					readCommon(atts, source);
+					Relation target = (Relation)targetDataSet.getPrimitiveById( source.getUniqueId(), source.getType() );
+					
+					if (target == null || !(source.isModified() || source.isDeleted()) )
+						r.load(source);
+					else {
+						r.cloneFrom(target);
+						r.load(source);
+					}
+					
+					currentPrimitive = r;
+					currentRelationMembers.clear();
+					externalIdMap.put(source.getPrimitiveId(), (OsmPrimitive)r);
+					//System.out.println("RELATION " + String.valueOf(source.getUniqueId()) + " HAS MAPPED TO INNER " + String.valueOf(r.getUniqueId()) );
+				}
+				else if (qName.equals("member")) {
+					if (atts.getValue("ref") == null)
+						throwException(tr("Missing mandatory attribute ''{0}'' on <member> of relation {1}.", "ref", currentPrimitive.getUniqueId()));
+					long id = getLong(atts, "ref");
+					if (id == 0)
+						throwException(tr("Illegal value of attribute ''ref'' of element <nd>. Got {0}.", id) );
+
+					OsmPrimitiveType type = OsmPrimitiveType.NODE;
+					String value = atts.getValue("type");
+					if (value == null) {
+						throwException(tr("Missing attribute ''type'' on member {0} in relation {1}.", Long.toString(id), Long.toString(currentPrimitive.getUniqueId())));
+					}
+					try {
+						type = OsmPrimitiveType.fromApiTypeName(value);
+					}
+					catch(IllegalArgumentException e) {
+						throwException(tr("Illegal value for attribute ''type'' on member {0} in relation {1}. Got {2}.", Long.toString(id), Long.toString(currentPrimitive.getUniqueId()), value));
+					}
+
+					String role = atts.getValue("role");
+
+					//System.out.println("MEMBER " + value.toUpperCase() + " " +String.valueOf(id) + " HAS ADDED TO RELATION " + String.valueOf(currentPrimitive.getUniqueId()));
+					OsmPrimitive member = externalIdMap.get(new SimplePrimitiveId(id, type));
+					if (member == null) {
+						member = targetDataSet.getPrimitiveById(new SimplePrimitiveId(id, type));
+						if (member == null)
+							throwException(tr("Missing definition of new object with id {0}.", id));
+					}
+					RelationMember relationMember = new RelationMember(role, member);
+					currentRelationMembers.add(relationMember);
+				}
+
+					// ---- PARSING TAGS (applicable to all objects) ----
+
+				else if (qName.equals("tag")) {
+					String key = atts.getValue("k");
+					String value = atts.getValue("v");
+					if (key == null || value == null) {
+						throwException(tr("Missing key or value attribute in tag."));
+					}
+					currentPrimitive.put(key.intern(), value.intern());
+				}
+				else {
+					System.out.println(tr("Undefined element ''{0}'' found in input stream. Skipping.", qName));
+				}
+			}
+			catch (Exception e) {
+				throw new SAXParseException(e.getMessage(), locator, e);
+			}
+		}
+
+		@Override
+		public void endElement(String namespaceURI, String localName, String qName) {
+			if (qName.equals("node")) {
+				if (currentPrimitive.isDeleted()) {
+					cmds.add(new DeleteCommand( targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()) ));
+				}
+				else if (currentPrimitive.isModified()) {
+					//System.out.println(String.valueOf(currentPrimitive.getUniqueId()) + " IS MODIFIED BY SCRIPT");
+					cmds.add(new ChangeCommand(Main.map.mapView.getEditLayer(), (Node)targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()), currentPrimitive));
+				}
+				else if (currentPrimitive.isNew()) {
+					cmds.add(new AddCommand(currentPrimitive));
+				}
+			}
+			else if (qName.equals("way")) {
+				((Way)currentPrimitive).setNodes(currentWayNodes);
+				if (currentPrimitive.isDeleted()) {
+					cmds.add(new DeleteCommand( targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()) ));
+				}
+				else if (currentPrimitive.isModified()) {
+					cmds.add(new ChangeCommand(Main.map.mapView.getEditLayer(), (Way)targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()), currentPrimitive));
+				}
+				else if (currentPrimitive.isNew()) {
+					cmds.add(new AddCommand(currentPrimitive));
+				}
+			}
+			else if (qName.equals("relation")) {
+				((Relation)currentPrimitive).setMembers(currentRelationMembers);
+				if (currentPrimitive.isDeleted()) {
+					cmds.add(new DeleteCommand( targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()) ));
+				}
+				else if (currentPrimitive.isModified()) {
+					cmds.add(new ChangeCommand(Main.map.mapView.getEditLayer(), (Relation)targetDataSet.getPrimitiveById(currentPrimitive.getPrimitiveId()), currentPrimitive));
+				}
+				else if (currentPrimitive.isNew()) {
+					cmds.add(new AddCommand(currentPrimitive));
+				}
+			}
+		}
+
+		private double getDouble(Attributes atts, String value) {
+			return Double.parseDouble(atts.getValue(value));
+		}
+
+		private long getLong(Attributes atts, String name) throws SAXException {
+			String value = atts.getValue(name);
+			if (value == null) {
+					throwException(tr("Missing required attribute ''{0}''.",name));
+				}
+				try {
+					return Long.parseLong(value);
+				}
+				catch(NumberFormatException e) {
+					throwException(tr("Illegal long value for attribute ''{0}''. Got ''{1}''.",name, value));
+			}
+			return 0; // should not happen
+		}
+
+		private User createUser(String uid, String name) throws SAXException {
+			if (uid == null) {
+				if (name == null)
+					return null;
+				return User.createLocalUser(name);
+			}
+			try {
+				long id = Long.parseLong(uid);
+				return User.createOsmUser(id, name);
+			}
+			catch(NumberFormatException e) {
+				throwException(tr("Illegal value for attribute ''uid''. Got ''{0}''.", uid));
+			}
+			return null;
+		}
+
+		void readCommon(Attributes atts, PrimitiveData current) throws SAXException {
+			current.setId(getLong(atts, "id"));
+			if (current.getUniqueId() == 0) {
+				throwException(tr("Illegal object with ID=0."));
+			}
+
+			String time = atts.getValue("timestamp");
+			if (time != null && time.length() != 0) {
+				current.setTimestamp(DateUtils.fromString(time));
+			}
+
+			String user = atts.getValue("user");
+			String uid = atts.getValue("uid");
+			current.setUser(createUser(uid, user));
+
+			String visible = atts.getValue("visible");
+			if (visible != null) {
+				current.setVisible(Boolean.parseBoolean(visible));
+			}
+
+			String versionString = atts.getValue("version");
+			int version = 0;
+			if (versionString != null) {
+				try {
+					version = Integer.parseInt(versionString);
+				} catch(NumberFormatException e) {
+					throwException(tr("Illegal value for attribute ''version'' on OSM primitive with ID {0}. Got {1}.", Long.toString(current.getUniqueId()), versionString));
+				}
+			}
+			current.setVersion(version);
+
+			String action = atts.getValue("action");
+			if (action == null) {
+				// do nothing
+			} else if (action.equals("delete")) {
+				current.setDeleted(true);
+				current.setModified(current.isVisible());
+			} else if (action.equals("modify")) {
+				current.setModified(true);
+			}
+
+			String v = atts.getValue("changeset");
+			if (v == null) {
+				current.setChangesetId(0);
+			} else {
+				try {
+					current.setChangesetId(Integer.parseInt(v));
+				} catch(NumberFormatException e) {
+					if (current.getUniqueId() <= 0) {
+						System.out.println(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.", v, current.getUniqueId()));
+						current.setChangesetId(0);
+					} else {
+						throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v));
+					}
+				}
+				if (current.getChangesetId() <=0) {
+					if (current.getUniqueId() <= 0) {
+						System.out.println(tr("Illegal value for attribute ''changeset'' on new object {1}. Got {0}. Resetting to 0.", v, current.getUniqueId()));
+						current.setChangesetId(0);
+					} else {
+						throwException(tr("Illegal value for attribute ''changeset''. Got {0}.", v));
+					}
+				}
+			}
+		}
+	}
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/Parameter.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/Parameter.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/Parameter.java	(revision 25037)
@@ -0,0 +1,84 @@
+/*
+ *      Parameter.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+ 
+package commandline;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+
+public class Parameter {
+	public boolean required;
+	public Type type;
+	public String name;
+	public String description;
+	private Object value;
+	private ArrayList<OsmPrimitive> valueList;
+	protected float maxVal;
+	protected float minVal;
+	protected int maxInstances;
+	
+	public Parameter () { required = false; maxInstances = 1; maxVal = 0; minVal = 0; value = ""; valueList = new ArrayList<OsmPrimitive>(); }
+	public String getValue() {
+		String out = "";
+		switch (type) {
+			case POINT:
+				out = (String)value;
+				break;
+			case LENGTH:
+				out = String.valueOf(value);
+				break;
+			case NATURAL:
+				out = String.valueOf(value);
+				break;
+			case STRING:
+				out = "\"" + String.valueOf(value) + "\"";
+				break;
+			case RELAY:
+				out = String.valueOf(((Relay)value).getValue());
+				break;
+		}
+		return out;
+	}
+
+	public Object getRawValue() {
+		return value;
+	}
+
+	public ArrayList<OsmPrimitive> getValueList() {
+		return valueList;
+	}
+
+	public void setValue(Object obj) {
+		if (type == Type.RELAY && obj instanceof String && value instanceof Relay) {
+			((Relay)value).setValue((String)obj);
+		}
+		else
+			value = obj;
+	}
+
+	public Collection<OsmPrimitive> getParameterObjects() {
+		ArrayList<OsmPrimitive> pObjects = new ArrayList<OsmPrimitive>();
+		if (isOsm()) {
+			if (maxInstances == 1) {
+				pObjects.add((OsmPrimitive)value);
+			}
+			else {
+				return valueList;
+			}
+		}
+		return pObjects;
+	}
+
+	public boolean isOsm() {
+		return type == Type.NODE || type == Type.WAY || type == Type.RELATION || type == Type.ANY;
+	}
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/PointAction.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/PointAction.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/PointAction.java	(revision 25037)
@@ -0,0 +1,202 @@
+/*
+ *	  PointAction.java
+ *	  
+ *	  Copyright 2010 Hind <foxhind@gmail.com>
+ *	  
+ */
+
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.AWTEvent;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.event.AWTEventListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.util.ArrayList;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.SelectionChangedListener;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class PointAction extends MapMode implements AWTEventListener {
+	private CommandLine parentPlugin;
+	final private Cursor cursorCrosshair;
+	final private Cursor cursorJoinNode;
+	private Cursor currentCursor;
+	private Point mousePos;
+	private Node nearestNode;
+	private ArrayList<String> pointList;
+	private boolean isCtrlDown;
+
+	public PointAction(MapFrame mapFrame, CommandLine parentPlugin) {
+		super(null, "addsegment.png", null, mapFrame, ImageProvider.getCursor("crosshair", null));
+		this.parentPlugin = parentPlugin;
+		cursorCrosshair = ImageProvider.getCursor("crosshair", null);
+		cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");
+		currentCursor = cursorCrosshair;
+		nearestNode = null;
+		pointList = new ArrayList<String>();
+	}
+
+	@Override public void enterMode() {
+		super.enterMode();
+		if (getCurrentDataSet() == null) {
+			Main.map.selectSelectTool(false);
+			return;
+		}
+		currentCursor = cursorCrosshair;
+		Main.map.mapView.addMouseListener(this);
+		Main.map.mapView.addMouseMotionListener(this);
+		try {
+			Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+		} catch (SecurityException ex) {
+		}
+	}
+
+	@Override public void exitMode() {
+		super.exitMode();
+		Main.map.mapView.removeMouseListener(this);
+		Main.map.mapView.removeMouseMotionListener(this);
+		try {
+			Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+		} catch (SecurityException ex) {
+		}
+	}
+
+	@Override public void mousePressed(MouseEvent e) {
+		if (e.getButton() == MouseEvent.BUTTON1) {
+			if (isCtrlDown) {
+				if (pointList.size() > 0) {
+					pointList.remove(pointList.size() - 1);
+					updateTextEdit();
+				}
+			}
+			else {
+				LatLon coor;
+				if (nearestNode == null)
+					coor = Main.map.mapView.getLatLon(e.getX(), e.getY());
+				else
+					coor = nearestNode.getCoor();
+				if (coor.isOutSideWorld()) {
+					JOptionPane.showMessageDialog(Main.parent,tr("Can not draw outside of the world."));
+					return;
+				}
+				String point = String.valueOf(coor.getX()) + "," + String.valueOf(coor.getY());
+				int maxInstances = parentPlugin.currentCommand.parameters.get(parentPlugin.currentCommand.currentParameterNum).maxInstances;
+				if (maxInstances == 1) {
+					parentPlugin.loadParameter(point, true);
+					exitMode();
+				}
+				else {
+					if (pointList.size() < maxInstances || maxInstances == 0) {
+						pointList.add(point);
+						updateTextEdit();
+					}
+					else
+						System.out.println("Maximum instances!");
+				}
+			}
+		}
+	}
+
+	@Override
+	public void mouseMoved(MouseEvent e) {
+		if (!Main.map.mapView.isActiveLayerDrawable())
+			return;
+		processMouseEvent(e);
+		updCursor();
+		Main.map.mapView.repaint();
+	}
+
+	public void eventDispatched(AWTEvent arg0) {
+		if (!(arg0 instanceof KeyEvent))
+			return;
+		KeyEvent ev = (KeyEvent) arg0;
+		isCtrlDown = (ev.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0;
+		if (ev.getKeyCode() == KeyEvent.VK_ESCAPE && ev.getID() == KeyEvent.KEY_PRESSED) {
+			ev.consume();
+			cancelDrawing();
+		}
+	}
+
+	private void updCursor() {
+		if (mousePos != null) {
+			if (!Main.isDisplayingMapView())
+				return;
+			nearestNode = Main.map.mapView.getNearestNode(mousePos, OsmPrimitive.isUsablePredicate);
+			if (nearestNode != null) {
+				setCursor(cursorJoinNode);
+			}
+			else {
+				setCursor(cursorCrosshair);
+			}
+		}
+	}
+
+	private void processMouseEvent(MouseEvent e) {
+		if (e != null) {
+			mousePos = e.getPoint();
+		}
+	}
+
+	private void setCursor(final Cursor c) {
+		if (currentCursor.equals(c))
+			return;
+		try {
+			// We invoke this to prevent strange things from happening
+			EventQueue.invokeLater(new Runnable() {
+				public void run() {
+					// Don't change cursor when mode has changed already
+					if (!(Main.map.mapMode instanceof PointAction))
+						return;
+					Main.map.mapView.setCursor(c);
+				}
+			});
+			currentCursor = c;
+		} catch (Exception e) {
+		}
+	}
+
+	public void cancelDrawing() {
+		if (Main.map == null || Main.map.mapView == null)
+			return;
+		Main.map.statusLine.setHeading(-1);
+		Main.map.statusLine.setAngle(-1);
+		Main.map.mapView.repaint();
+		updateStatusLine();
+		parentPlugin.endInput();
+	}
+
+	public String currentValue() {
+		String out = "";
+		boolean first = true;
+		for (String point : pointList) {
+			if (!first)
+				out += ";";
+			out += point;
+			first = false;
+		}
+		return out;
+	}
+	
+	private void updateTextEdit() {
+		Parameter currentParameter = parentPlugin.currentCommand.parameters.get(parentPlugin.currentCommand.currentParameterNum);
+		String prefix = tr(currentParameter.description);
+		prefix += parentPlugin.commandSymbol;
+		String value = currentValue();
+		parentPlugin.textField.setText(prefix + value);
+	}
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/RelationAction.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/RelationAction.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/RelationAction.java	(revision 25037)
@@ -0,0 +1,60 @@
+/*
+ *      RelationAction.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.AWTEvent;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.event.AWTEventListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class RelationAction extends MapMode implements AWTEventListener {
+	private CommandLine parentPlugin;
+
+	public RelationAction(MapFrame mapFrame, CommandLine parentPlugin) {
+		super(null, "addsegment.png", null, mapFrame, ImageProvider.getCursor("normal", null));
+		this.parentPlugin = parentPlugin;
+	}
+
+	public void eventDispatched(AWTEvent arg0) {
+		if (!(arg0 instanceof KeyEvent))
+			return;
+		KeyEvent ev = (KeyEvent) arg0;
+        if (ev.getKeyCode() == KeyEvent.VK_ESCAPE && ev.getID() == KeyEvent.KEY_PRESSED) {
+            ev.consume();
+            cancelDrawing();
+        }
+    }
+
+    public void cancelDrawing() {
+        if (Main.map == null || Main.map.mapView == null)
+            return;
+        Main.map.statusLine.setHeading(-1);
+        Main.map.statusLine.setAngle(-1);
+        Main.map.mapView.repaint();
+        updateStatusLine();
+        parentPlugin.endInput();
+    }
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/Relay.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/Relay.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/Relay.java	(revision 25037)
@@ -0,0 +1,62 @@
+/*
+ *      Relay.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+
+package commandline;
+
+import java.util.HashMap;
+
+public class Relay {
+  static String marker = "\u0332";
+  private String optionsString;
+  private HashMap<String, String> options;
+  private String value;
+
+  public Relay() {
+    optionsString = "";
+    value = "";
+    options = new HashMap<String, String>();
+  }
+
+  public void setValue(String value) {
+    if (options.containsKey(value))
+      this.value = options.get(value);
+    else if (options.containsValue(value))
+      this.value = value;
+  }
+
+  public void addValue(String value) {
+    String letter = null;
+    if (!(options.containsValue(value))) {
+      int i = 0;
+      for (; i < value.length() ; i++) {
+        letter = value.substring(i, i + 1).toLowerCase();
+        if (!options.containsKey(letter))
+          break;
+      }
+      if (i == value.length()) {
+        letter = String.valueOf(System.currentTimeMillis());
+        optionsString = optionsString + (optionsString.length() == 0 ? "" : ", ") + value;
+      }
+      else
+        optionsString = optionsString + (optionsString.length() == 0 ? "" : ", ") + value.substring(0, i) + marker + value.substring(i);
+      options.put(letter, value);
+    }
+    this.value = value;
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  public boolean isCorrectValue(String value) {
+    return options.containsValue(value) || options.containsKey(value.toLowerCase());
+  }
+
+  public String getOptionsString() {
+    return optionsString;
+  }
+}
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/Type.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/Type.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/Type.java	(revision 25037)
@@ -0,0 +1,21 @@
+/*
+ *      Type.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ *      NODE     - Node
+ *      WAY      - Way
+ *      RELATION - Relation
+ *      ANY      - Any osm object (node, way or relation)
+ *      POINT    - Coordinates like as Lon,Lat
+ *      LENGTH   - Fractional number
+ *      NATURAL  - Natural number (1, 10, 9000)
+ *      STRING   - Text string
+ *      TRIGGER  - Yes/No
+ *      RELAY    - 
+ * 
+ */
+ 
+package commandline;
+
+public enum Type { NODE, WAY, RELATION, ANY, POINT, LENGTH, NATURAL, STRING, TRIGGER, RELAY }
Index: /applications/editors/josm/plugins/CommandLine/src/CommandLine/WayAction.java
===================================================================
--- /applications/editors/josm/plugins/CommandLine/src/CommandLine/WayAction.java	(revision 25037)
+++ /applications/editors/josm/plugins/CommandLine/src/CommandLine/WayAction.java	(revision 25037)
@@ -0,0 +1,195 @@
+/*
+ *      WayAction.java
+ *      
+ *      Copyright 2010 Hind <foxhind@gmail.com>
+ *      
+ */
+
+package commandline;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.AWTEvent;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.event.AWTEventListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class WayAction extends MapMode implements AWTEventListener {
+	private CommandLine parentPlugin;
+    final private Cursor cursorNormal, cursorActive;
+    private Cursor currentCursor;
+    private Point mousePos;
+    private Way nearestWay;
+    private boolean isCtrlDown;
+    // private Type type;
+
+	public WayAction(MapFrame mapFrame, CommandLine parentPlugin) {
+		super(null, "addsegment.png", null, mapFrame, ImageProvider.getCursor("normal", "selection"));
+		this.parentPlugin = parentPlugin;
+/*
+		this.type = type;
+		switch (type) {
+			case POINT:
+				cursorNormal = ImageProvider.getCursor("crosshair", null);
+				cursorActive = ImageProvider.getCursor("crosshair", "joinnode");
+				break;
+			case NODE:
+				cursorNormal = ImageProvider.getCursor("normal", "selection");
+				cursorActive = ImageProvider.getCursor("normal", "joinnode");
+				break;
+			case WAY:
+*/
+				cursorNormal = ImageProvider.getCursor("normal", "selection");
+				cursorActive = ImageProvider.getCursor("normal", "joinway");
+/*
+				break;
+			default:
+				cursorNormal = ImageProvider.getCursor("normal", "selection");
+				cursorActive = ImageProvider.getCursor("normal", null);
+				break;
+		}
+*/
+        currentCursor = cursorNormal;
+        nearestWay = null;
+	}
+
+	@Override public void enterMode() {
+		super.enterMode();
+        currentCursor = cursorNormal;
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+        try {
+            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+        } catch (SecurityException ex) {
+        }
+	}
+
+	@Override public void exitMode() {
+		super.exitMode();
+		Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        try {
+            Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+        } catch (SecurityException ex) {
+        }
+	}
+
+    @Override
+    public void mouseMoved(MouseEvent e) {
+        if (!Main.map.mapView.isActiveLayerDrawable())
+            return;
+        processMouseEvent(e);
+        updCursor();
+        Main.map.mapView.repaint();
+        super.mouseMoved(e);
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e) {
+        if (!Main.map.mapView.isActiveLayerDrawable())
+            return;
+        processMouseEvent(e);
+        if (nearestWay != null) {
+			if (isCtrlDown) {
+				Main.main.getCurrentDataSet().clearSelection(nearestWay);
+				Main.map.mapView.repaint();
+			}
+			else {
+				int maxInstances = parentPlugin.currentCommand.parameters.get(parentPlugin.currentCommand.currentParameterNum).maxInstances;
+				switch (maxInstances) {
+				case 0:
+					Main.main.getCurrentDataSet().addSelected(nearestWay);
+					Main.map.mapView.repaint();
+					break;
+				case 1:
+					Main.main.getCurrentDataSet().addSelected(nearestWay);
+					Main.map.mapView.repaint();
+					parentPlugin.loadParameter(nearestWay, true);
+					exitMode();
+					break;
+				default:
+					if (Main.main.getCurrentDataSet().getSelected().size() < maxInstances) {
+						Main.main.getCurrentDataSet().addSelected(nearestWay);
+						Main.map.mapView.repaint();
+					}
+					else
+						System.out.println("Maximum instances!");
+				}
+			}
+		}
+        super.mousePressed(e);
+    }
+
+	public void eventDispatched(AWTEvent arg0) {
+		if (!(arg0 instanceof KeyEvent))
+			return;
+		KeyEvent ev = (KeyEvent) arg0;
+        isCtrlDown = (ev.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0;
+        if (ev.getKeyCode() == KeyEvent.VK_ESCAPE && ev.getID() == KeyEvent.KEY_PRESSED) {
+            ev.consume();
+            cancelDrawing();
+        }
+    }
+
+    private void updCursor() {
+        if (mousePos != null) {
+			if (!Main.isDisplayingMapView())
+				return;
+			nearestWay = Main.map.mapView.getNearestWay(mousePos, OsmPrimitive.isUsablePredicate);
+			if (nearestWay != null) {
+				setCursor(cursorActive);
+			}
+			else {
+				setCursor(cursorNormal);
+			}
+		}
+    }
+
+	private void processMouseEvent(MouseEvent e) {
+		if (e != null) { mousePos = e.getPoint(); }
+	}
+
+    private void setCursor(final Cursor c) {
+        if (currentCursor.equals(c))
+            return;
+        try {
+            // We invoke this to prevent strange things from happening
+            EventQueue.invokeLater(new Runnable() {
+                public void run() {
+                    // Don't change cursor when mode has changed already
+                    if (!(Main.map.mapMode instanceof WayAction))
+                        return;
+                    Main.map.mapView.setCursor(c);
+                }
+            });
+            currentCursor = c;
+        } catch (Exception e) {
+        }
+    }
+
+    public void cancelDrawing() {
+        if (Main.map == null || Main.map.mapView == null)
+            return;
+        Main.map.statusLine.setHeading(-1);
+        Main.map.statusLine.setAngle(-1);
+        Main.map.mapView.repaint();
+        updateStatusLine();
+        parentPlugin.endInput();
+    }
+}
Index: /applications/editors/josm/plugins/build.xml
===================================================================
--- /applications/editors/josm/plugins/build.xml	(revision 25036)
+++ /applications/editors/josm/plugins/build.xml	(revision 25037)
@@ -14,4 +14,5 @@
         <ant antfile="build.xml" target="dist" dir="colorscheme"/>
         <ant antfile="build.xml" target="dist" dir="ColumbusCSV"/>
+		<ant antfile="build.xml" target="dist" dir="CommandLine"/>
         <ant antfile="build.xml" target="dist" dir="Create_grid_of_ways"/>
         <ant antfile="build.xml" target="dist" dir="czechaddress"/>
@@ -86,4 +87,5 @@
         <ant antfile="build.xml" target="clean" dir="cadastre-fr"/>
         <ant antfile="build.xml" target="clean" dir="colorscheme"/>
+        <ant antfile="build.xml" target="clean" dir="CommandLine"/>
         <ant antfile="build.xml" target="clean" dir="Create_grid_of_ways"/>
         <ant antfile="build.xml" target="clean" dir="czechaddress"/>
