All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.swing.Publisher.scala Maven / Gradle / Ivy

/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2007-2013, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

package scala.swing

import scala.collection.mutable
import mutable.Buffer
import event.Event

/** 

* Notifies registered reactions when an event is published. Publishers are * also reactors and listen to themselves per default as a convenience. *

*

* In order to reduce memory leaks, reactions are weakly referenced by default, * unless they implement Reactions.StronglyReferenced. That way, * the lifetime of reactions are more easily bound to the registering object, * which are reactors in common client code and hold strong references to their * reactions. As a result, reactors can be garbage collected even though they * still have reactions registered at some publisher, but not vice versa * since reactors (strongly) reference publishers they are interested in. *

*/ trait Publisher extends Reactor { import Reactions._ protected val listeners = new RefSet[Reaction] { import scala.ref._ val underlying = new mutable.HashSet[Reference[Reaction]] protected def Ref(a: Reaction) = a match { case a: StronglyReferenced => new StrongReference[Reaction](a) with super.Ref[Reaction] case _ => new WeakReference[Reaction](a, referenceQueue) with super.Ref[Reaction] } } private[swing] def subscribe(listener: Reaction) { listeners += listener } private[swing] def unsubscribe(listener: Reaction) { listeners -= listener } /** * Notify all registered reactions. */ def publish(e: Event) { for (l <- listeners) l(e) } listenTo(this) } /** * A publisher that subscribes itself to an underlying event source not before the first * reaction is installed. Can unsubscribe itself when the last reaction is uninstalled. */ private[swing] trait LazyPublisher extends Publisher { import Reactions._ protected def onFirstSubscribe() protected def onLastUnsubscribe() override def subscribe(listener: Reaction) { if(listeners.size == 1) onFirstSubscribe() super.subscribe(listener) } override def unsubscribe(listener: Reaction) { super.unsubscribe(listener) if(listeners.size == 1) onLastUnsubscribe() } } import scala.ref._ private[swing] trait SingleRefCollection[+A <: AnyRef] extends Iterable[A] { self => trait Ref[+A <: AnyRef] extends Reference[A] { override def hashCode() = get match { case Some(x) => x.## case _ => 0 } override def equals(that: Any) = that match { case that: ReferenceWrapper[_] => val v1 = this.get val v2 = that.get v1 == v2 case _ => false } } //type Ref <: Reference[A] // TODO: could use higher kinded types, but currently crashes protected[this] def Ref(a: A): Ref[A] protected[this] val referenceQueue = new ReferenceQueue[A] protected val underlying: Iterable[Reference[A]] def purgeReferences() { var ref = referenceQueue.poll while (ref != None) { removeReference(ref.get.asInstanceOf[Reference[A]]) ref = referenceQueue.poll } } protected[this] def removeReference(ref: Reference[A]) def iterator = new Iterator[A] { private val elems = self.underlying.iterator private var hd: A = _ private var ahead: Boolean = false private def skip(): Unit = while (!ahead && elems.hasNext) { // make sure we have a reference to the next element, // otherwise it might be garbage collected val next = elems.next.get ahead = next != None if (ahead) hd = next.get } def hasNext: Boolean = { skip; ahead } def next(): A = if (hasNext) { ahead = false; hd } else throw new NoSuchElementException("next on empty iterator") } } private[swing] class StrongReference[+T <: AnyRef](value: T) extends Reference[T] { private[this] var ref: Option[T] = Some(value) def isValid: Boolean = ref != None def apply(): T = ref.get def get : Option[T] = ref override def toString = get.map(_.toString).getOrElse("") def clear() { ref = None } def enqueue(): Boolean = false def isEnqueued(): Boolean = false } abstract class RefBuffer[A <: AnyRef] extends Buffer[A] with SingleRefCollection[A] { self => protected val underlying: Buffer[Reference[A]] def +=(el: A): this.type = { purgeReferences(); underlying += Ref(el); this } def +=:(el: A) = { purgeReferences(); Ref(el) +=: underlying; this } def remove(el: A) { underlying -= Ref(el); purgeReferences(); } def remove(n: Int) = { val el = apply(n); remove(el); el } def insertAll(n: Int, iter: Iterable[A]) { purgeReferences() underlying.insertAll(n, iter.view.map(Ref(_))) } def update(n: Int, el: A) { purgeReferences(); underlying(n) = Ref(el) } def apply(n: Int) = { purgeReferences() var el = underlying(n).get while (el == None) { purgeReferences(); el = underlying(n).get } el.get } def length = { purgeReferences(); underlying.length } def clear() { underlying.clear(); purgeReferences() } protected[this] def removeReference(ref: Reference[A]) { underlying -= ref } } private[swing] abstract class RefSet[A <: AnyRef] extends mutable.Set[A] with SingleRefCollection[A] { self => protected val underlying: mutable.Set[Reference[A]] def -=(el: A): this.type = { underlying -= Ref(el); purgeReferences(); this } def +=(el: A): this.type = { purgeReferences(); underlying += Ref(el); this } def contains(el: A): Boolean = { purgeReferences(); underlying.contains(Ref(el)) } override def size = { purgeReferences(); underlying.size } protected[this] def removeReference(ref: Reference[A]) { underlying -= ref } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy