/* * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.javafx.event; import javafx.event.Event; import javafx.event.EventHandler; import javafx.event.WeakEventHandler; public final class CompositeEventHandler { private EventProcessorRecord firstRecord; private EventProcessorRecord lastRecord; private EventHandler eventHandler; public void setEventHandler(final EventHandler eventHandler) { this.eventHandler = eventHandler; } public EventHandler getEventHandler() { return eventHandler; } public void addEventHandler(final EventHandler eventHandler) { if (find(eventHandler, false) == null) { append(lastRecord, createEventHandlerRecord(eventHandler)); } } public void removeEventHandler(final EventHandler eventHandler) { final EventProcessorRecord record = find(eventHandler, false); if (record != null) { remove(record); } } public void addEventFilter(final EventHandler eventFilter) { if (find(eventFilter, true) == null) { append(lastRecord, createEventFilterRecord(eventFilter)); } } public void removeEventFilter(final EventHandler eventFilter) { final EventProcessorRecord record = find(eventFilter, true); if (record != null) { remove(record); } } public void dispatchBubblingEvent(final Event event) { final T specificEvent = (T) event; EventProcessorRecord record = firstRecord; while (record != null) { if (record.isDisconnected()) { remove(record); } else { record.handleBubblingEvent(specificEvent); } record = record.nextRecord; } if (eventHandler != null) { eventHandler.handle(specificEvent); } } public void dispatchCapturingEvent(final Event event) { final T specificEvent = (T) event; EventProcessorRecord record = firstRecord; while (record != null) { if (record.isDisconnected()) { remove(record); } else { record.handleCapturingEvent(specificEvent); } record = record.nextRecord; } } /* Used for testing. */ boolean containsHandler(final EventHandler eventHandler) { return find(eventHandler, false) != null; } /* Used for testing. */ boolean containsFilter(final EventHandler eventFilter) { return find(eventFilter, true) != null; } private EventProcessorRecord createEventHandlerRecord( final EventHandler eventHandler) { return (eventHandler instanceof WeakEventHandler) ? new WeakEventHandlerRecord( (WeakEventHandler) eventHandler) : new NormalEventHandlerRecord(eventHandler); } private EventProcessorRecord createEventFilterRecord( final EventHandler eventFilter) { return (eventFilter instanceof WeakEventHandler) ? new WeakEventFilterRecord( (WeakEventHandler) eventFilter) : new NormalEventFilterRecord(eventFilter); } private void remove(final EventProcessorRecord record) { final EventProcessorRecord prevRecord = record.prevRecord; final EventProcessorRecord nextRecord = record.nextRecord; if (prevRecord != null) { prevRecord.nextRecord = nextRecord; } else { firstRecord = nextRecord; } if (nextRecord != null) { nextRecord.prevRecord = prevRecord; } else { lastRecord = prevRecord; } // leave record.nextRecord set } private void append(final EventProcessorRecord prevRecord, final EventProcessorRecord newRecord) { EventProcessorRecord nextRecord; if (prevRecord != null) { nextRecord = prevRecord.nextRecord; prevRecord.nextRecord = newRecord; } else { nextRecord = firstRecord; firstRecord = newRecord; } if (nextRecord != null) { nextRecord.prevRecord = newRecord; } else { lastRecord = newRecord; } newRecord.prevRecord = prevRecord; newRecord.nextRecord = nextRecord; } private EventProcessorRecord find( final EventHandler eventProcessor, final boolean isFilter) { EventProcessorRecord record = firstRecord; while (record != null) { if (record.isDisconnected()) { remove(record); } else if (record.stores(eventProcessor, isFilter)) { return record; } record = record.nextRecord; } return null; } private static abstract class EventProcessorRecord { private EventProcessorRecord nextRecord; private EventProcessorRecord prevRecord; public abstract boolean stores(EventHandler eventProcessor, boolean isFilter); public abstract void handleBubblingEvent(T event); public abstract void handleCapturingEvent(T event); public abstract boolean isDisconnected(); } private static final class NormalEventHandlerRecord extends EventProcessorRecord { private final EventHandler eventHandler; public NormalEventHandlerRecord( final EventHandler eventHandler) { this.eventHandler = eventHandler; } @Override public boolean stores(final EventHandler eventProcessor, final boolean isFilter) { return !isFilter && (this.eventHandler == eventProcessor); } @Override public void handleBubblingEvent(final T event) { eventHandler.handle(event); } @Override public void handleCapturingEvent(final T event) { } @Override public boolean isDisconnected() { return false; } } private static final class WeakEventHandlerRecord extends EventProcessorRecord { private final WeakEventHandler weakEventHandler; public WeakEventHandlerRecord( final WeakEventHandler weakEventHandler) { this.weakEventHandler = weakEventHandler; } @Override public boolean stores(final EventHandler eventProcessor, final boolean isFilter) { return !isFilter && (weakEventHandler == eventProcessor); } @Override public void handleBubblingEvent(final T event) { weakEventHandler.handle(event); } @Override public void handleCapturingEvent(final T event) { } @Override public boolean isDisconnected() { return weakEventHandler.wasGarbageCollected(); } } private static final class NormalEventFilterRecord extends EventProcessorRecord { private final EventHandler eventFilter; public NormalEventFilterRecord( final EventHandler eventFilter) { this.eventFilter = eventFilter; } @Override public boolean stores(final EventHandler eventProcessor, final boolean isFilter) { return isFilter && (this.eventFilter == eventProcessor); } @Override public void handleBubblingEvent(final T event) { } @Override public void handleCapturingEvent(final T event) { eventFilter.handle(event); } @Override public boolean isDisconnected() { return false; } } private static final class WeakEventFilterRecord extends EventProcessorRecord { private final WeakEventHandler weakEventFilter; public WeakEventFilterRecord( final WeakEventHandler weakEventFilter) { this.weakEventFilter = weakEventFilter; } @Override public boolean stores(final EventHandler eventProcessor, final boolean isFilter) { return isFilter && (weakEventFilter == eventProcessor); } @Override public void handleBubblingEvent(final T event) { } @Override public void handleCapturingEvent(final T event) { weakEventFilter.handle(event); } @Override public boolean isDisconnected() { return weakEventFilter.wasGarbageCollected(); } } }