Created
May 2, 2011 07:57
-
-
Save jppellet/951288 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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