de.sciss.lucre.swing.impl.CellViewEditor.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lucreswing_2.13.0-RC2 Show documentation
Show all versions of lucreswing_2.13.0-RC2 Show documentation
Swing support for Lucre, and common views
The newest version!
/*
* CellViewEditor.scala
* (LucreSwing)
*
* Copyright (c) 2014-2019 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU Lesser General Public License v2.1+
*
*
* For further information, please contact Hanns Holger Rutz at
* [email protected]
*/
package de.sciss.lucre.swing.impl
import de.sciss.lucre.stm.{Disposable, Sys}
import de.sciss.lucre.swing.View
import javax.swing.event.{UndoableEditEvent, UndoableEditListener}
import scala.swing.{Component, TextComponent}
trait CellViewEditor[S <: Sys[S], A, Comp <: Component]
extends View[S] with ComponentHolder[Comp] with CellViewFactory.View[A] {
type C = Comp
// ---- abstract ----
// the current ephemeral (but committed) value of the view. sub classes should
// implement this with the correct initial value
protected var value: A
// must be implemented by updating the GUI component with the current `value`
protected def valueToComponent(): Unit
// must be implemented by creating the GUI component
protected def createComponent(): Comp
// final var observer: Disposable[S#Tx] = _
protected def observer: Disposable[S#Tx]
// maybe be set by the sub class in `createComponent()`
final protected var dirty = Option.empty[DirtyBorder]
// clears the dirty status if `dirty` is non empty
protected def clearDirty(): Unit = dirty.foreach(_.visible = false)
// called when the expression changes, so that the change will be reflected in the GUI
final def update(newValue: A): Unit =
if (value != newValue) {
value = newValue
valueToComponent()
clearDirty()
}
// installs an edit listener for the given text component which will flag `dirty` upon the first change
// to the component's document
final protected def observeDirty(text: TextComponent): Unit = {
// the fucking JSpinner implementation removes and re-inserts its text when focused,
// at least with aqua LaF. this means that two undoable edits are fired which are
// completely pointless and idiotically marked as "significant". In order to skip
// them, we register focus and key listeners.
val j = text.peer
// var valid = true // false
j.getDocument.addUndoableEditListener(new UndoableEditListener {
def undoableEditHappened(e: UndoableEditEvent): Unit = {
// if (valid) {
// println(s"UNDOABLE EDIT: ${e.getEdit}")
dirty.foreach(_.visible = true)
// }
}
})
// text.peer.addFocusListener(new FocusListener {
// def focusLost (e: FocusEvent) = ()
// def focusGained(e: FocusEvent): Unit = valid = false
// })
// text.peer.addKeyListener(new KeyListener {
// def keyReleased(e: KeyEvent): Unit = ()
// def keyPressed (e: KeyEvent): Unit = valid = true
// def keyTyped (e: KeyEvent): Unit = ()
// })
}
final def guiInit(): Unit =
component = createComponent()
// disposes the observer.
def dispose()(implicit tx: S#Tx): Unit = observer.dispose()
}