|
@@ -1,60 +1,133 @@
|
|
|
|
|
+@file:Suppress("DEPRECATION")
|
|
|
|
|
+
|
|
|
package eu.mjdev.desktop.data
|
|
package eu.mjdev.desktop.data
|
|
|
|
|
|
|
|
import eu.mjdev.desktop.extensions.Custom.ParsedBoolean
|
|
import eu.mjdev.desktop.extensions.Custom.ParsedBoolean
|
|
|
import eu.mjdev.desktop.extensions.Custom.ParsedList
|
|
import eu.mjdev.desktop.extensions.Custom.ParsedList
|
|
|
|
|
+import eu.mjdev.desktop.extensions.Custom.ParsedString
|
|
|
import org.ini4j.Ini
|
|
import org.ini4j.Ini
|
|
|
|
|
+import org.ini4j.Profile
|
|
|
|
|
+import org.ini4j.Wini
|
|
|
import java.io.File
|
|
import java.io.File
|
|
|
|
|
+import java.io.InputStream
|
|
|
|
|
+import java.io.StringBufferInputStream
|
|
|
|
|
|
|
|
-@Suppress("ConstPropertyName", "unused")
|
|
|
|
|
|
|
+@Suppress("ConstPropertyName", "unused", "CanBeParameter", "MemberVisibilityCanBePrivate", "KotlinConstantConditions")
|
|
|
class DesktopFile(
|
|
class DesktopFile(
|
|
|
- val file: File
|
|
|
|
|
|
|
+ val file: File,
|
|
|
|
|
+ private val content: Ini? = runCatching { if (file.exists()) Wini(file) else null }.getOrNull(),
|
|
|
|
|
+ private val props: Profile.Section? = content?.get(DesktopFileType.DesktopEntry.text)
|
|
|
) {
|
|
) {
|
|
|
- private val content
|
|
|
|
|
- get() = runCatching { if (file.exists()) Ini(file) else null }.getOrNull()
|
|
|
|
|
-
|
|
|
|
|
- private val props
|
|
|
|
|
- get() = content?.get("Desktop Entry")
|
|
|
|
|
-
|
|
|
|
|
- val fileName: String
|
|
|
|
|
- get() = file.name
|
|
|
|
|
-
|
|
|
|
|
- val type
|
|
|
|
|
- get() = DesktopFileType(props?.get(Prop_Type))
|
|
|
|
|
-
|
|
|
|
|
- val version
|
|
|
|
|
- get() = props?.get(Prop_Version).orEmpty()
|
|
|
|
|
-
|
|
|
|
|
- val name
|
|
|
|
|
- get() = props?.get(Prop_Name).orEmpty()
|
|
|
|
|
-
|
|
|
|
|
- val comment
|
|
|
|
|
- get() = props?.get(Prop_Comment).orEmpty()
|
|
|
|
|
-
|
|
|
|
|
- val path
|
|
|
|
|
- get() = props?.get(Prop_Path).orEmpty()
|
|
|
|
|
-
|
|
|
|
|
- val exec
|
|
|
|
|
- get() = props?.get(Prop_Exec).orEmpty()
|
|
|
|
|
-
|
|
|
|
|
- val icon
|
|
|
|
|
- get() = props?.get(Prop_Icon).orEmpty()
|
|
|
|
|
-
|
|
|
|
|
- val categories
|
|
|
|
|
- get() = ParsedList(props?.get(Prop_Categories))
|
|
|
|
|
-
|
|
|
|
|
- val notifyOnStart
|
|
|
|
|
- get() = ParsedBoolean(props?.get(Prop_StartupNotify))
|
|
|
|
|
-
|
|
|
|
|
- val runInTerminal
|
|
|
|
|
- get() = ParsedBoolean(props?.get(Prop_Terminal))
|
|
|
|
|
|
|
+ var fileName: String = file.name
|
|
|
|
|
+ val absolutePath: String = file.absolutePath
|
|
|
|
|
+
|
|
|
|
|
+ val actions: MutableList<Action> = parseActions()
|
|
|
|
|
+
|
|
|
|
|
+ var type: DesktopFileType = DesktopFileType(props?.get(Prop_Type))
|
|
|
|
|
+ var version: String = ParsedString(props?.get(Prop_Version))
|
|
|
|
|
+ var name: String = ParsedString(props?.get(Prop_Name))
|
|
|
|
|
+ var comment: String = ParsedString(props?.get(Prop_Comment))
|
|
|
|
|
+ var path: String = ParsedString(props?.get(Prop_Path))
|
|
|
|
|
+ var exec: String = ParsedString(props?.get(Prop_Exec))
|
|
|
|
|
+ var icon: String = ParsedString(props?.get(Prop_Icon))
|
|
|
|
|
+ var categories: MutableList<String> = ParsedList(props?.get(Prop_Categories))
|
|
|
|
|
+ var notifyOnStart: Boolean = ParsedBoolean(props?.get(Prop_StartupNotify))
|
|
|
|
|
+ var runInTerminal: Boolean = ParsedBoolean(props?.get(Prop_Terminal))
|
|
|
|
|
+ var encoding: String = ParsedString(props?.get(Prop_Encoding))
|
|
|
|
|
+
|
|
|
|
|
+ // todo
|
|
|
|
|
+ private fun parseActions(): MutableList<Action> = mutableListOf()
|
|
|
|
|
+
|
|
|
|
|
+ fun action(
|
|
|
|
|
+ header: DesktopFileType,
|
|
|
|
|
+ block: Action.() -> Unit
|
|
|
|
|
+ ) = actions.add(Action("[${header.text}]").apply(block))
|
|
|
|
|
+
|
|
|
|
|
+ fun write() {
|
|
|
|
|
+ Wini().also { ini ->
|
|
|
|
|
+ ini.add(DesktopFileType.DesktopEntry.text).also { section ->
|
|
|
|
|
+ section.add(Prop_Type, type.text)
|
|
|
|
|
+ if (name.isNotEmpty()) section.add(Prop_Name, name)
|
|
|
|
|
+ if (comment.isNotEmpty()) section.add(Prop_Comment, comment)
|
|
|
|
|
+ if (version.isNotEmpty()) section.add(Prop_Version, version)
|
|
|
|
|
+ if (encoding.isNotEmpty()) section.add(Prop_Encoding, encoding)
|
|
|
|
|
+ if (type == DesktopFileType.Application) {
|
|
|
|
|
+ if (path.isNotEmpty()) section.add(Prop_Path, path)
|
|
|
|
|
+ if (exec.isNotEmpty()) section.add(Prop_Exec, exec)
|
|
|
|
|
+ if (icon.isNotEmpty()) section.add(Prop_Icon, icon)
|
|
|
|
|
+ if (categories.isNotEmpty()) section.add(Prop_Categories, categories.joinToString { "$it;" })
|
|
|
|
|
+ if (notifyOnStart) section.add(Prop_StartupNotify, notifyOnStart)
|
|
|
|
|
+ if (runInTerminal) section.add(Prop_Terminal, runInTerminal)
|
|
|
|
|
+ }
|
|
|
|
|
+ actions.forEach { action ->
|
|
|
|
|
+ section.addChild(action.type.text).also { subsection ->
|
|
|
|
|
+ if (type == DesktopFileType.Application) {
|
|
|
|
|
+ subsection.add(Prop_Type, type.text)
|
|
|
|
|
+ if (version.isNotEmpty()) subsection.add(Prop_Type, version)
|
|
|
|
|
+ if (name.isNotEmpty()) subsection.add(Prop_Name, name)
|
|
|
|
|
+ if (comment.isNotEmpty()) subsection.add(Prop_Comment, comment)
|
|
|
|
|
+ if (path.isNotEmpty()) subsection.add(Prop_Path, path)
|
|
|
|
|
+ if (exec.isNotEmpty()) subsection.add(Prop_Exec, exec)
|
|
|
|
|
+ if (icon.isNotEmpty()) subsection.add(Prop_Icon, icon)
|
|
|
|
|
+ if (categories.isNotEmpty()) subsection.add(
|
|
|
|
|
+ Prop_Categories,
|
|
|
|
|
+ categories.joinToString { "$it;" })
|
|
|
|
|
+ if (notifyOnStart) subsection.add(Prop_StartupNotify, notifyOnStart)
|
|
|
|
|
+ if (runInTerminal) subsection.add(Prop_Terminal, runInTerminal)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (type == DesktopFileType.Theme) {
|
|
|
|
|
+ if (action.gtkTheme.isNotEmpty()) subsection.add(Prop_GtkTheme, action.gtkTheme)
|
|
|
|
|
+ if (action.metacityTheme.isNotEmpty()) subsection.add(
|
|
|
|
|
+ Prop_MetacityTheme,
|
|
|
|
|
+ action.metacityTheme
|
|
|
|
|
+ )
|
|
|
|
|
+ if (action.iconTheme.isNotEmpty()) subsection.add(Prop_IconTheme, action.iconTheme)
|
|
|
|
|
+ if (action.cursorTheme.isNotEmpty()) subsection.add(Prop_CursorTheme, action.cursorTheme)
|
|
|
|
|
+ if (action.buttonLayout.isNotEmpty()) subsection.add(Prop_ButtonLayout, action.buttonLayout)
|
|
|
|
|
+// subsection.add(Prop_X_Ubuntu_UseOverlayScrollbars, action.useOverlayScrollbars)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (encoding.isNotEmpty()) section.add(Prop_Encoding, encoding)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (file.exists()) {
|
|
|
|
|
+ file.delete()
|
|
|
|
|
+ }
|
|
|
|
|
+ file.createNewFile()
|
|
|
|
|
+ ini.store(file)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- val absolutePath: String
|
|
|
|
|
- get() = file.absolutePath
|
|
|
|
|
|
|
+ class Action(
|
|
|
|
|
+ val text: String = "",
|
|
|
|
|
+ private val data: InputStream = StringBufferInputStream(text),
|
|
|
|
|
+ private val content: Ini? = runCatching { Ini(data) }.getOrNull(),
|
|
|
|
|
+ private val props: Profile.Section? = content?.get("Desktop Entry")
|
|
|
|
|
+ ) {
|
|
|
|
|
+ var type: DesktopFileType = DesktopFileType(props?.get(Prop_Type))
|
|
|
|
|
+ var version: String = ParsedString(props?.get(Prop_Version))
|
|
|
|
|
+ var name: String = ParsedString(props?.get(Prop_Name))
|
|
|
|
|
+ var comment: String = ParsedString(props?.get(Prop_Comment))
|
|
|
|
|
+ var path: String = ParsedString(props?.get(Prop_Path))
|
|
|
|
|
+ var exec: String = ParsedString(props?.get(Prop_Exec))
|
|
|
|
|
+ var icon: String = ParsedString(props?.get(Prop_Icon))
|
|
|
|
|
+ var categories: MutableList<String> = ParsedList(props?.get(Prop_Categories))
|
|
|
|
|
+ var notifyOnStart: Boolean = ParsedBoolean(props?.get(Prop_StartupNotify))
|
|
|
|
|
+ var runInTerminal: Boolean = ParsedBoolean(props?.get(Prop_Terminal))
|
|
|
|
|
+ var encoding: String = ParsedString(props?.get(Prop_Encoding))
|
|
|
|
|
+ var gtkTheme: String = ParsedString(props?.get(Prop_GtkTheme))
|
|
|
|
|
+ var metacityTheme: String = ParsedString(props?.get(Prop_MetacityTheme))
|
|
|
|
|
+ var iconTheme: String = ParsedString(props?.get(Prop_IconTheme))
|
|
|
|
|
+ var cursorTheme: String = ParsedString(props?.get(Prop_CursorTheme))
|
|
|
|
|
+ var buttonLayout: String = ParsedString(props?.get(Prop_ButtonLayout))
|
|
|
|
|
+// var useOverlayScrollbars: Boolean = ParsedBoolean(props?.get(Prop_X_Ubuntu_UseOverlayScrollbars))
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
enum class DesktopFileType(
|
|
enum class DesktopFileType(
|
|
|
- val header: String
|
|
|
|
|
|
|
+ val text: String
|
|
|
) {
|
|
) {
|
|
|
Unknown(""),
|
|
Unknown(""),
|
|
|
|
|
+ DesktopEntry("Desktop Entry"),
|
|
|
Application("Application"),
|
|
Application("Application"),
|
|
|
Theme("X-GNOME-Metatheme");
|
|
Theme("X-GNOME-Metatheme");
|
|
|
|
|
|
|
@@ -62,7 +135,7 @@ class DesktopFile(
|
|
|
operator fun invoke(
|
|
operator fun invoke(
|
|
|
value: String?
|
|
value: String?
|
|
|
): DesktopFileType = value.orEmpty().trim().let { v ->
|
|
): DesktopFileType = value.orEmpty().trim().let { v ->
|
|
|
- entries.firstOrNull { e -> e.header.contentEquals(v, true) } ?: Unknown
|
|
|
|
|
|
|
+ entries.firstOrNull { e -> e.text.contentEquals(v, true) } ?: Unknown
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -82,17 +155,19 @@ class DesktopFile(
|
|
|
const val Prop_MimeType = "MimeType" // string delimited ;
|
|
const val Prop_MimeType = "MimeType" // string delimited ;
|
|
|
const val Prop_Actions = "Actions"
|
|
const val Prop_Actions = "Actions"
|
|
|
const val Prop_DBusActivatable = "DBusActivatable"
|
|
const val Prop_DBusActivatable = "DBusActivatable"
|
|
|
|
|
+ const val Prop_Encoding = "Encoding"
|
|
|
|
|
|
|
|
const val Prop_X_GNOME_UsesNotifications = "X-GNOME-UsesNotifications"
|
|
const val Prop_X_GNOME_UsesNotifications = "X-GNOME-UsesNotifications"
|
|
|
const val Prop_X_Purism_FormFactor = "X-Purism-FormFactor"
|
|
const val Prop_X_Purism_FormFactor = "X-Purism-FormFactor"
|
|
|
const val Prop_X_Unity_IconBackgroundColor = "X-Unity-IconBackgroundColor"
|
|
const val Prop_X_Unity_IconBackgroundColor = "X-Unity-IconBackgroundColor"
|
|
|
const val Prop_X_Ubuntu_Gettext_Domain = "X-Ubuntu-Gettext-Domain"
|
|
const val Prop_X_Ubuntu_Gettext_Domain = "X-Ubuntu-Gettext-Domain"
|
|
|
|
|
|
|
|
- private fun String.asBoolean(): Boolean = when (this.lowercase()) {
|
|
|
|
|
- "true" -> true
|
|
|
|
|
- "1" -> true
|
|
|
|
|
- else -> false
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const val Prop_GtkTheme = "GtkTheme"
|
|
|
|
|
+ const val Prop_MetacityTheme = "MetacityTheme"
|
|
|
|
|
+ const val Prop_IconTheme = "IconTheme"
|
|
|
|
|
+ const val Prop_CursorTheme = "CursorTheme"
|
|
|
|
|
+ const val Prop_ButtonLayout = "ButtonLayout"
|
|
|
|
|
+ const val Prop_X_Ubuntu_UseOverlayScrollbars = "X-Ubuntu-UseOverlayScrollbars"
|
|
|
|
|
|
|
|
fun create(path: String): DesktopFile = create(File(path).apply {
|
|
fun create(path: String): DesktopFile = create(File(path).apply {
|
|
|
if (!exists()) createNewFile()
|
|
if (!exists()) createNewFile()
|