package org.docear.plugin.core.event; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Stack; import org.freeplane.core.util.LogUtils; public class DocearEventQueue { private final Thread dispatcher; private final Stack<DocearEvent> eventStack = new Stack<DocearEvent>(); private final List<IDocearEventListener> eventListeners = Collections.synchronizedList(new ArrayList<IDocearEventListener>()); private boolean stopDispatcher = false; /*********************************************************************************** * CONSTRUCTORS **********************************************************************************/ public DocearEventQueue() { dispatcher = getDispatcherThread(); } /*********************************************************************************** * METHODS **********************************************************************************/ private Thread getDispatcherThread() { return new Thread("Docear-EventQueue") { public void run() { while(!stopDispatcher) { DocearEvent event = null; while((event = popEvent()) != null) { try { if(event instanceof DocearRunnableEvent) { ((DocearRunnableEvent) event).exec(); } else { dispatchEvent(event); } } catch (Throwable e) { LogUtils.severe(e); } if(stopDispatcher) { return; } } try { synchronized (this) { this.wait(); } } catch (InterruptedException e) { } } } }; } private DocearEvent popEvent() { synchronized (eventStack) { if(eventStack.empty()) { return null; } return eventStack.pop(); } } public void invoke(DocearEvent event) { if(dispatcher.isAlive()) { synchronized (eventStack) { eventStack.add(event); } synchronized(dispatcher) { dispatcher.notify(); } } } public void invoke(Runnable task) { DocearEvent event = new DocearRunnableEvent(this, task); invoke(event); } public void addEventListener(IDocearEventListener listener) { synchronized (this.eventListeners) { if(this.eventListeners.contains(listener)) { return; } this.eventListeners.add(listener); } } public void removeEventListener(IDocearEventListener listener) { synchronized (this.eventListeners) { this.eventListeners.remove(listener); } } public void removeAllEventListeners() { synchronized (this.eventListeners) { this.eventListeners.clear(); } } public synchronized void dispatchEvent(DocearEvent event) { synchronized (this.eventListeners) { IDocearEventListener[] listenerArray = this.eventListeners.toArray(new IDocearEventListener[0]); for(IDocearEventListener listener : listenerArray) { listener.handleEvent(event); } } } public void start() { if(!dispatcher.isAlive()) { dispatcher.start(); } } public void stop() { stopDispatcher = true; if(dispatcher.isAlive()) { synchronized(dispatcher) { dispatcher.notify(); } } } /*********************************************************************************** * REQUIRED METHODS FOR INTERFACES **********************************************************************************/ /*********************************************************************************** * NESTED TYPES **********************************************************************************/ private static class DocearRunnableEvent extends DocearEvent { private static final long serialVersionUID = 1L; public DocearRunnableEvent(Object source, Runnable r) { super(source, r); } public void exec() { ((Runnable)getEventObject()).run(); } } }