001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.util; 003 004import java.awt.Component; 005import java.awt.Cursor; 006import java.util.Iterator; 007import java.util.LinkedHashMap; 008import java.util.Objects; 009import java.util.concurrent.CopyOnWriteArrayList; 010 011/** 012 * This class manages multiple cursors for multiple components. 013 * All components share the same cursor that was last set using {@link #setNewCursor(Cursor, Object)} 014 * 015 * @author Michael Zangl 016 */ 017public class CursorManager { 018 019 private final LinkedHashMap<Object, Cursor> cursors = new LinkedHashMap<>(); 020 private final CopyOnWriteArrayList<Component> components = new CopyOnWriteArrayList<>(); 021 022 /** 023 * Creates a new NavigationCursorManager 024 * @param forComponent The initial component the cursor should be managed for. 025 */ 026 public CursorManager(Component forComponent) { 027 addComponent(forComponent); 028 } 029 030 /** 031 * Adds a component that this manager should send cursor changes to. 032 * @param forComponent The component. 033 */ 034 public synchronized void addComponent(Component forComponent) { 035 components.addIfAbsent(forComponent); 036 forComponent.setCursor(getCurrentCursor()); 037 } 038 039 /** 040 * Removes a component that this manager should send cursor changes to. The current cursor is not reset. 041 * @param forComponent The component. 042 */ 043 public synchronized void removeComponent(Component forComponent) { 044 components.remove(forComponent); 045 } 046 047 /** 048 * Set new cursor. 049 * @param cursor The new cursor to use. 050 * @param reference A reference object that can be passed to the next set/reset calls to identify the caller. 051 */ 052 public synchronized void setNewCursor(Cursor cursor, Object reference) { 053 Objects.requireNonNull(reference, "Cannot register a cursor that can never be removed."); 054 // re-insert to allow overriding. 055 cursors.remove(reference); 056 cursors.put(reference, cursor); 057 updateCursor(); 058 } 059 060 /** 061 * Remove the new cursor that was set with the given reference object. and reset to previous 062 * @param reference A reference object that can be passed to the next set/reset calls to identify the caller. 063 */ 064 public synchronized void resetCursor(Object reference) { 065 if (reference == null) { 066 return; 067 } 068 cursors.remove(reference); 069 updateCursor(); 070 } 071 072 private void updateCursor() { 073 Cursor cursor = getCurrentCursor(); 074 for (Component c : components) { 075 c.setCursor(cursor); 076 } 077 } 078 079 private Cursor getCurrentCursor() { 080 Iterator<Cursor> it = cursors.values().iterator(); 081 Cursor cursor = null; 082 while (it.hasNext()) { 083 cursor = it.next(); 084 } 085 return cursor; 086 } 087 088}