152 lines
6.5 KiB
Kotlin
152 lines
6.5 KiB
Kotlin
package io.gitlab.jfronny.inceptum.gtk.control
|
|
|
|
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.gdk.Gdk
|
|
import org.gnome.gio.Menu
|
|
import org.gnome.gtk.*
|
|
import java.io.IOException
|
|
|
|
class InstanceListEntryFactory(
|
|
private val app: Application?,
|
|
private val instanceList: List<Instance>
|
|
) : KSignalListItemFactory<InstanceListEntryFactory.Decomposed, ActionRow>() {
|
|
override fun setup(): ActionRow {
|
|
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"]
|
|
|
|
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 = Gdk.BUTTON_SECONDARY
|
|
rightClicked.onPressed { nPress, _, _ -> if (nPress == 1) menu.emitActivate() }
|
|
row.addController(rightClicked)
|
|
|
|
return row
|
|
}
|
|
|
|
override fun BindContext.bind(widget: ActionRow, data: Decomposed) {
|
|
if (data.instance?.isLocked ?: true) {
|
|
data.item.activatable = false
|
|
widget.subtitle = if (data.instance?.isRunningLocked ?: false) I18n["instance.launch.locked.running"]
|
|
else I18n["instance.launch.locked.setup"]
|
|
}
|
|
|
|
widget.title = data.instance.toString()
|
|
|
|
data.thumbnail.bind(data.instance!!)
|
|
|
|
val menuBuilder = MenuBuilder(data.popoverMenu, data.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 (!data.instance.kill()) LauncherEnv.showError(I18n["instance.kill.fail"], I18n["failed"])
|
|
}
|
|
}
|
|
kill.enabled = data.instance.isRunningLocked
|
|
|
|
launchSection.literalButton(
|
|
"launch.client", I18n["instance.launch.client"]
|
|
) { GtkMenubar.launch(data.instance, LaunchType.Client) }.iconName = "media-playback-start-symbolic"
|
|
launchSection.literalButton(
|
|
"launch.server", I18n["instance.launch.server"]
|
|
) { GtkMenubar.launch(data.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, data.instance).visible = true
|
|
}.iconName = "document-edit-symbolic"
|
|
settingsSection.literalButton(
|
|
"directory", I18n["instance.directory"]
|
|
) { Utils.openFile(data.instance.path.toFile()) }.iconName = "folder-symbolic"
|
|
settingsSection.literalButton("copy", I18n["instance.copy"]) {
|
|
LauncherEnv.getInput(
|
|
I18n["instance.copy.prompt"],
|
|
I18n["instance.copy.details"],
|
|
InstanceNameTool.getNextValid(data.instance.name),
|
|
{ s: String? ->
|
|
try {
|
|
JFiles.copyRecursive(
|
|
data.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(data.instance.path)
|
|
} catch (e: IOException) {
|
|
LauncherEnv.showError(I18n["instance.delete.fail"], e)
|
|
}
|
|
}
|
|
}.iconName = "edit-delete-symbolic"
|
|
|
|
registerForUnbind(data.launch.onClicked { GtkMenubar.launch(data.instance, LaunchType.Client) })
|
|
}
|
|
|
|
override fun UnbindContext.unbind(widget: ActionRow, data: Decomposed) {
|
|
data.popoverMenu.insertActionGroup(data.instanceId, null)
|
|
}
|
|
|
|
override fun ActionContext.castWidget(widget: Widget): ActionRow = widget as ActionRow
|
|
|
|
override fun ActionContext.lookup(id: String, widget: ActionRow): Decomposed {
|
|
val instance = instanceList[id]
|
|
val prefixes = widget.firstChild!!.firstChild as Box
|
|
val suffixes = widget.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(listItem, id, instance, thumbnail, launch, popoverMenu)
|
|
}
|
|
|
|
class Decomposed(
|
|
val item: ListItem,
|
|
val instanceId: String,
|
|
val instance: Instance?,
|
|
val thumbnail: InstanceThumbnail,
|
|
val launch: Button,
|
|
val popoverMenu: PopoverMenu
|
|
)
|
|
}
|