--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.scenegraph.g2d.events;\r
+\r
+import java.lang.reflect.Method;\r
+import java.util.LinkedList;\r
+\r
+import org.simantics.utils.datastructures.ListenerList;\r
+import org.simantics.utils.threads.IThreadWorkQueue;\r
+import org.simantics.utils.threads.SyncListenerList;\r
+\r
+/**\r
+ * @see IEventQueue\r
+ * @author Toni Kalajainen\r
+ */\r
+public class EventQueue implements IEventQueue, IEventHandler {\r
+\r
+ ListenerList<IEventQueueListener> listeners = new ListenerList<IEventQueueListener>(IEventQueueListener.class);\r
+ SyncListenerList<IEventQueueListener> listeners2 = new SyncListenerList<IEventQueueListener>(IEventQueueListener.class);\r
+ ListenerList<EventCoalescer> coalescers = new ListenerList<EventCoalescer>(EventCoalescer.class);\r
+ LinkedList<Event> queue = new LinkedList<Event>();\r
+\r
+ IEventHandler handler;\r
+\r
+ public EventQueue(IEventHandler handler) {\r
+ assert (handler != null);\r
+ this.handler = handler;\r
+ }\r
+\r
+ @Override\r
+ public int getEventMask() {\r
+ return EventTypes.AnyMask;\r
+ }\r
+\r
+ @Override\r
+ public synchronized void queueEvent(Event e) {\r
+ // coalesce with last\r
+ EventCoalescer[] css = coalescers.getListeners();\r
+ if (css.length > 0 && !queue.isEmpty()) {\r
+ Event last = queue.get(queue.size() - 1);\r
+ Event coalesced = null;\r
+ for (EventCoalescer ecs : css) {\r
+ coalesced = ecs.coalesce(last, e);\r
+ if (coalesced != null)\r
+ break;\r
+ }\r
+ if (coalesced == last)\r
+ return;\r
+ if (coalesced != null) {\r
+ // replace last with coalesced\r
+ queue.remove(queue.size() - 1);\r
+ queue.addLast(coalesced);\r
+ int index = queue.size() - 1;\r
+ fireEventAdded(coalesced, index);\r
+ return;\r
+ }\r
+ }\r
+\r
+ queue.addLast(e);\r
+ int index = queue.size() - 1;\r
+ fireEventAdded(e, index);\r
+ }\r
+\r
+ @Override\r
+ public synchronized void queueFirst(Event e) {\r
+ // coalescale with first\r
+ EventCoalescer[] css = coalescers.getListeners();\r
+ if (css.length > 0 && !queue.isEmpty()) {\r
+ Event first = queue.get(0);\r
+ Event coalesced = null;\r
+ for (EventCoalescer ecs : css) {\r
+ coalesced = ecs.coalesce(e, first);\r
+ if (coalesced != null)\r
+ break;\r
+ }\r
+ if (coalesced == first)\r
+ return;\r
+ if (coalesced != null) {\r
+ // replace last with coalesced\r
+ queue.remove(0);\r
+ queue.addFirst(coalesced);\r
+ fireEventAdded(coalesced, 0);\r
+ return;\r
+ }\r
+ }\r
+\r
+ queue.addFirst(e);\r
+ fireEventAdded(e, 0);\r
+ }\r
+\r
+ public void handleEvents() {\r
+ int eventsHandled = 0;\r
+ Event[] events = null;\r
+ do {\r
+ synchronized (this) {\r
+ events = queue.toArray(new Event[queue.size()]);\r
+ queue.clear();\r
+ }\r
+ for (Event e : events) {\r
+ if (EventTypes.passes(handler, e))\r
+ handler.handleEvent(e);\r
+ eventsHandled++;\r
+ }\r
+ } while (events.length > 0);\r
+ if (eventsHandled > 0)\r
+ fireQueueEmpty();\r
+ }\r
+\r
+ @Override\r
+ public void addEventCoalesceler(EventCoalescer coalescaler) {\r
+ coalescers.add(coalescaler);\r
+ }\r
+\r
+ @Override\r
+ public void removeEventCoalesceler(EventCoalescer coalescaler) {\r
+ coalescers.remove(coalescaler);\r
+ }\r
+\r
+ @Override\r
+ public boolean handleEvent(Event e) {\r
+ handleEvents();\r
+ return EventTypes.passes(handler, e) ? handler.handleEvent(e) : false;\r
+ }\r
+\r
+ @Override\r
+ public void addQueueListener(IEventQueueListener listener) {\r
+ listeners.add(listener);\r
+ }\r
+\r
+ @Override\r
+ public synchronized int size() {\r
+ return queue.size();\r
+ }\r
+\r
+ @Override\r
+ public synchronized boolean isEmpty() {\r
+ return queue.isEmpty();\r
+ }\r
+\r
+ @Override\r
+ public void removeQueueListener(IEventQueueListener listener) {\r
+ listeners.remove(listener);\r
+ }\r
+\r
+ Method onEventAdded = SyncListenerList.getMethod(IEventQueueListener.class, "onEventAdded");\r
+\r
+ protected void fireEventAdded(Event e, int index) {\r
+ for (IEventQueueListener eql : listeners.getListeners())\r
+ eql.onEventAdded(this, e, index);\r
+ listeners2.fireEventSync(onEventAdded, this, e, index);\r
+ }\r
+\r
+ Method onQueueEmpty = SyncListenerList.getMethod(IEventQueueListener.class, "onQueueEmpty");\r
+\r
+ protected void fireQueueEmpty() {\r
+ for (IEventQueueListener eql : listeners.getListeners())\r
+ eql.onQueueEmpty(this);\r
+ listeners2.fireEventSync(onQueueEmpty, this);\r
+ }\r
+\r
+ @Override\r
+ public void addQueueListener(IEventQueueListener listener, IThreadWorkQueue thread) {\r
+ listeners2.add(thread, listener);\r
+ }\r
+\r
+ @Override\r
+ public void removeQueueListener(IEventQueueListener listener, IThreadWorkQueue thread) {\r
+ listeners2.remove(thread, listener);\r
+ }\r
+\r
+}\r