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