/******************************************************************************* * 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.scenegraph.g2d.events; import java.lang.reflect.Method; import java.util.LinkedList; import org.simantics.utils.datastructures.ListenerList; import org.simantics.utils.threads.IThreadWorkQueue; import org.simantics.utils.threads.SyncListenerList; /** * @see IEventQueue * @author Toni Kalajainen */ public class EventQueue implements IEventQueue, IEventHandler { ListenerList listeners = new ListenerList(IEventQueueListener.class); SyncListenerList listeners2 = new SyncListenerList(IEventQueueListener.class); ListenerList coalescers = new ListenerList(EventCoalescer.class); LinkedList queue = new LinkedList(); IEventHandler handler; public EventQueue(IEventHandler handler) { assert (handler != null); this.handler = handler; } @Override public int getEventMask() { return EventTypes.AnyMask; } @Override public synchronized void queueEvent(Event e) { // coalesce with last EventCoalescer[] css = coalescers.getListeners(); if (css.length > 0 && !queue.isEmpty()) { Event last = queue.get(queue.size() - 1); Event coalesced = null; for (EventCoalescer ecs : css) { coalesced = ecs.coalesce(last, e); if (coalesced != null) break; } if (coalesced == last) return; if (coalesced != null) { // replace last with coalesced queue.remove(queue.size() - 1); queue.addLast(coalesced); int index = queue.size() - 1; fireEventAdded(coalesced, index); return; } } queue.addLast(e); int index = queue.size() - 1; fireEventAdded(e, index); } @Override public synchronized void queueFirst(Event e) { // coalescale with first EventCoalescer[] css = coalescers.getListeners(); if (css.length > 0 && !queue.isEmpty()) { Event first = queue.get(0); Event coalesced = null; for (EventCoalescer ecs : css) { coalesced = ecs.coalesce(e, first); if (coalesced != null) break; } if (coalesced == first) return; if (coalesced != null) { // replace last with coalesced queue.remove(0); queue.addFirst(coalesced); fireEventAdded(coalesced, 0); return; } } queue.addFirst(e); fireEventAdded(e, 0); } public void handleEvents() { int eventsHandled = 0; Event[] events = null; do { synchronized (this) { events = queue.toArray(new Event[queue.size()]); queue.clear(); } for (Event e : events) { if (EventTypes.passes(handler, e)) handler.handleEvent(e); eventsHandled++; } } while (events.length > 0); if (eventsHandled > 0) fireQueueEmpty(); } @Override public void addEventCoalesceler(EventCoalescer coalescaler) { coalescers.add(coalescaler); } @Override public void removeEventCoalesceler(EventCoalescer coalescaler) { coalescers.remove(coalescaler); } @Override public boolean handleEvent(Event e) { handleEvents(); return EventTypes.passes(handler, e) ? handler.handleEvent(e) : false; } @Override public void addQueueListener(IEventQueueListener listener) { listeners.add(listener); } @Override public synchronized int size() { return queue.size(); } @Override public synchronized boolean isEmpty() { return queue.isEmpty(); } @Override public void removeQueueListener(IEventQueueListener listener) { listeners.remove(listener); } Method onEventAdded = SyncListenerList.getMethod(IEventQueueListener.class, "onEventAdded"); protected void fireEventAdded(Event e, int index) { for (IEventQueueListener eql : listeners.getListeners()) eql.onEventAdded(this, e, index); listeners2.fireEventSync(onEventAdded, this, e, index); } Method onQueueEmpty = SyncListenerList.getMethod(IEventQueueListener.class, "onQueueEmpty"); protected void fireQueueEmpty() { for (IEventQueueListener eql : listeners.getListeners()) eql.onQueueEmpty(this); listeners2.fireEventSync(onQueueEmpty, this); } @Override public void addQueueListener(IEventQueueListener listener, IThreadWorkQueue thread) { listeners2.add(thread, listener); } @Override public void removeQueueListener(IEventQueueListener listener, IThreadWorkQueue thread) { listeners2.remove(thread, listener); } }