166 lines
7.3 KiB
Kotlin
166 lines
7.3 KiB
Kotlin
package io.gitlab.jfronny.inceptum.gtk.control
|
|
|
|
import io.github.jwharm.javagi.base.Signal
|
|
import io.gitlab.jfronny.commons.io.JFiles
|
|
import io.gitlab.jfronny.commons.ref.R
|
|
import io.gitlab.jfronny.inceptum.common.MetaHolder
|
|
import io.gitlab.jfronny.inceptum.common.Utils
|
|
import io.gitlab.jfronny.inceptum.gtk.GtkMenubar
|
|
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder
|
|
import io.gitlab.jfronny.inceptum.gtk.util.I18n
|
|
import io.gitlab.jfronny.inceptum.gtk.util.fixSubtitle
|
|
import io.gitlab.jfronny.inceptum.gtk.util.get
|
|
import io.gitlab.jfronny.inceptum.gtk.util.margin
|
|
import io.gitlab.jfronny.inceptum.gtk.window.settings.instance.InstanceSettingsWindow
|
|
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv
|
|
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance
|
|
import io.gitlab.jfronny.inceptum.launcher.system.instance.InstanceNameTool
|
|
import io.gitlab.jfronny.inceptum.launcher.system.launch.LaunchType
|
|
import org.gnome.adw.ActionRow
|
|
import org.gnome.gio.Menu
|
|
import org.gnome.gtk.*
|
|
import java.io.IOException
|
|
import java.util.function.Consumer
|
|
|
|
class InstanceListEntryFactory(app: Application?, instanceList: List<Instance>) : SignalListItemFactory() {
|
|
init {
|
|
onSetup {
|
|
val li = it as ListItem
|
|
|
|
val thumbnail = InstanceThumbnail()
|
|
thumbnail.name = "inceptum-thumbnail"
|
|
|
|
val launch = Button.newFromIconName("media-playback-start-symbolic")
|
|
launch.addCssClass("flat")
|
|
launch.name = "inceptum-launch"
|
|
launch.tooltipText = I18n["instance.launch"]
|
|
launch.hasTooltip = true
|
|
|
|
val menu = MenuButton()
|
|
menu.addCssClass("flat")
|
|
menu.iconName = "view-more-symbolic"
|
|
menu.setPopover(PopoverMenu.newFromModel(Menu()))
|
|
|
|
val row = ActionRow()
|
|
row.margin = 8
|
|
row.name = "inceptum-row"
|
|
row.removeCssClass("activatable") //TODO remove this workaround if a better way to support opening the menu is found
|
|
row.addPrefix(thumbnail)
|
|
row.addSuffix(launch)
|
|
row.addSuffix(menu)
|
|
row.fixSubtitle()
|
|
|
|
val rightClicked = GestureClick()
|
|
rightClicked.button = 3
|
|
rightClicked.onPressed { nPress, _, _ -> if (nPress == 1) menu.emitActivate() }
|
|
row.addController(rightClicked)
|
|
|
|
li.child = row
|
|
}
|
|
val toDisconnect: MutableMap<String, MutableSet<Signal<*>>> = HashMap()
|
|
onBind {
|
|
val li = Decomposed.of(it as ListItem, instanceList)
|
|
|
|
if (li.instance?.isLocked ?: true) {
|
|
li.item.activatable = false
|
|
li.row.subtitle = if (li.instance?.isRunningLocked ?: false) I18n["instance.launch.locked.running"]
|
|
else I18n["instance.launch.locked.setup"]
|
|
}
|
|
|
|
li.row.title = li.instance.toString()
|
|
|
|
li.thumbnail.bind(li.instance!!)
|
|
|
|
val menuBuilder = MenuBuilder(li.popoverMenu, li.instanceId)
|
|
val launchSection = menuBuilder.literalSection("launch", null)
|
|
val kill = launchSection.literalButton("kill", I18n["instance.kill"]) {
|
|
//TODO test
|
|
LauncherEnv.showOkCancel(I18n["instance.kill.prompt"], I18n["instance.kill.details"]) {
|
|
if (!li.instance.kill()) LauncherEnv.showError(I18n["instance.kill.fail"], I18n["failed"])
|
|
}
|
|
}
|
|
kill.enabled = li.instance.isRunningLocked
|
|
|
|
launchSection.literalButton(
|
|
"launch.client", I18n["instance.launch.client"]
|
|
) { GtkMenubar.launch(li.instance, LaunchType.Client) }.iconName = "media-playback-start-symbolic"
|
|
launchSection.literalButton(
|
|
"launch.server", I18n["instance.launch.server"]
|
|
) { GtkMenubar.launch(li.instance, LaunchType.Server) }.iconName = "network-server-symbolic"
|
|
val settingsSection = menuBuilder.literalSection("settings", null)
|
|
settingsSection.literalButton("settings", I18n["instance.settings"]) {
|
|
//TODO keep track of properties windows and don't allow opening two
|
|
InstanceSettingsWindow(app, li.instance).visible = true
|
|
}.iconName = "document-edit-symbolic"
|
|
settingsSection.literalButton(
|
|
"directory", I18n["instance.directory"]
|
|
) { Utils.openFile(li.instance.path.toFile()) }.iconName = "folder-symbolic"
|
|
settingsSection.literalButton("copy", I18n["instance.copy"]) {
|
|
LauncherEnv.getInput(
|
|
I18n["instance.copy.prompt"],
|
|
I18n["instance.copy.details"],
|
|
InstanceNameTool.getNextValid(li.instance.name),
|
|
{ s: String? ->
|
|
try {
|
|
JFiles.copyRecursive(
|
|
li.instance.path,
|
|
MetaHolder.INSTANCE_DIR.resolve(InstanceNameTool.getNextValid(s))
|
|
)
|
|
} catch (e: IOException) {
|
|
LauncherEnv.showError(I18n["instance.copy.fail"], e)
|
|
}
|
|
}) { R.nop() }
|
|
}.iconName = "edit-copy-symbolic"
|
|
settingsSection.literalButton("delete", I18n["instance.delete"]) {
|
|
LauncherEnv.showOkCancel(
|
|
I18n["instance.delete.confirm"],
|
|
I18n["instance.delete.confirm.title"]
|
|
) {
|
|
try {
|
|
JFiles.deleteRecursive(li.instance.path)
|
|
} catch (e: IOException) {
|
|
LauncherEnv.showError(I18n["instance.delete.fail"], e)
|
|
}
|
|
}
|
|
}.iconName = "edit-delete-symbolic"
|
|
|
|
val dc = Consumer { s: Signal<*> ->
|
|
toDisconnect.computeIfAbsent(li.instanceId) { _ -> HashSet() }
|
|
.add(s)
|
|
}
|
|
|
|
dc.accept(li.launch.onClicked { GtkMenubar.launch(li.instance, LaunchType.Client) })
|
|
}
|
|
onUnbind {
|
|
val li = Decomposed.of(it as ListItem, instanceList)
|
|
li.popoverMenu.insertActionGroup(li.instanceId, null)
|
|
toDisconnect[li.instanceId]?.forEach(Consumer { obj: Signal<*> -> obj.disconnect() })
|
|
}
|
|
}
|
|
|
|
private class Decomposed(
|
|
val item: ListItem,
|
|
val instanceId: String,
|
|
val instance: Instance?,
|
|
val row: ActionRow,
|
|
val thumbnail: InstanceThumbnail,
|
|
val launch: Button,
|
|
val popoverMenu: PopoverMenu
|
|
) {
|
|
companion object {
|
|
fun of(item: ListItem, instanceList: List<Instance>): Decomposed {
|
|
val instanceId = (item.item as StringObject).string
|
|
val instance = instanceList[instanceId]
|
|
val row = item.child as ActionRow
|
|
val prefixes = row.firstChild!!.firstChild as Box
|
|
val suffixes = row.firstChild!!.lastChild as Box
|
|
val thumbnail = InstanceThumbnail.castFrom(prefixes.firstChild as Stack)
|
|
val launch = suffixes.firstChild as Button
|
|
val menuButton = launch.nextSibling as MenuButton
|
|
val popoverMenu = menuButton.popover as PopoverMenu
|
|
return Decomposed(item, instanceId, instance, row, thumbnail, launch, popoverMenu)
|
|
}
|
|
}
|
|
}
|
|
}
|