Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/ConfigKeys.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/ConfigKeys.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/ConfigKeys.java	(revision 19282)
@@ -40,3 +40,4 @@
     public static final String OSB_NEW_HISTORY = "osb.new.history";
     public static final String OSB_NICKNAME = "osb.nickname";
+    public static final String OSB_API_OFFLINE = "osb.api.offline";
 }
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbDownloadLoop.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbDownloadLoop.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbDownloadLoop.java	(revision 19282)
@@ -78,5 +78,5 @@
 
                 // auto download if configured
-                if( Main.pref.getBoolean(ConfigKeys.OSB_AUTO_DOWNLOAD) && 
+                if( Main.pref.getBoolean(ConfigKeys.OSB_AUTO_DOWNLOAD) && !Main.pref.getBoolean(ConfigKeys.OSB_API_OFFLINE) && 
                         plugin != null && plugin.getDialog() != null && plugin.getDialog().isDialogShowing() ) {
                     if(countdown < 0) {
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbLayer.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbLayer.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbLayer.java	(revision 19282)
@@ -58,5 +58,5 @@
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.plugins.osb.gui.action.OsbAction;
+import org.openstreetmap.josm.plugins.osb.gui.OsbDialog;
 import org.openstreetmap.josm.plugins.osb.gui.action.PopupFactory;
 import org.openstreetmap.josm.tools.ColorHelper;
@@ -72,8 +72,11 @@
     private static ImageIcon iconError = OsbPlugin.loadIcon("icon_error16.png");
     private static ImageIcon iconValid = OsbPlugin.loadIcon("icon_valid16.png");
-
-    public OsbLayer(DataSet dataSet, String name) {
+    
+    private OsbDialog dialog;
+
+    public OsbLayer(DataSet dataSet, String name, OsbDialog dialog) {
         super(name);
         this.data = dataSet;
+        this.dialog = dialog;
         DataSet.selListeners.add(new SelectionChangedListener() {
             public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
@@ -234,5 +237,5 @@
                 Node n = getNearestNode(e.getPoint());
                 if(data.getNodes().contains(n)) {
-                    data.setSelected(n);
+                    dialog.setSelectedNode(n);
                 }
             }
@@ -252,7 +255,6 @@
             if(Main.map.mapView.getActiveLayer() == this) {
                 Node n = getNearestNode(e.getPoint());
-                OsbAction.setSelectedNode(n);
                 if(data.getNodes().contains(n)) {
-                    PopupFactory.createPopup(n).show(e.getComponent(), e.getX(), e.getY());
+                    PopupFactory.createPopup(n, dialog).show(e.getComponent(), e.getX(), e.getY());
                 }
             }
@@ -263,3 +265,7 @@
 
     public void mouseExited(MouseEvent e) {}
+    
+    public DataSet getDataSet() {
+        return data;
+    }
 }
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbPlugin.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbPlugin.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/OsbPlugin.java	(revision 19282)
@@ -156,20 +156,23 @@
         }
 
-        try {
-            // download the data
-            download.execute(dataSet, bounds);
-
-            // display the parsed data
-            if(!dataSet.getNodes().isEmpty() && dialog.isDialogShowing()) {
-                // if the map layer has been closed, while we are requesting the osb db,
-                // we don't have to update the gui, because the user is not interested
-                // in this area anymore
-                if(Main.map != null && Main.map.mapView != null) {
-                    updateGui();
+        // download data for the new bounds, if the plugin is not in offline mode
+        if(!Main.pref.getBoolean(ConfigKeys.OSB_API_OFFLINE)) {
+            try {
+                // download the data
+                download.execute(dataSet, bounds);
+    
+                // display the parsed data
+                if(!dataSet.getNodes().isEmpty() && dialog.isDialogShowing()) {
+                    // if the map layer has been closed, while we are requesting the osb db,
+                    // we don't have to update the gui, because the user is not interested
+                    // in this area anymore
+                    if(Main.map != null && Main.map.mapView != null) {
+                        updateGui();
+                    }
                 }
+            } catch (Exception e) {
+                JOptionPane.showMessageDialog(Main.parent, e.getMessage());
+                e.printStackTrace();
             }
-        } catch (Exception e) {
-            JOptionPane.showMessageDialog(Main.parent, e.getMessage());
-            e.printStackTrace();
         }
     }
@@ -188,5 +191,5 @@
     private void updateLayer(DataSet osbData) {
         if(layer == null) {
-            layer = new OsbLayer(osbData, "OpenStreetBugs");
+            layer = new OsbLayer(osbData, "OpenStreetBugs", dialog);
             Main.main.addLayer(layer);
         }
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbBugListCellRenderer.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbBugListCellRenderer.java	(revision 19282)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbBugListCellRenderer.java	(revision 19282)
@@ -0,0 +1,84 @@
+/* Copyright (c) 2008, Henrik Niehaus
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openstreetmap.josm.plugins.osb.gui;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.UIManager;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.plugins.osb.OsbPlugin;
+
+public class OsbBugListCellRenderer implements ListCellRenderer {
+
+    private Color background = Color.WHITE;
+    private Color altBackground = new Color(250, 250, 220);
+
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+            boolean cellHasFocus) {
+
+        JLabel label = new JLabel();
+        label.setOpaque(true);
+
+        if(isSelected) {
+            label.setForeground(UIManager.getColor("List.selectionForeground"));
+            label.setBackground(UIManager.getColor("List.selectionBackground"));
+        } else {
+            label.setForeground(UIManager.getColor("List.foreground"));
+            label.setBackground(index % 2 == 0 ? background : altBackground);
+        }
+
+        OsbListItem item = (OsbListItem) value;
+        Node n = item.getNode();
+        Icon icon = null;
+        if("0".equals(n.get("state"))) {
+            icon = OsbPlugin.loadIcon("icon_error16.png");
+        } else if("1".equals(n.get("state"))) {
+            icon = OsbPlugin.loadIcon("icon_valid16.png");
+        }
+        label.setIcon(icon);
+        String text = n.get("note");
+        if(text.indexOf("<hr />") > 0) {
+            text = text.substring(0, text.indexOf("<hr />"));
+        }
+        label.setText("<html>" + text + "</html>");
+
+        Dimension d = label.getPreferredSize();
+        d.height += 10;
+        label.setPreferredSize(d);
+
+        return label;
+    }
+
+}
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbDialog.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbDialog.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbDialog.java	(revision 19282)
@@ -38,5 +38,4 @@
 import java.awt.event.MouseListener;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -50,4 +49,5 @@
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
 import javax.swing.JToggleButton;
 import javax.swing.ListSelectionModel;
@@ -57,5 +57,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
@@ -69,10 +68,12 @@
 import org.openstreetmap.josm.plugins.osb.OsbObserver;
 import org.openstreetmap.josm.plugins.osb.OsbPlugin;
+import org.openstreetmap.josm.plugins.osb.gui.action.ActionQueue;
 import org.openstreetmap.josm.plugins.osb.gui.action.AddCommentAction;
 import org.openstreetmap.josm.plugins.osb.gui.action.CloseIssueAction;
-import org.openstreetmap.josm.plugins.osb.gui.action.NewIssueAction;
 import org.openstreetmap.josm.plugins.osb.gui.action.OsbAction;
 import org.openstreetmap.josm.plugins.osb.gui.action.OsbActionObserver;
+import org.openstreetmap.josm.plugins.osb.gui.action.PointToNewIssueAction;
 import org.openstreetmap.josm.plugins.osb.gui.action.PopupFactory;
+import org.openstreetmap.josm.plugins.osb.gui.action.ToggleConnectionModeAction;
 import org.openstreetmap.josm.tools.OsmUrlToBounds;
 import org.openstreetmap.josm.tools.Shortcut;
@@ -82,13 +83,19 @@
 
     private static final long serialVersionUID = 1L;
-    private DefaultListModel model;
-    private JList list;
+    private JPanel bugListPanel, queuePanel;
+    private DefaultListModel bugListModel;
+    private JList bugList;
+    private JList queueList;
     private OsbPlugin osbPlugin;
     private boolean fireSelectionChanged = true;
     private JButton refresh;
-    private JButton addComment = new JButton(new AddCommentAction());
-    private JButton closeIssue = new JButton(new CloseIssueAction());
+    private JButton addComment;
+    private JButton closeIssue;
+    private JButton processQueue = new JButton(tr("Process queue"));
     private JToggleButton newIssue = new JToggleButton();
-
+    private JToggleButton toggleConnectionMode;
+    private JTabbedPane tabbedPane = new JTabbedPane();
+    private boolean queuePanelVisible = false;
+    
     private boolean buttonLabels = Main.pref.getBoolean(ConfigKeys.OSB_BUTTON_LABELS);
 
@@ -100,22 +107,23 @@
 
         osbPlugin = plugin;
-
-        model = new DefaultListModel();
-        list = new JList(model);
-        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        list.addListSelectionListener(this);
-        list.addMouseListener(this);
-        list.setCellRenderer(new OsbListCellRenderer());
-        add(new JScrollPane(list), BorderLayout.CENTER);
-
+        bugListPanel = new JPanel(new BorderLayout());
+        bugListPanel.setName(tr("Bug list"));
+        add(bugListPanel, BorderLayout.CENTER);
+
+        bugListModel = new DefaultListModel();
+        bugList = new JList(bugListModel);
+        bugList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        bugList.addListSelectionListener(this);
+        bugList.addMouseListener(this);
+        bugList.setCellRenderer(new OsbBugListCellRenderer());
+        bugListPanel.add(new JScrollPane(bugList), BorderLayout.CENTER);
+        
         // create dialog buttons
-        GridLayout layout = buttonLabels ? new GridLayout(2, 2) : new GridLayout(1, 4);
+        GridLayout layout = buttonLabels ? new GridLayout(3, 2) : new GridLayout(1, 5);
         JPanel buttonPanel = new JPanel(layout);
-        add(buttonPanel, BorderLayout.SOUTH);
         refresh = new JButton(tr("Refresh"));
         refresh.setToolTipText(tr("Refresh"));
         refresh.setIcon(OsbPlugin.loadIcon("view-refresh22.png"));
         refresh.addActionListener(new ActionListener() {
-
             public void actionPerformed(ActionEvent e) {
                 int zoom = OsmUrlToBounds.getZoom(Main.map.mapView.getRealBounds());
@@ -131,22 +139,67 @@
             }
         });
-
+        bugListPanel.add(buttonPanel, BorderLayout.SOUTH);
+        Action toggleConnectionModeAction = new ToggleConnectionModeAction(this, osbPlugin);
+        toggleConnectionMode = new JToggleButton(toggleConnectionModeAction);
+        toggleConnectionMode.setToolTipText(ToggleConnectionModeAction.MSG_OFFLINE);
+        boolean offline = Main.pref.getBoolean(ConfigKeys.OSB_API_OFFLINE);
+        toggleConnectionMode.setIcon(OsbPlugin.loadIcon("online22.png"));
+        toggleConnectionMode.setSelectedIcon(OsbPlugin.loadIcon("offline22.png"));
+        if(offline) {
+            // inverse the current value and then do a click, so that
+            // we are offline and the gui represents the offline state, too
+            Main.pref.put(ConfigKeys.OSB_API_OFFLINE, false);
+            toggleConnectionMode.doClick();
+        }
+        
+
+        AddCommentAction addCommentAction = new AddCommentAction(this);
+        addComment = new JButton(addCommentAction);
         addComment.setEnabled(false);
         addComment.setToolTipText((String) addComment.getAction().getValue(Action.NAME));
         addComment.setIcon(OsbPlugin.loadIcon("add_comment22.png"));
+        CloseIssueAction closeIssueAction = new CloseIssueAction(this);
+        closeIssue = new JButton(closeIssueAction);
         closeIssue.setEnabled(false);
         closeIssue.setToolTipText((String) closeIssue.getAction().getValue(Action.NAME));
         closeIssue.setIcon(OsbPlugin.loadIcon("icon_valid22.png"));
-        NewIssueAction nia = new NewIssueAction(newIssue, osbPlugin);
+        PointToNewIssueAction nia = new PointToNewIssueAction(newIssue, osbPlugin);
         newIssue.setAction(nia);
         newIssue.setToolTipText((String) newIssue.getAction().getValue(Action.NAME));
         newIssue.setIcon(OsbPlugin.loadIcon("icon_error_add22.png"));
 
+        buttonPanel.add(toggleConnectionMode);
         buttonPanel.add(refresh);
         buttonPanel.add(newIssue);
         buttonPanel.add(addComment);
         buttonPanel.add(closeIssue);
+        
+        queuePanel = new JPanel(new BorderLayout());
+        queuePanel.setName(tr("Queue"));
+        queueList = new JList(ActionQueue.getInstance());
+        queueList.setCellRenderer(new OsbQueueListCellRenderer());
+        queuePanel.add(new JScrollPane(queueList), BorderLayout.CENTER);
+        queuePanel.add(processQueue, BorderLayout.SOUTH);
+        processQueue.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                Main.pref.put(ConfigKeys.OSB_API_OFFLINE, "false");
+                setConnectionMode(false);
+                try {
+                    ActionQueue.getInstance().processQueue();
+    
+                    // refresh, if the api is enabled
+                    if(!Main.pref.getBoolean(ConfigKeys.OSB_API_DISABLED)) {
+                        plugin.updateData();
+                    }
+                } catch (Exception e1) {
+                    System.err.println("Couldn't process action queue");
+                    e1.printStackTrace();
+                }
+            }
+        });
+        tabbedPane.add(queuePanel);
 
         if (buttonLabels) {
+            toggleConnectionMode.setHorizontalAlignment(SwingConstants.LEFT);
             refresh.setHorizontalAlignment(SwingConstants.LEFT);
             addComment.setHorizontalAlignment(SwingConstants.LEFT);
@@ -154,4 +207,5 @@
             newIssue.setHorizontalAlignment(SwingConstants.LEFT);
         } else {
+            toggleConnectionMode.setText(null);
             refresh.setText(null);
             addComment.setText(null);
@@ -160,50 +214,43 @@
         }
 
-        // add a selection listener to the data
-        DataSet.selListeners.add(new SelectionChangedListener() {
-            public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-                fireSelectionChanged = false;
-                list.clearSelection();
-                for (OsmPrimitive osmPrimitive : newSelection) {
-                    for (int i = 0; i < model.getSize(); i++) {
-                        OsbListItem item = (OsbListItem) model.get(i);
-                        if (item.getNode() == osmPrimitive) {
-                            list.addSelectionInterval(i, i);
-                        }
-                    }
-                }
-                fireSelectionChanged = true;
-            }
-        });
-
-        AddCommentAction.addActionObserver(this);
-        CloseIssueAction.addActionObserver(this);
+        addCommentAction.addActionObserver(this);
+        closeIssueAction.addActionObserver(this);
+        setConnectionMode(offline);
     }
 
     public synchronized void update(final DataSet dataset) {
-        Node lastNode = OsbAction.getSelectedNode();
-        model = new DefaultListModel();
+        // store the last selection
+        OsbListItem listItem = (OsbListItem) bugList.getSelectedValue();
+        Node lastNode = null;
+        if(listItem != null) {
+            lastNode = listItem.getNode();
+        }
+        
+        // create a new list model
+        bugListModel = new DefaultListModel();
         List<Node> sortedList = new ArrayList<Node>(dataset.getNodes());
         Collections.sort(sortedList, new BugComparator());
-
         for (Node node : sortedList) {
             if (node.isUsable()) {
-                model.addElement(new OsbListItem(node));
-            }
-        }
-        list.setModel(model);
-        list.setSelectedValue(new OsbListItem(lastNode), true);
+                bugListModel.addElement(new OsbListItem(node));
+            }
+        }
+        bugList.setModel(bugListModel);
+        
+        // restore the last selection 
+        if(lastNode != null) {
+            bugList.setSelectedValue(new OsbListItem(lastNode), true);
+        }
     }
 
     public void valueChanged(ListSelectionEvent e) {
-        if (list.getSelectedValues().length == 0) {
+        if (bugList.getSelectedValues().length == 0) {
             addComment.setEnabled(false);
             closeIssue.setEnabled(false);
-            OsbAction.setSelectedNode(null);
             return;
         }
 
         List<OsmPrimitive> selected = new ArrayList<OsmPrimitive>();
-        for (Object listItem : list.getSelectedValues()) {
+        for (Object listItem : bugList.getSelectedValues()) {
             Node node = ((OsbListItem) listItem).getNode();
             selected.add(node);
@@ -217,5 +264,4 @@
             }
 
-            OsbAction.setSelectedNode(node);
             scrollToSelected(node);
         }
@@ -224,5 +270,5 @@
         // If so, a temporary DataSet is created because it's the simplest way
         // to fire all necessary events so OSB updates its popups.
-        DataSet ds = Main.main.getCurrentDataSet();
+        DataSet ds = osbPlugin.getLayer().getDataSet();
         if (fireSelectionChanged) {
             if(ds == null)
@@ -233,9 +279,9 @@
 
     private void scrollToSelected(Node node) {
-        for (int i = 0; i < model.getSize(); i++) {
-            Node current = ((OsbListItem) model.get(i)).getNode();
+        for (int i = 0; i < bugListModel.getSize(); i++) {
+            Node current = ((OsbListItem) bugListModel.get(i)).getNode();
             if (current.getId()== node.getId()) {
-                list.scrollRectToVisible(list.getCellBounds(i, i));
-                list.setSelectedIndex(i);
+                bugList.scrollRectToVisible(bugList.getCellBounds(i, i));
+                bugList.setSelectedIndex(i);
                 return;
             }
@@ -255,5 +301,5 @@
     public void layerRemoved(Layer oldLayer) {
         if (oldLayer == osbPlugin.getLayer()) {
-            model.removeAllElements();
+            bugListModel.removeAllElements();
         }
     }
@@ -269,6 +315,5 @@
     public void mouseClicked(MouseEvent e) {
         if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
-            OsbListItem item = (OsbListItem) list.getSelectedValue();
-            zoomToNode(item.getNode());
+            zoomToNode(getSelectedNode());
         }
     }
@@ -284,9 +329,7 @@
     private void mayTriggerPopup(MouseEvent e) {
         if (e.isPopupTrigger()) {
-            int selectedRow = list.locationToIndex(e.getPoint());
-            list.setSelectedIndex(selectedRow);
-            Node n = ((OsbListItem) list.getSelectedValue()).getNode();
-            OsbAction.setSelectedNode(n);
-            PopupFactory.createPopup(n).show(e.getComponent(), e.getX(), e.getY());
+            int selectedRow = bugList.locationToIndex(e.getPoint());
+            bugList.setSelectedIndex(selectedRow);
+            PopupFactory.createPopup(getSelectedNode(), this).show(e.getComponent(), e.getX(), e.getY());
         }
     }
@@ -334,3 +377,40 @@
         super.showDialog();
     }
+    
+    public void showQueuePanel() {
+        if(!queuePanelVisible) {
+            remove(bugListPanel);
+            tabbedPane.add(bugListPanel, 0);
+            add(tabbedPane, BorderLayout.CENTER);
+            tabbedPane.setSelectedIndex(0);
+            queuePanelVisible = true;
+            invalidate();
+            repaint();
+        }
+    }
+    
+    public void hideQueuePanel() {
+        if(queuePanelVisible) {
+            tabbedPane.remove(bugListPanel);
+            remove(tabbedPane);
+            add(bugListPanel, BorderLayout.CENTER);
+            queuePanelVisible = false;
+            invalidate();
+            repaint();
+        }
+    }
+    
+    public Node getSelectedNode() {
+        return ((OsbListItem)bugList.getSelectedValue()).getNode();
+    }
+    
+    public void setSelectedNode(Node node) {
+        bugList.setSelectedValue(new OsbListItem(node), true);
+    }
+    
+    public void setConnectionMode(boolean offline) {
+        refresh.setEnabled(!offline);
+        setTitle("OpenStreetBugs (" + (offline ? "offline" : "online") + ")");
+        toggleConnectionMode.setSelected(offline);
+    }
 }
Index: plications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbListCellRenderer.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbListCellRenderer.java	(revision 19281)
+++ 	(revision )
@@ -1,84 +1,0 @@
-/* Copyright (c) 2008, Henrik Niehaus
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its
- *    contributors may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-package org.openstreetmap.josm.plugins.osb.gui;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-
-import javax.swing.Icon;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.ListCellRenderer;
-import javax.swing.UIManager;
-
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.plugins.osb.OsbPlugin;
-
-public class OsbListCellRenderer implements ListCellRenderer {
-
-    private Color background = Color.WHITE;
-    private Color altBackground = new Color(250, 250, 220);
-
-    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
-            boolean cellHasFocus) {
-
-        JLabel label = new JLabel();
-        label.setOpaque(true);
-
-        if(isSelected) {
-            label.setForeground(UIManager.getColor("List.selectionForeground"));
-            label.setBackground(UIManager.getColor("List.selectionBackground"));
-        } else {
-            label.setForeground(UIManager.getColor("List.foreground"));
-            label.setBackground(index % 2 == 0 ? background : altBackground);
-        }
-
-        OsbListItem item = (OsbListItem) value;
-        Node n = item.getNode();
-        Icon icon = null;
-        if("0".equals(n.get("state"))) {
-            icon = OsbPlugin.loadIcon("icon_error16.png");
-        } else if("1".equals(n.get("state"))) {
-            icon = OsbPlugin.loadIcon("icon_valid16.png");
-        }
-        label.setIcon(icon);
-        String text = n.get("note");
-        if(text.indexOf("<hr />") > 0) {
-            text = text.substring(0, text.indexOf("<hr />"));
-        }
-        label.setText("<html>" + text + "</html>");
-
-        Dimension d = label.getPreferredSize();
-        d.height += 10;
-        label.setPreferredSize(d);
-
-        return label;
-    }
-
-}
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbQueueListCellRenderer.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbQueueListCellRenderer.java	(revision 19282)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/OsbQueueListCellRenderer.java	(revision 19282)
@@ -0,0 +1,88 @@
+/* Copyright (c) 2008, Henrik Niehaus
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openstreetmap.josm.plugins.osb.gui;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.UIManager;
+
+import org.openstreetmap.josm.plugins.osb.OsbPlugin;
+import org.openstreetmap.josm.plugins.osb.gui.action.AddCommentAction;
+import org.openstreetmap.josm.plugins.osb.gui.action.CloseIssueAction;
+import org.openstreetmap.josm.plugins.osb.gui.action.NewIssueAction;
+import org.openstreetmap.josm.plugins.osb.gui.action.OsbAction;
+
+public class OsbQueueListCellRenderer implements ListCellRenderer {
+
+    private Color background = Color.WHITE;
+    private Color altBackground = new Color(250, 250, 220);
+
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+            boolean cellHasFocus) {
+
+        JLabel label = new JLabel();
+        label.setOpaque(true);
+
+        if(isSelected) {
+            label.setForeground(UIManager.getColor("List.selectionForeground"));
+            label.setBackground(UIManager.getColor("List.selectionBackground"));
+        } else {
+            label.setForeground(UIManager.getColor("List.foreground"));
+            label.setBackground(index % 2 == 0 ? background : altBackground);
+        }
+
+        OsbAction action = (OsbAction) value;
+        Icon icon = null;
+        if(action instanceof NewIssueAction) {
+            icon = OsbPlugin.loadIcon("icon_error_add16.png");
+        } else if(action instanceof AddCommentAction) {
+            icon = OsbPlugin.loadIcon("add_comment16.png");
+        } else if(action instanceof CloseIssueAction) {
+            icon = OsbPlugin.loadIcon("icon_valid16.png");
+        }
+        label.setIcon(icon);
+        String text = action.toString();
+        if(text.indexOf("<hr />") > 0) {
+            text = text.substring(0, text.indexOf("<hr />"));
+        }
+        label.setText("<html>" + text + "</html>");
+
+        Dimension d = label.getPreferredSize();
+        d.height += 10;
+        label.setPreferredSize(d);
+
+        return label;
+    }
+
+}
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/ActionQueue.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/ActionQueue.java	(revision 19282)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/ActionQueue.java	(revision 19282)
@@ -0,0 +1,72 @@
+package org.openstreetmap.josm.plugins.osb.gui.action;
+
+import java.util.LinkedList;
+
+import javax.swing.AbstractListModel;
+
+public class ActionQueue extends AbstractListModel {
+
+    private static ActionQueue instance;
+
+    private LinkedList<OsbAction> queue = new LinkedList<OsbAction>();
+
+    private ActionQueue() {}
+
+    public static synchronized ActionQueue getInstance() {
+        if(instance == null) {
+            instance = new ActionQueue();
+        }
+        return instance;
+    }
+
+    public boolean offer(OsbAction e) {
+        boolean result = queue.offer(e);
+        fireIntervalAdded(this, queue.size()-1, queue.size()-1);
+        return result;
+    }
+
+    public OsbAction peek() {
+        return queue.peek();
+    }
+
+    public OsbAction poll() {
+        OsbAction action = queue.poll();
+        fireIntervalRemoved(this, 0, 0);
+        return action;
+    }
+
+    public boolean remove(Object o) {
+        int index = queue.indexOf(o);
+        if(index >= 0) {
+            fireIntervalRemoved(this, index, index);
+        }
+        return queue.remove(o);
+    }
+
+    public void processQueue() throws Exception {
+        while(!queue.isEmpty()) {
+            // get the first action, but leave it in queue
+            OsbAction action = queue.peek();
+
+            // execute the action
+            action.execute();
+            
+            // notify observers
+            for (OsbActionObserver obs : action.getActionObservers()) {
+                obs.actionPerformed(action);
+            }
+
+            // if no exception has been thrown, remove the action from the queue
+            queue.remove();
+            fireIntervalRemoved(this, 0, 0);
+        }
+    }
+
+    public Object getElementAt(int index) {
+        return queue.get(index);
+    }
+
+    public int getSize() {
+        return queue.size();
+    }
+}
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/AddCommentAction.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/AddCommentAction.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/AddCommentAction.java	(revision 19282)
@@ -31,12 +31,15 @@
 
 import java.awt.event.ActionEvent;
+import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.gui.widgets.HistoryChangedListener;
 import org.openstreetmap.josm.plugins.osb.ConfigKeys;
 import org.openstreetmap.josm.plugins.osb.OsbPlugin;
 import org.openstreetmap.josm.plugins.osb.api.EditAction;
+import org.openstreetmap.josm.plugins.osb.gui.OsbDialog;
 import org.openstreetmap.josm.plugins.osb.gui.dialogs.TextInputDialog;
 
@@ -46,7 +49,11 @@
 
     private EditAction editAction = new EditAction();
+    
+    private String comment;
+    
+    private Node node;
 
-    public AddCommentAction() {
-        super(tr("Add a comment"));
+    public AddCommentAction(OsbDialog dialog) {
+        super(tr("Add a comment"), dialog);
     }
 
@@ -59,5 +66,6 @@
             }
         };
-        String comment = TextInputDialog.showDialog(
+        node = dialog.getSelectedNode();
+        comment = TextInputDialog.showDialog(
                 Main.map,
                 tr("Add a comment"),
@@ -65,9 +73,28 @@
                 OsbPlugin.loadIcon("add_comment22.png"),
                 history, l);
-
-        if(comment != null) {
-            comment = addMesgInfo(comment);
-            editAction.execute(getSelectedNode(), comment);
+        
+        if(comment == null) {
+            cancelled = true;
         }
     }
+
+    @Override
+    public void execute() throws IOException {
+        comment = addMesgInfo(comment);
+        editAction.execute(node, comment);
+    }
+    
+    @Override
+    public String toString() {
+        return tr("Comment: " + node.get("note") + " - " + comment);
+    }
+    
+    @Override
+    public AddCommentAction clone() {
+        AddCommentAction action = new AddCommentAction(dialog);
+        action.comment = comment;
+        action.cancelled = cancelled;
+        action.node = node;
+        return action;
+    }
 }
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/CloseIssueAction.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/CloseIssueAction.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/CloseIssueAction.java	(revision 19282)
@@ -31,8 +31,10 @@
 
 import java.awt.event.ActionEvent;
+import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.gui.widgets.HistoryChangedListener;
 import org.openstreetmap.josm.plugins.osb.ConfigKeys;
@@ -40,4 +42,5 @@
 import org.openstreetmap.josm.plugins.osb.api.CloseAction;
 import org.openstreetmap.josm.plugins.osb.api.EditAction;
+import org.openstreetmap.josm.plugins.osb.gui.OsbDialog;
 import org.openstreetmap.josm.plugins.osb.gui.dialogs.TextInputDialog;
 
@@ -48,7 +51,11 @@
     private CloseAction closeAction = new CloseAction();
     private EditAction commentAction = new EditAction();
+    
+    private String comment;
+    
+    private Node node;
 
-    public CloseIssueAction() {
-        super(tr("Mark as done"));
+    public CloseIssueAction(OsbDialog dialog) {
+        super(tr("Mark as done"), dialog);
     }
 
@@ -61,17 +68,38 @@
             }
         };
-        String comment = TextInputDialog.showDialog(Main.map,
+        node = dialog.getSelectedNode();
+        comment = TextInputDialog.showDialog(Main.map,
                 tr("Really close?"),
                 tr("<html>Really mark this issue as ''done''?<br><br>You may add an optional comment:</html>"),
                 OsbPlugin.loadIcon("icon_valid22.png"),
                 history, l);
+        
+        if(comment == null) {
+            cancelled = true;
+        }
 
-        if(comment != null) {
-            if(comment.length() > 0) {
-                comment = addMesgInfo(comment);
-                commentAction.execute(getSelectedNode(), comment);
-            }
-            closeAction.execute(getSelectedNode());
+    }
+
+    @Override
+    public void execute() throws IOException {
+        if (comment.length() > 0) {
+            comment = addMesgInfo(comment);
+            commentAction.execute(node, comment);
         }
+        closeAction.execute(node);
+    }
+    
+    @Override
+    public String toString() {
+        return tr("Close: " + node.get("note") + " - Comment: " + comment);
+    }
+    
+    @Override
+    public CloseIssueAction clone() {
+        CloseIssueAction action = new CloseIssueAction(dialog);
+        action.cancelled = cancelled;
+        action.comment = comment;
+        action.node = node;
+        return action;
     }
 }
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/NewIssueAction.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/NewIssueAction.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/NewIssueAction.java	(revision 19282)
@@ -30,14 +30,9 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Cursor;
+import java.awt.Point;
 import java.awt.event.ActionEvent;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
 import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
-
-import javax.swing.JOptionPane;
-import javax.swing.JToggleButton;
 
 import org.openstreetmap.josm.Main;
@@ -49,52 +44,24 @@
 import org.openstreetmap.josm.plugins.osb.gui.dialogs.TextInputDialog;
 
-public class NewIssueAction extends OsbAction implements MouseListener {
+public class NewIssueAction extends OsbAction {
 
     private static final long serialVersionUID = 1L;
 
-    private NewAction newAction = new NewAction();
-
-    private JToggleButton button;
-
     private OsbPlugin plugin;
 
-    private Cursor previousCursor;
-
-    public NewIssueAction(JToggleButton button, OsbPlugin plugin) {
-        super(tr("New issue"));
-        this.button = button;
+    private String result;
+    
+    private Point p;
+    
+    private NewAction newAction = new NewAction();
+    
+    public NewIssueAction(OsbPlugin plugin, Point p) {
+        super(tr("New issue"), plugin.getDialog());
         this.plugin = plugin;
+        this.p = p;
     }
 
     @Override
-    protected void doActionPerformed(ActionEvent e) throws IOException {
-        if(button.isSelected()) {
-            previousCursor = Main.map.mapView.getCursor();
-            Main.map.mapView.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
-            Main.map.mapView.addMouseListener(this);
-        } else {
-            reset();
-        }
-    }
-
-    private void reset() {
-        Main.map.mapView.setCursor(previousCursor);
-        Main.map.mapView.removeMouseListener(this);
-        button.setSelected(false);
-    }
-
-    public void mouseClicked(MouseEvent e) {
-        addNewIssue(e);
-    }
-
-    public void mouseEntered(MouseEvent e) {}
-
-    public void mouseExited(MouseEvent e) {}
-
-    public void mousePressed(MouseEvent e) {
-        addNewIssue(e);
-    }
-
-    private void addNewIssue(MouseEvent e) {
+    protected void doActionPerformed(ActionEvent e) throws IOException, InterruptedException {
         List<String> history = new LinkedList<String>(Main.pref.getCollection(ConfigKeys.OSB_NEW_HISTORY, new LinkedList<String>()));
         HistoryChangedListener l = new HistoryChangedListener() {
@@ -103,5 +70,6 @@
             }
         };
-        String result = TextInputDialog.showDialog(
+
+        result = TextInputDialog.showDialog(
                 Main.map,
                 tr("Create issue"),
@@ -109,27 +77,36 @@
                 OsbPlugin.loadIcon("icon_error_add22.png"),
                 history, l);
+        
+        if(result == null) {
+            cancelled = true;
+        }
+    }
 
-        if(result != null && result.length() > 0) {
-            try {
-                result = addMesgInfo(result);
-                Node n = newAction.execute(e.getPoint(), result);
-                plugin.getDataSet().addPrimitive(n);
-                if(Main.pref.getBoolean(ConfigKeys.OSB_API_DISABLED)) {
-                    plugin.updateGui();
-                } else {
-                    plugin.updateData();
-                }
-            } catch (Exception e1) {
-                e1.printStackTrace();
-                JOptionPane.showMessageDialog(Main.parent,
-                        tr("An error occurred: {0}", new Object[] {result}),
-                        tr("Error"),
-                        JOptionPane.ERROR_MESSAGE);
+    @Override
+    public void execute() throws IOException {
+        if (result.length() > 0) {
+            result = addMesgInfo(result);
+            Node n = newAction.execute(p, result);
+            plugin.getDataSet().addPrimitive(n);
+            if (Main.pref.getBoolean(ConfigKeys.OSB_API_DISABLED)) {
+                plugin.updateGui();
+            } else {
+                plugin.updateData();
             }
         }
-
-        reset();
     }
-
-    public void mouseReleased(MouseEvent e) {}
+    
+    @Override
+    public String toString() {
+        return tr("Create: " + result);
+    }
+    
+    @Override
+    public OsbAction clone() {
+        NewIssueAction action = new NewIssueAction(plugin, p);
+        action.cancelled = cancelled;
+        action.p = p;
+        action.result = result;
+        return action;
+    }
 }
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/OsbAction.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/OsbAction.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/OsbAction.java	(revision 19282)
@@ -41,6 +41,6 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.plugins.osb.ConfigKeys;
+import org.openstreetmap.josm.plugins.osb.gui.OsbDialog;
 
 public abstract class OsbAction extends AbstractAction {
@@ -48,25 +48,29 @@
     private static final long serialVersionUID = 1L;
 
-    private static List<OsbActionObserver> observers = new ArrayList<OsbActionObserver>();
+    private List<OsbActionObserver> observers = new ArrayList<OsbActionObserver>();
+    
+    protected OsbDialog dialog;
+    
+    protected boolean cancelled = false;
 
-    private static Node selectedNode;
-
-    public OsbAction(String name) {
+    public OsbAction(String name, OsbDialog osbDialog) {
         super(name);
-    }
-
-    public static Node getSelectedNode() {
-        return selectedNode;
-    }
-
-    public static void setSelectedNode(Node selectedNode) {
-        OsbAction.selectedNode = selectedNode;
+        this.dialog = osbDialog;
     }
 
     public void actionPerformed(ActionEvent e) {
+        cancelled = false;
         try {
             doActionPerformed(e);
-            for (OsbActionObserver obs : observers) {
-                obs.actionPerformed(this);
+            if(!cancelled) {
+                if (!Main.pref.getBoolean(ConfigKeys.OSB_API_OFFLINE)) {
+                    execute();
+                    for (OsbActionObserver obs : observers) {
+                        obs.actionPerformed(this);
+                    }
+                } else {
+                    OsbAction action = clone();
+                    ActionQueue.getInstance().offer(action);
+                }
             }
         } catch (Exception e1) {
@@ -78,9 +82,9 @@
     protected abstract void doActionPerformed(ActionEvent e) throws Exception;
 
-    public static void addActionObserver(OsbActionObserver obs) {
+    public void addActionObserver(OsbActionObserver obs) {
         observers.add(obs);
     }
 
-    public static void removeActionObserver(OsbActionObserver obs) {
+    public void removeActionObserver(OsbActionObserver obs) {
         observers.remove(obs);
     }
@@ -114,3 +118,11 @@
         return msg;
     }
+    
+    public List<OsbActionObserver> getActionObservers() {
+        return observers;
+    }
+    
+    public abstract void execute() throws Exception;
+    
+    public abstract OsbAction clone();
 }
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/PointToNewIssueAction.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/PointToNewIssueAction.java	(revision 19282)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/PointToNewIssueAction.java	(revision 19282)
@@ -0,0 +1,91 @@
+/* Copyright (c) 2008, Henrik Niehaus
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openstreetmap.josm.plugins.osb.gui.action;
+
+import java.awt.Cursor;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.JToggleButton;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.plugins.osb.OsbPlugin;
+
+public class PointToNewIssueAction extends AbstractAction implements MouseListener {
+
+    private static final long serialVersionUID = 1L;
+
+    private JToggleButton button;
+    
+    private OsbPlugin plugin;
+
+    private Cursor previousCursor;
+    
+    public PointToNewIssueAction(JToggleButton button, OsbPlugin plugin) {
+        this.button = button;
+        this.plugin = plugin;
+    }
+
+    private void reset() {
+        Main.map.mapView.setCursor(previousCursor);
+        Main.map.mapView.removeMouseListener(this);
+        button.setSelected(false);
+    }
+
+    public void mouseClicked(MouseEvent e) {
+        addNewIssue(e);
+    }
+
+    public void mouseEntered(MouseEvent e) {}
+
+    public void mouseExited(MouseEvent e) {}
+
+    public void mousePressed(MouseEvent e) {
+        addNewIssue(e);
+    }
+
+    private void addNewIssue(MouseEvent e) {
+        NewIssueAction nia = new NewIssueAction(plugin, e.getPoint());
+        nia.actionPerformed(new ActionEvent(this, 0, ""));
+        reset();
+    }
+
+    public void mouseReleased(MouseEvent e) {}
+
+    public void actionPerformed(ActionEvent e) {
+        if(button.isSelected()) {
+            previousCursor = Main.map.mapView.getCursor();
+            Main.map.mapView.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
+            Main.map.mapView.addMouseListener(this);
+        } else {
+            reset();
+        }
+    }
+}
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/PopupFactory.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/PopupFactory.java	(revision 19281)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/PopupFactory.java	(revision 19282)
@@ -35,4 +35,5 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.plugins.osb.OsbPlugin;
+import org.openstreetmap.josm.plugins.osb.gui.OsbDialog;
 
 public class PopupFactory {
@@ -41,9 +42,9 @@
     private static JPopupMenu fixedPopup;
 
-    public static synchronized JPopupMenu createPopup(Node node) {
+    public static synchronized JPopupMenu createPopup(Node node, OsbDialog dialog) {
         if("0".equals(node.get("state"))) {
-            return getIssuePopup();
+            return getIssuePopup(dialog);
         } else if("1".equals(node.get("state"))) {
-            return getFixedPopup();
+            return getFixedPopup(dialog);
         } else {
             throw new RuntimeException(tr("Unknown issue state"));
@@ -51,13 +52,13 @@
     }
 
-    private static JPopupMenu getIssuePopup() {
+    private static JPopupMenu getIssuePopup(OsbDialog dialog) {
         if(issuePopup == null) {
             issuePopup = new JPopupMenu();
             JMenuItem add = new JMenuItem();
-            add.setAction(new AddCommentAction());
+            add.setAction(new AddCommentAction(dialog));
             add.setIcon(OsbPlugin.loadIcon("add_comment16.png"));
             issuePopup.add(add);
             JMenuItem close = new JMenuItem();
-            close.setAction(new CloseIssueAction());
+            close.setAction(new CloseIssueAction(dialog));
             close.setIcon(OsbPlugin.loadIcon("icon_valid16.png"));
             issuePopup.add(close);
@@ -66,14 +67,14 @@
     }
 
-    private static JPopupMenu getFixedPopup() {
+    private static JPopupMenu getFixedPopup(OsbDialog dialog) {
         if(fixedPopup == null) {
             fixedPopup = new JPopupMenu();
             JMenuItem add = new JMenuItem();
-            AddCommentAction aca = new AddCommentAction();
+            AddCommentAction aca = new AddCommentAction(dialog);
             aca.setEnabled(false);
             add.setAction(aca);
             add.setIcon(OsbPlugin.loadIcon("add_comment16.png"));
             JMenuItem close = new JMenuItem();
-            CloseIssueAction cia = new CloseIssueAction();
+            CloseIssueAction cia = new CloseIssueAction(dialog);
             cia.setEnabled(false);
             close.setAction(cia);
Index: /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/ToggleConnectionModeAction.java
===================================================================
--- /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/ToggleConnectionModeAction.java	(revision 19282)
+++ /applications/editors/josm/plugins/openstreetbugs/src/org/openstreetmap/josm/plugins/osb/gui/action/ToggleConnectionModeAction.java	(revision 19282)
@@ -0,0 +1,88 @@
+package org.openstreetmap.josm.plugins.osb.gui.action;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JOptionPane;
+import javax.swing.JToggleButton;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.plugins.osb.ConfigKeys;
+import org.openstreetmap.josm.plugins.osb.OsbPlugin;
+import org.openstreetmap.josm.plugins.osb.gui.OsbDialog;
+
+public class ToggleConnectionModeAction extends AbstractAction {
+
+    private OsbPlugin plugin;
+    
+    private OsbDialog dialog;
+    
+    public static final String MSG_ONLINE = tr("Switch to online mode");
+    public static final String MSG_OFFLINE = tr("Switch to offline mode");
+    
+    public ToggleConnectionModeAction(OsbDialog osbDialog, OsbPlugin osbPlugin) {
+        super(MSG_OFFLINE);
+        this.dialog = osbDialog;
+        this.plugin = osbPlugin;
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        boolean isOffline = !Main.pref.getBoolean(ConfigKeys.OSB_API_OFFLINE);
+        
+        // inform the dialog about the connection mode
+        dialog.setConnectionMode(isOffline);
+        
+        // set the new value in the preferences
+        Main.pref.put(ConfigKeys.OSB_API_OFFLINE, isOffline);
+        
+        // toggle the tooltip text
+        if(e.getSource() != null && e.getSource() instanceof JToggleButton) {
+            JToggleButton button = (JToggleButton) e.getSource();
+            if(isOffline) {
+                button.setToolTipText(MSG_ONLINE);
+                if(Main.pref.getBoolean(ConfigKeys.OSB_BUTTON_LABELS)) {
+                    button.setText(MSG_ONLINE);
+                }
+            } else {
+                button.setToolTipText(MSG_OFFLINE);
+                if(Main.pref.getBoolean(ConfigKeys.OSB_BUTTON_LABELS)) {
+                    button.setText(MSG_OFFLINE);
+                }
+            }
+        }
+        
+        
+        if(!isOffline) {
+            if(ActionQueue.getInstance().getSize() == 0) {
+                dialog.hideQueuePanel();
+                return;
+            }
+            
+            // if we switch to online mode, ask if the queue should be processed
+            int result = JOptionPane.showConfirmDialog(Main.parent,
+                tr("You have unsaved changes in your queue. Do you want to submit them now?"),
+                tr("OpenStreetBugs"),
+                JOptionPane.YES_NO_OPTION);
+            if(result == JOptionPane.YES_OPTION) {
+                try {
+                    ActionQueue.getInstance().processQueue();
+                    
+                    // toggle queue panel visibility, if now error occured
+                    dialog.hideQueuePanel();
+    
+                    // refresh, if the api is enabled
+                    if(!Main.pref.getBoolean(ConfigKeys.OSB_API_DISABLED)) {
+                        plugin.updateData();
+                    }
+                } catch (Exception e1) {
+                    System.err.println("Couldn't process action queue");
+                    e1.printStackTrace();
+                }
+            }
+        } else {
+            dialog.showQueuePanel();
+        }
+    }
+}
