public
Created

  • Download Gist
gistfile1.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
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]
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.