From 9030153876f46cedbc9639fc7aa19c771655c34c Mon Sep 17 00:00:00 2001
From: Michael Zangl <michael.zangl@student.kit.edu>
Date: Wed, 1 Jul 2015 17:03:30 +0200
Subject: [PATCH 10/11] Moved cursor management to new class and used java
 library fuctnions for the cursor stack

---
 .../josm/gui/NavigatableComponent.java             | 52 +++----------
 .../josm/gui/navigate/NavigationCursorManager.java | 87 ++++++++++++++++++++++
 2 files changed, 98 insertions(+), 41 deletions(-)
 create mode 100644 src/org/openstreetmap/josm/gui/navigate/NavigationCursorManager.java

diff --git a/src/org/openstreetmap/josm/gui/NavigatableComponent.java b/src/org/openstreetmap/josm/gui/NavigatableComponent.java
index c5505f9..6bd0808 100644
--- a/src/org/openstreetmap/josm/gui/NavigatableComponent.java
+++ b/src/org/openstreetmap/josm/gui/NavigatableComponent.java
@@ -51,6 +51,7 @@ import org.openstreetmap.josm.gui.download.DownloadDialog;
 import org.openstreetmap.josm.gui.help.Helpful;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
+import org.openstreetmap.josm.gui.navigate.NavigationCursorManager;
 import org.openstreetmap.josm.tools.Predicate;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -186,6 +187,8 @@ public class NavigatableComponent extends JComponent implements Helpful {
 
     protected transient ViewportData initialViewport;
 
+    protected transient final NavigationCursorManager cursorManager = new NavigationCursorManager(this);
+
     /**
      * Constructs a new {@code NavigatableComponent}.
      */
@@ -1435,30 +1438,11 @@ public class NavigatableComponent extends JComponent implements Helpful {
         return (int) id.getValue();
     }
 
-    private static class CursorInfo {
-        private final Cursor cursor;
-        private final Object object;
-
-        public CursorInfo(Cursor c, Object o) {
-            cursor = c;
-            object = o;
-        }
-    }
-
-    private LinkedList<CursorInfo> cursors = new LinkedList<>();
-
     /**
      * Set new cursor.
      */
     public void setNewCursor(Cursor cursor, Object reference) {
-        if (!cursors.isEmpty()) {
-            CursorInfo l = cursors.getLast();
-            if (l != null && l.cursor == cursor && l.object == reference)
-                return;
-            stripCursors(reference);
-        }
-        cursors.add(new CursorInfo(cursor, reference));
-        setCursor(cursor);
+        cursorManager.setNewCursor(cursor, reference);
     }
 
     public void setNewCursor(int cursor, Object reference) {
@@ -1469,29 +1453,15 @@ public class NavigatableComponent extends JComponent implements Helpful {
      * Remove the new cursor and reset to previous
      */
     public void resetCursor(Object reference) {
-        if (cursors.isEmpty()) {
-            setCursor(null);
-            return;
-        }
-        CursorInfo l = cursors.getLast();
-        stripCursors(reference);
-        if (l != null && l.object == reference) {
-            if (cursors.isEmpty()) {
-                setCursor(null);
-            } else {
-                setCursor(cursors.getLast().cursor);
-            }
-        }
+        cursorManager.resetCursor(reference);
     }
 
-    private void stripCursors(Object reference) {
-        LinkedList<CursorInfo> c = new LinkedList<>();
-        for (CursorInfo i : cursors) {
-            if (i.object != reference) {
-                c.add(i);
-            }
-        }
-        cursors = c;
+    /**
+     * Gets the cursor manager that is used for this NavigatableComponent.
+     * @return The cursor manager.
+     */
+    public NavigationCursorManager getCursorManager() {
+        return cursorManager;
     }
 
     @Override
diff --git a/src/org/openstreetmap/josm/gui/navigate/NavigationCursorManager.java b/src/org/openstreetmap/josm/gui/navigate/NavigationCursorManager.java
new file mode 100644
index 0000000..b2a810b
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/navigate/NavigationCursorManager.java
@@ -0,0 +1,87 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.navigate;
+
+import java.awt.Component;
+import java.awt.Cursor;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * This class manages multiple cursors for multiple components. All components share the same cursor that was last set using {@link #setNewCursor(Cursor, Object)}
+ * @author Michael Zangl
+ */
+public class NavigationCursorManager {
+
+    private final LinkedHashMap<Object, Cursor> cursors = new LinkedHashMap<>();
+    private final CopyOnWriteArrayList<Component> components = new CopyOnWriteArrayList<>();
+
+    /**
+     * Creates a new NavigationCursorManager
+     * @param forComponent The initial component the cursor should be managed for.
+     */
+    public NavigationCursorManager(Component forComponent) {
+        addComponent(forComponent);
+    }
+
+    /**
+     * Adds a component that this manager should send cursor changes to.
+     * @param forComponent The component.
+     */
+    public synchronized void addComponent(Component forComponent) {
+        components.addIfAbsent(forComponent);
+        forComponent.setCursor(getCurrentCursor());
+    }
+
+    /**
+     * Removes a component that this manager should send cursor changes to. The current cursor is not reset.
+     * @param forComponent The component.
+     */
+    public synchronized void removeComponent(Component forComponent) {
+        components.remove(forComponent);
+    }
+
+    /**
+     * Set new cursor.
+     * @param cursor The new cursor to use.
+     * @param reference A reference object that can be passed to the next set/reset calls to identify the caller.
+     */
+    public synchronized void setNewCursor(Cursor cursor, Object reference) {
+        if (reference == null) {
+            throw new NullPointerException("Cannot register a cursor that can never be removed.");
+        }
+        // re-insert to allow overriding.
+        cursors.remove(reference);
+        cursors.put(reference, cursor);
+        updateCursor();
+    }
+
+    /**
+     * Remove the new cursor that was set with the given reference object. and reset to previous
+     * @param reference A reference object that can be passed to the next set/reset calls to identify the caller.
+     */
+    public synchronized void resetCursor(Object reference) {
+        if (reference == null) {
+            return;
+        }
+        cursors.remove(reference);
+        updateCursor();
+    }
+
+    private void updateCursor() {
+        Cursor cursor = getCurrentCursor();
+        for (Component c : components) {
+            c.setCursor(cursor);
+        }
+    }
+
+    private Cursor getCurrentCursor() {
+        Iterator<Cursor> it = cursors.values().iterator();
+        Cursor cursor = null;
+        while (it.hasNext()) {
+            cursor = it.next();
+        }
+        return cursor;
+    }
+
+}
-- 
1.9.1

