All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
de.sciss.mellite.impl.artifact.ArtifactViewImpl.scala Maven / Gradle / Ivy
/*
* ArtifactViewImpl.scala
* (Mellite)
*
* Copyright (c) 2012-2023 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU Affero General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* [email protected]
*/
package de.sciss.mellite.impl.artifact
import de.sciss.desktop.{Desktop, FileDialog, PathField}
import de.sciss.file.File
import de.sciss.icons.raphael
import de.sciss.lucre.edit.UndoManager
import de.sciss.lucre.edit.impl.BasicUndoableEdit
import de.sciss.lucre.swing.LucreSwing.{deferTx, requireEDT}
import de.sciss.lucre.swing.View
import de.sciss.lucre.swing.impl.ComponentHolder
import de.sciss.lucre.synth.Txn
import de.sciss.lucre.{Artifact, Disposable, Source}
import de.sciss.mellite.GUI.iconNormal
import de.sciss.mellite.impl.objview.ArtifactObjView.humanName
import de.sciss.mellite.{ArtifactLocationFrame, ArtifactLocationObjView, ArtifactView, UniverseHandler, ViewState}
import de.sciss.proc.Universe
import de.sciss.swingplus.ComboBox
import java.net.URI
import javax.swing.undo.{CannotRedoException, CannotUndoException}
import scala.swing.event.{SelectionChanged, ValueChanged}
import scala.swing.{Action, Button, Component, FlowPanel}
import scala.util.Try
object ArtifactViewImpl {
def mkPathField(reveal: Boolean, mode: Boolean,
initMode: FileDialog.Mode = FileDialog.Save): (PathField, FlowPanel) = {
val ggFile = new PathField
ggFile.mode = initMode
val c0: List[Component] = if (!mode) ggFile :: Nil else {
val ggMode = new ComboBox(Seq("New File", "Existing File", "Existing Folder")) {
listenTo(selection)
reactions += {
case SelectionChanged(_) =>
ggFile.mode = selection.index match {
case 1 => FileDialog.Open
case 2 => FileDialog.Folder
case _ => FileDialog.Save
}
}
}
ggFile :: ggMode :: Nil
}
val c = if (!reveal) c0 else {
val ggReveal = new Button(Action(null)(Desktop.revealFile(ggFile.value)))
ggReveal.icon = iconNormal(raphael.Shapes.Inbox)
ggReveal.tooltip = s"Reveal in ${if (Desktop.isMac) "Finder" else "File Manager"}"
ggReveal :: c0
}
val ggValue = new FlowPanel(c: _*)
(ggFile, ggValue)
}
def apply[T <: Txn[T]](obj: Artifact[T], mode: Boolean, initMode: FileDialog.Mode)
(implicit tx: T, handler: UniverseHandler[T], undo: UndoManager[T]): ArtifactView[T] = {
val objH = tx.newHandle(obj)
val editable = obj.modifiableOption.isDefined
val res = new Impl(objH, mode = mode, initMode = initMode, editable = editable)
res.init(obj)
res
}
private final class UpdateChild[T <: Txn[T]](val name: String, aH: Source[T, Artifact.Modifiable[T]],
oldChild: Artifact.Child,
newChild: Artifact.Child)
extends BasicUndoableEdit[T] {
override protected def undoImpl()(implicit tx: T): Unit = {
val a = aH()
if (a.child != newChild) throw new CannotUndoException()
a.child = oldChild
}
override protected def redoImpl()(implicit tx: T): Unit =
perform()
def perform()(implicit tx: T): Unit = {
val a = aH()
if (a.child != oldChild) throw new CannotRedoException()
a.child = newChild
}
}
private final class Impl[T <: Txn[T]](objH: Source[T, Artifact[T]], mode: Boolean, initMode: FileDialog.Mode,
val editable: Boolean)
(implicit handler: UniverseHandler[T], val undoManager: UndoManager[T])
extends ArtifactView[T] with View.Editable[T] with ComponentHolder[Component] {
type C = Component
private[this] var ggPath : PathField = _
private[this] var observer : Disposable[T] = _
override implicit val universe: Universe[T] = handler.universe
override def obj(implicit tx: T): Artifact[T] = objH()
override def viewState: Set[ViewState] = Set.empty
def init(obj0: Artifact[T])(implicit tx: T): this.type = {
val value0 = obj0.value
deferTx(initGUI(value0))
observer = obj0.changed.react { implicit tx => upd =>
deferTx {
val fileNowOpt = Try(new File(upd.now)).toOption
ggPath.valueOption = fileNowOpt
}
}
this
}
private def initGUI(value0: URI): Unit = {
val (_ggPath, p) = mkPathField(reveal = true, mode = mode, initMode = initMode)
val file0Opt = Try(new File(value0)).toOption
_ggPath.valueOption = file0Opt
val ggLoc: Button = new Button(Action(null) {
cursor.step { implicit tx =>
ArtifactLocationFrame(objH().location)
}
})
ggLoc.icon = iconNormal(raphael.Shapes.Location)
ggLoc.tooltip = s"${ArtifactLocationObjView.humanName} View"
p.contents.insert(1, ggLoc)
ggPath = _ggPath
if (editable) _ggPath.reactions += {
case ValueChanged(_) => save()
}
component = p
}
def save(): Unit = {
requireEDT()
val newPath = ggPath.valueOption.map(_.toURI)
cursor.step { implicit tx =>
val title = s"Edit $humanName"
objH().modifiableOption match {
case Some(pVr) if newPath.isDefined =>
val oldVal = pVr.child
val newVal = Artifact.Value.relativize(pVr.location.value, newPath.get)
import de.sciss.equal.Implicits._
if (newVal === oldVal) None else {
val edit = new UpdateChild[T](title, tx.newHandle(pVr), oldChild = oldVal, newChild = newVal)
edit.perform()
undoManager.addEdit(edit)
}
case _ => None
}
}
}
def dispose()(implicit tx: T): Unit = observer.dispose()
}
}