/*
*
*
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.perseus.model;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
/**
* An <code>EventBaseCondition</code> generates a <code>TimeInstance</code>
* everytime the associated event happens.
*
* <p>It is the responsibility of this class to register as an
* <code>EventListener</code>. The <code>TimeInstance</code> created
* by an <code>EventBaseCondition</code> are cleared on reset, i.e, when
* the associated <code>TimedElementSupport</code> restarts.
*
* @version $Id: EventBaseCondition.java,v 1.3 2006/06/29 10:47:31 ln156897 Exp $
*/
public class EventBaseCondition extends TimeCondition
implements EventListener, IDRef {
/**
* Offset from the event base
*/
long offset;
/**
* Keeps a reference to the last occurence of the event.
*/
Time lastEventTime = Time.UNRESOLVED;
/**
* The event base, i.e., the element which generates events this
* listeners listens to.
*/
ModelNode eventBase;
/**
* The id of the event base. If null, the event base is the timed
* element of this condition.
*/
String eventBaseId;
/**
* The type of event this listener listens to.
*/
String eventType;
/**
* @param timedElement the associated <code>TimedElementSupport</code>.
* Should not be null.
* @param isBegin defines whether this condition is for a begin list.
* @param eventBaseId the id of the element which generates events this
* listener listens to. If null, this means the events are
* generated by the timedElement itself.
* @param eventType the type of event this listener listens to. Should
* not be null.
* @param offset offset from the sync base. This means that time instances
* synchronized on the syncBase begin or end time are offset by
* this amount.
* @throws IllegalArgumentException if eventType is null or if the
* <code>ModelNode</code> associated with the
* <code>timedElement</code> is null.
*/
public EventBaseCondition(final TimedElementSupport timedElement,
final boolean isBegin,
final String eventBaseId,
final String eventType,
final long offset) {
this(timedElement,
isBegin,
eventBaseId,
timedElement.animationElement,
eventType,
offset);
}
/**
* @param timedElement the associated <code>TimedElementSupport</code>.
* Should not be null.
* @param isBegin defines whether this condition is for a begin list.
* @param eventBaseId the id of the element which generates events this
* listener listens to. If null, this means the events are
* generated by the timedElement itself.
* @param eventBase in case eventBaseId is null, this should be used as
* the source for generating events. If eventBaseId is null, this
* should not be null.
* @param eventType the type of event this listener listens to. Should
* not be null.
* @param offset offset from the sync base. This means that time instances
* synchronized on the syncBase begin or end time are offset by
* this amount.
* @throws IllegalArgumentException if eventType is null or if eventBase
* and eventBaseId are null.
*/
protected EventBaseCondition(final TimedElementSupport timedElement,
final boolean isBegin,
final String eventBaseId,
final ModelNode eventBase,
final String eventType,
final long offset) {
super(timedElement, isBegin);
if (eventType == null
||
(eventBaseId == null && eventBase == null)) {
throw new IllegalArgumentException();
}
this.eventBaseId = eventBaseId;
this.eventType = eventType;
this.offset = offset;
ModelNode elt = timedElement.animationElement;
if (eventBaseId == null) {
setEventBase(eventBase);
} else {
elt.ownerDocument.resolveIDRef(this, eventBaseId);
}
}
/**
* Implementation helper.
*
* @param eventBase this node's event base.
*/
private void setEventBase(final ModelNode eventBase) {
if (this.eventBase != null) {
throw new IllegalStateException();
}
this.eventBase = eventBase;
// Register the listener for the bubble phase.
eventBase.ownerDocument.getEventSupport().addEventListener
(eventBase, eventType, EventSupport.BUBBLE_PHASE, this);
}
/**
* <code>IDRef</code> implementation.
*
* @param ref the resolved reference (from eventBaseId).
*/
public void resolveTo(final ElementNode ref) {
setEventBase(ref);
}
/**
* Implementation of the <code>EventListener</code> interface.
* When an event is received from the event base, this condition
* should generate a new <code>TimeInstance</code> that will be added
* to the associdated <code>TimedElementSupport</code> begin or end instance
* list (depending on the <code>isBegin</code> setting). The condition
* should also record the time of the new event as its
* <code>lastEventTime</code>.
*
* <p>Note that a condition is sensitive to events according to the
* SMIL Animation specification, section 3.6.4 specifying 'Event
* Sensitivity' (or SMIL 2 Timing and Synchronization Module,
* 'Event Sensitivity').</p>
*
* @param evt the event that occured
*/
public void handleEvent(final Event evt) {
// =====================================================================
// If the container is not active, there is no event sensitivity
// If the event time is unresolved, there is no event sensitivy either,
// as there is no way to compute the time instance that should be
// added to the timed element.
if (timedElement.timeContainer.state
!=
TimedElementSupport.STATE_PLAYING
||
!((ModelEvent) evt).eventTime.isResolved()) {
return;
}
// =====================================================================
// When the container is active, begin condition are sensitive when:
// - there is no current interval yet, i.e., the timedElement is not
// active.
// - there is a current interval, and the restart behavior is 'always'
//
// When the container is active (i.e., there is a resolved currentTime),
// end condition are sensitive when the element is active and the
// restart behavior is never or when active and the restart behavior
// is 'always' but there is no begin condition for the event.
Time eventTime = new Time(((ModelEvent) evt).eventTime.value);
eventTime = timedElement.toContainerSimpleTime(eventTime);
if (timedElement.state != TimedElementSupport.STATE_PLAYING) {
if (isBegin) {
new TimeInstance(timedElement,
new Time(eventTime.value + offset),
true,
isBegin);
lastEventTime = eventTime;
}
} else {
// The element is active
if (timedElement.restart == TimedElementSupport.RESTART_ALWAYS) {
// Only add an instance if this is a begin condition
// of if there is not begin event condition
if (isBegin || !timedElement.hasBeginCondition(this)) {
new TimeInstance(timedElement,
new Time(eventTime.value + offset),
true,
isBegin);
lastEventTime = eventTime;
}
} else {
if (!isBegin) {
new TimeInstance(timedElement,
new Time(eventTime.value + offset),
true,
isBegin);
lastEventTime = eventTime;
}
}
}
}
/**
* Converts this <code>EventBaseCondition</code> to a String trait.
*
* @return a string describing this <code>TimeCondition</code>
*/
protected String toStringTrait() {
StringBuffer sb = new StringBuffer();
sb.append(eventBaseId);
sb.append('.');
sb.append(eventType);
if (offset != 0) {
if (offset > 0) {
sb.append('+');
}
sb.append(offset / 1000f);
sb.append('s');
}
return sb.toString();
}
}
|