/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.canvas.impl; import java.awt.Cursor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Stack; import org.simantics.g2d.canvas.IMouseCursorContext; import org.simantics.g2d.canvas.IMouseCursorHandle; import org.simantics.g2d.canvas.IMouseCursorHandleListener; import org.simantics.g2d.canvas.IMouseCursorListener; import org.simantics.utils.datastructures.ListenerList; import org.simantics.utils.threads.IThreadWorkQueue; import org.simantics.utils.threads.SyncListenerList; /** * @author Toni Kalajainen */ public class MouseCursorContext implements IMouseCursorContext { protected Map> mouseCursorStack = new HashMap>(); protected SyncListenerList cursorListeners = new SyncListenerList(IMouseCursorListener.class); public void addCursorListener(IMouseCursorListener listener) { cursorListeners.add(listener); } public void addCursorListener(IMouseCursorListener listener, IThreadWorkQueue thread) { cursorListeners.add(thread, listener); } public void removeCursorListener(IMouseCursorListener listener) { cursorListeners.remove(listener); } public void removeCursorListener(IMouseCursorListener listener, IThreadWorkQueue thread) { cursorListeners.remove(thread, listener); } private final static Method onCursorSet = SyncListenerList.getMethod(IMouseCursorListener.class, "onCursorSet"); protected void fireSetCursor(int mouseId, Cursor cursor) { cursorListeners.fireEventSync(onCursorSet, this, mouseId, cursor); } protected void fireAsyncSetCursor(int mouseId, Cursor cursor) { cursorListeners.fireEventAsync(onCursorSet, this, mouseId, cursor); } class CursorReserve implements IMouseCursorHandle { Cursor cursor; int mouseId; ListenerList listeners; public CursorReserve(Cursor cursor, int mouseId) { this.cursor = cursor; this.mouseId = mouseId; } @Override public void remove() { synchronized(MouseCursorContext.this) { Stack cursorStack = mouseCursorStack.get(mouseId); if (cursorStack == null || !cursorStack.contains(this)) return; boolean wasLast = cursorStack.lastElement()==this; cursorStack.remove(this); if (cursorStack.isEmpty()) { _setCursor(mouseId, null); return; } // Select the second last cursor if (wasLast) { CursorReserve newLast = cursorStack.peek(); if (newLast==null) { _setCursor(mouseId, null); } else { Cursor newCursor = newLast.cursor; if (!cursor.equals(newCursor)) _setCursor(mouseId, newCursor); } } } } @Override public Cursor getCursor() { return cursor; } @Override public int getMouseId() { return mouseId; } void fireOnRemoved() { ListenerList lis; synchronized(this) { lis = listeners; if (lis==null) return; } for (IMouseCursorHandleListener l : lis.getListeners()) l.onMouseCursorRemoved(this); } @Override public synchronized void addMouseCursorHandleListener(IMouseCursorHandleListener listener) { if (listeners == null) { listeners = new ListenerList(IMouseCursorHandleListener.class); } listeners.add(listener); } @Override public synchronized void removeMouseCursorHandleListener(IMouseCursorHandleListener listener) { if (listeners == null) return; listeners.remove(listener); } } @Override public synchronized IMouseCursorHandle setCursor(int mouseId, Cursor cursor) { assert(cursor!=null); Stack cursorStack = mouseCursorStack.get(mouseId); if (cursorStack == null) { cursorStack = new Stack(); mouseCursorStack.put(mouseId, cursorStack); } CursorReserve cr = new CursorReserve(cursor, mouseId); cursorStack.push(cr); _setCursor(mouseId, cursor); return cr; } protected void _setCursor(int mouseId, Cursor cursor) { fireAsyncSetCursor(mouseId, cursor); } }