Index: applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/UtilsPlugin2.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/UtilsPlugin2.java	(revision 29124)
+++ applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/UtilsPlugin2.java	(revision 29226)
@@ -53,4 +53,5 @@
     JMenuItem wiki;
     JMenuItem latlon;
+    JMenuItem pasteExtended;
     
     JMenuItem replaceGeometry;
@@ -88,4 +89,5 @@
         wiki = MainMenu.add(toolsMenu, new OpenPageAction());
         latlon = MainMenu.add(toolsMenu, new LatLonAction());
+        pasteExtended = MainMenu.add(toolsMenu, new PasteTagsExtendedAction());
 
         JMenu selectionMenu = Main.main.menu.addMenu(marktr("Selection"), KeyEvent.VK_N, Main.main.menu.defaultMenuPos, "help");
@@ -126,4 +128,5 @@
         alignWayNodes.setEnabled(enabled);
         splitOnIntersections.setEnabled(enabled);
+        pasteExtended.setEnabled(enabled);
         wiki.setEnabled(enabled);
 
Index: applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/actions/PasteTagsExtendedAction.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/actions/PasteTagsExtendedAction.java	(revision 29226)
+++ applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/actions/PasteTagsExtendedAction.java	(revision 29226)
@@ -0,0 +1,72 @@
+package org.openstreetmap.josm.plugins.utilsplugin2.actions;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.plugins.utilsplugin2.helper.TextTagParser;
+import org.openstreetmap.josm.tools.Shortcut;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trn;
+import org.openstreetmap.josm.tools.Utils;
+
+public class PasteTagsExtendedAction extends JosmAction {
+    public PasteTagsExtendedAction() {
+        super(tr("Paste tags [testing]"), "pastetags", tr("Apply tags parsed from buffer to all selected items.."),
+            Shortcut.registerShortcut("tools:pastetags", tr("Tool: {0}", tr("Paste tags")),
+            KeyEvent.VK_T, Shortcut.CTRL), true); // TODO: shortcut is temporary, will be on Ctrl-Shift-V
+        //putValue("help", ht("/Action/Paste"));
+    }
+    
+    
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();
+
+        if (selection.isEmpty())
+            return;
+        
+        String buf = Utils.getClipboardContent();
+
+        if (buf==null) return;
+        List<Command> commands = new ArrayList<Command>();
+        for (Tag tag: TextTagParser.readTagsFromText(buf)) {
+            commands.add(new ChangePropertyCommand(selection, tag.getKey(), "".equals(tag.getValue())?null:tag.getValue()));
+        }
+        if (!commands.isEmpty()) {
+            String title1 = trn("Pasting {0} tag", "Pasting {0} tags", commands.size(), commands.size());
+            String title2 = trn("to {0} object", "to {0} objects", selection.size(), selection.size());
+            Main.main.undoRedo.add(
+                    new SequenceCommand(
+                            title1 + " " + title2,
+                            commands
+                    ));
+        }
+    }
+    
+    
+    
+    @Override
+    protected void updateEnabledState() {
+        if (getCurrentDataSet() == null) {
+            setEnabled(false);
+        } else {
+            updateEnabledState(getCurrentDataSet().getSelected());
+        }
+    }
+
+    @Override
+    protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
+        setEnabled(selection != null && !selection.isEmpty());
+    }
+}
Index: applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/helper/TextTagParser.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/helper/TextTagParser.java	(revision 29226)
+++ applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/helper/TextTagParser.java	(revision 29226)
@@ -0,0 +1,161 @@
+package org.openstreetmap.josm.plugins.utilsplugin2.helper;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.openstreetmap.josm.data.osm.Tag;
+
+public class TextTagParser {
+
+    int start = 0;
+    boolean keyFound = false;
+    boolean quotesStarted = false;
+    boolean esc = false;
+    StringBuilder s = new StringBuilder(200);
+    int pos;
+    String data;
+    int n;
+    boolean notFound;
+
+    public TextTagParser(String text) {
+        pos = 0;
+        data = text;
+        n = data.length();
+    }
+    
+    /**
+     * Read tags from format, tag1\t val1 \n tag2 \t vat2 
+     * if possible
+     */
+    Collection<Tag> getFormattedTags() {
+         String lines[] = data.split("\n");
+         
+         Pattern p = Pattern.compile("(.*?)\t(.*?)");
+         List<Tag> tags = new ArrayList<Tag>();
+         String k=null, v=null;
+         for (String  line: lines) {
+            if (line.trim().isEmpty()) continue; // skiip empty lines
+            Matcher m = p.matcher(line);
+            if (m.matches()) {
+                 k=m.group(1).trim(); v=m.group(2).trim();
+                 tags.add(new Tag(k,v));
+            } else {
+                tags.clear();
+                break;
+            }
+         }
+         if (!tags.isEmpty()) {
+            return tags;
+        }  else {
+            return null;
+        }
+    }
+
+    /**
+     * Read tags from "Free format"
+     */
+    Collection<Tag> getParsedTags() {
+        String k, v;
+        List<Tag> tags = new ArrayList<Tag>();
+
+        while (true) {
+            skipEmpty();
+            if (pos == n) { 
+               break; 
+            }
+            k = parseString(true);
+            if (pos == n) { 
+               tags.clear();
+               break; 
+            }
+            skipSign();
+            if (pos == n) { 
+                tags.clear();
+                break; 
+            }
+            v = parseString(false);
+            tags.add(new Tag(k, v));
+        }
+        return tags;
+    }
+
+    private String parseString(boolean stopOnEquals) {
+        char c;
+        while (pos < n) {
+            c = data.charAt(pos);
+            if (esc) {
+                esc = false;
+                s.append(c); //  \" \\
+            } else if (c == '\\') {
+                esc = true;
+            } else if (c == '\"' && !quotesStarted) { // opening "
+                if (s.toString().trim().length()>0) { // we had   ||some text"||
+                    s.append(c); // just add ", not open
+                } else {
+                    s.delete(0, s.length()); // forget that empty characthers and start reading "....
+                    quotesStarted = true;
+                }
+            } else if (c == '\"' && quotesStarted) {  // closing "
+                quotesStarted = false;
+                pos++;
+                break;
+            } else if (!quotesStarted && (c=='\n'|| c=='\t'|| c==' ' || c=='\r'
+                  || (c=='=' && stopOnEquals))) {  // stop-symbols
+                pos++;
+                break;
+            } else {
+                if(c>=32) s.append(c);
+            }
+            pos++;
+        }
+
+        String res = s.toString();
+        s.delete(0, s.length());
+        return res.trim();
+    }
+
+    private void skipSign() {
+        char c;
+        boolean signFound = false;;
+        while (pos < n) {
+            c = data.charAt(pos);
+            if (c == '\t' || c == '\n'  || c == ' ') {
+                pos++;
+            } else if (c== '=') {
+                if (signFound) break; // a  =  =qwerty means "a"="=qwerty"
+                signFound = true;
+                pos++;
+            } else {
+                break;
+            }
+        }
+    }
+
+    private void skipEmpty() {
+        char c;
+        while (pos < n) {
+            c = data.charAt(pos);
+            if (c == '\t' || c == '\n' || c == '\r' || c == ' ' ) {
+                pos++;
+            } else {
+                break;
+            }
+        }
+    }
+
+    public static Collection<Tag> readTagsFromText(String buf) {
+        TextTagParser parser = new TextTagParser(buf);
+        Collection<Tag> tags;
+        tags = parser.getFormattedTags(); // try "tag\tvalue\n" format
+        if (tags == null) {
+            tags = parser.getParsedTags();
+        }
+        return tags;
+
+    }
+
+
+    
+}
