Skip to content

Instantly share code, notes, and snippets.

@jppellet
Created May 2, 2011 07:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jppellet/951288 to your computer and use it in GitHub Desktop.
Save jppellet/951288 to your computer and use it in GitHub Desktop.
import collection.mutable.{ Buffer, ArrayBuffer, ObservableBuffer, Subscriber, Builder, Undoable }
import collection.generic.{ Growable, GenericTraversableTemplate, SeqFactory, CanBuildFrom, GenericCompanion }
import collection.script.{ Message, Include, Update, Remove, Reset, Location, Start, End, NoLo, Index }
import org.eclipse.core.databinding.observable.list.{ IObservableList, ObservableList }
import org.eclipse.core.databinding.observable.{ Diffs, Observable }
trait AsObservable[+O <: IObservable] {
def asObservable: O
}
trait ObservableBridgeCommons[A] {
this: Iterable[A] =>
protected def toIndex(loc: Location) = loc match {
case Start => 0
case End => size - 1
case Index(ind) => ind
case NoLo => error("no location available")
}
}
trait SavesBeforeClear[A] extends Growable[A] {
this: Iterable[A] =>
private var elementsJustCleared: List[A] = Nil
protected def getAndClearElementsJustCleared() = {
val value = elementsJustCleared
elementsJustCleared = Nil
value
}
abstract override def clear(): Unit = {
// just a trick to save the old elements to send them in the ListDiff
elementsJustCleared = Nil ++ this
super.clear
}
}
trait ObservableListBridge[A] extends Buffer[A] with ObservableBridgeCommons[A] with SavesBeforeClear[A] with AsObservable[IObservableList[A]] {
self: ObservableBuffer[A] =>
import collection.JavaConversions._
lazy val asObservable: IObservableList[A] = makeObservableList
private var elementJustUpdated: A = _
abstract override def update(n: Int, newElement: A): Unit = {
// just a trick to save the old element to send it in the ListDiff
elementJustUpdated = apply(n)
super.update(n, newElement)
}
private def makeObservableList: IObservableList[A] =
new ObservableList[A](asJavaList(self), null) {
private var listenerAdapter: Subscriber[Message[A], ObservableBuffer[A]] = _
override protected def firstListenerAdded() = {
if (listenerAdapter == null) {
listenerAdapter = new Subscriber[Message[A], ObservableBuffer[A]] {
import Diffs._
def notify(pub: ObservableBuffer[A], e: Message[A]) = e match {
case Update(loc, newElement) => {
val index = toIndex(loc)
fireListChange(createListDiff(
createListDiffEntry(index, false, elementJustUpdated),
createListDiffEntry(index, true, newElement)
))
}
case Include(loc, element) =>
fireListChange(createListDiff(
createListDiffEntry(toIndex(loc), true, element)))
case Remove(loc, oldElement) =>
fireListChange(createListDiff(
createListDiffEntry(toIndex(loc), false, oldElement)))
case Reset() =>
fireListChange(createListDiff(
getAndClearElementsJustCleared().map(e => createListDiffEntry(0, false, e)).toArray
))
case unknown => error("unexpected update type: " + unknown)
}
}
}
self.subscribe(listenerAdapter)
}
override protected def lastListenerRemoved() = {
self.removeSubscription(listenerAdapter)
listenerAdapter = null
}
}
}
class ObservableArrayBuffer[A] extends ArrayBuffer[A]
with GenericTraversableTemplate[A, ObservableArrayBuffer] // hey, I'm an ObservableArrayBuffer!
with Builder[A, ObservableArrayBuffer[A]] // like normal buffers, it is a builder for itself
with ObservableBuffer[A] // is Scala-observable
with ObservableListBridge[A] { // can provide a Eclipse-databinding object
override def companion: GenericCompanion[ObservableArrayBuffer] = ObservableArrayBuffer
override def result: ObservableArrayBuffer[A] = this
override def stringPrefix: String = "ObservableArrayBuffer"
override def ++=(xs: TraversableOnce[A]): this.type = {
var lastIndex = this.size
super.++=(xs)
// TODO remove this once https://lampsvn.epfl.ch/trac/scala/ticket/4461 is fixed
xs ifMatch {
case vs: IndexedSeq[_] => vs.foreach { v =>
publish(new Include(Index(lastIndex), v) with Undoable {
def undo() { trimEnd(1) }
})
lastIndex += 1
}
}
this
}
}
object ObservableArrayBuffer extends SeqFactory[ObservableArrayBuffer] {
/** $genericCanBuildFromInfo */
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ObservableArrayBuffer[A]] = new GenericCanBuildFrom[A]
def newBuilder[A]: Builder[A, ObservableArrayBuffer[A]] = new ObservableArrayBuffer[A]
override def empty[A] = new ObservableArrayBuffer[A]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment