package org.geogebra.common.plugin; import java.util.ArrayList; import org.geogebra.common.kernel.ClientView; import org.geogebra.common.kernel.ModeSetter; import org.geogebra.common.kernel.geos.GProperty; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.main.App; import org.geogebra.common.util.debug.GeoGebraProfiler; /** * Every event scripting machinery must implement the EventListener interface * and register with the application's event dispatcher (via * app.getEventDispatcher().addEventListener(...)). It will then obtain events * via the sendEvent() method. * * EventDispatcher registers itself as a view so it can listen to most event * types and forward them to listeners. Click events are handled differently * because they are not part of the View interface (the clicked GeoElement is * responsible for relaying the event to the event dispatcher) * * @author arno * */ public class EventDispatcher implements ClientView { private App app; private ArrayList<EventListener> listeners = new ArrayList<EventListener>(); /** * @param app * application */ public EventDispatcher(App app) { this.app = app; app.getKernel().attach(this); } /** * Add a new EventListener object * * @param listener * the object that wants to receive notifications of events */ public void addEventListener(EventListener listener) { listeners.add(listener); } /** * Remove an EventListener object * * @param listener * the object to remove */ public void removeEventListener(EventListener listener) { listeners.remove(listener); } /** * Dispatch an event to all registered event listeners * * @param evt * the event to be dispatched */ public void dispatchEvent(Event evt) { if (app.getKernel().getConstruction() != null) { app.getKernel().getConstruction().setSelfGeo(evt.target); } for (EventListener listener : listeners) { listener.sendEvent(evt); } if (app.getKernel().getConstruction() != null) { app.getKernel().getConstruction().setSelfGeo(null); } } /** * Convenience method for dispatching an event * * @param evtType * the type of the event * @param geo * the target of the event * @param arg * an extra argument */ public void dispatchEvent(EventType evtType, GeoElement geo, String arg) { if (!geo.isLabelSet()) { return; } dispatchEvent(new Event(evtType, geo, arg)); } /** * Convenience method for dispatching an event * * @param evtType * the type of the event * @param geo * the target of the event */ public void dispatchEvent(EventType evtType, GeoElement geo) { if ((null != geo) && !geo.isLabelSet() && !geo.isGeoCasCell()) { return; } dispatchEvent(new Event(evtType, geo)); } /** * @param evtType * event type * @param geos * multiple targets */ public void dispatchBulkEvent(EventType evtType, ArrayList<GeoElement> geos) { dispatchEvent(new Event(evtType, null, null, geos)); } /* * Implementation of View */ @Override public void add(GeoElement geo) { dispatchEvent(EventType.ADD, geo); } @Override public void remove(GeoElement geo) { dispatchEvent(EventType.REMOVE, geo); } @Override public void rename(GeoElement geo) { dispatchEvent(EventType.RENAME, geo); } @Override public void update(GeoElement geo) { long start = System.currentTimeMillis(); dispatchEvent(EventType.UPDATE, geo); GeoGebraProfiler.addEvent(System.currentTimeMillis() - start); } @Override public void updateVisualStyle(GeoElement geo, GProperty prop) { dispatchEvent(EventType.UPDATE_STYLE, geo); } @Override public void updatePreviewFromInputBar(GeoElement[] geos) { // not used } @Override public void updateAuxiliaryObject(GeoElement geo) { // Ignore } @Override public void repaintView() { // Ignore } @Override public void reset() { // Ignore } @Override public void clearView() { // As I understand it, this happens when a new file is started. This is // the time to call the reset() function of the registered event // listeners. for (EventListener listener : listeners) { listener.reset(); } } @Override public void setMode(int mode, ModeSetter m) { this.dispatchEvent(new Event(EventType.SET_MODE, null, mode + "")); } @Override public int getViewID() { return App.VIEW_EVENT_DISPATCHER; } @Override public boolean hasFocus() { return false; } @Override public boolean isShowing() { return false; } @Override public void startBatchUpdate() { // TODO Auto-generated method stub } @Override public void endBatchUpdate() { // TODO Auto-generated method stub } @Override public void renameUpdatesComplete() { dispatchEvent(EventType.RENAME_COMPLETE, null); } @Override public void addingPolygon() { dispatchEvent(EventType.ADD_POLYGON, null); } @Override public void addPolygonComplete(GeoElement polygon) { dispatchEvent(EventType.ADD_POLYGON_COMPLETE, polygon); } @Override public void movingGeos() { dispatchEvent(EventType.MOVING_GEOS, null); } @Override public void movedGeos(ArrayList<GeoElement> elms) { dispatchBulkEvent(EventType.MOVED_GEOS, elms); } @Override public void deleteGeos(ArrayList<GeoElement> elms) { dispatchBulkEvent(EventType.DELETE_GEOS, elms); } @Override public void pasteElms(String pasteXml) { dispatchEvent(new Event(EventType.PASTE_ELMS, null, pasteXml)); } @Override public void pasteElmsComplete(ArrayList<GeoElement> pastedElms) { dispatchBulkEvent(EventType.PASTE_ELMS_COMPLETE, pastedElms); } @Override public boolean suggestRepaint() { return false; // not used for this view } }