129 lines
5.2 KiB
Python
129 lines
5.2 KiB
Python
from .Module import Module as _Module
|
|
import locale as _locale
|
|
import subprocess as _subprocess
|
|
import shlex as _shlex
|
|
from pathlib import Path as _Path
|
|
from os import listdir as _listdir
|
|
from os.path import isfile as _isfile, join as _join
|
|
|
|
|
|
class Application(_Module):
|
|
|
|
def __init__(self):
|
|
self.db_type = "Application"
|
|
self._home = str(_Path.home())
|
|
self._lang = _locale.getlocale()[0].split("_")[0].strip()
|
|
self._dirs = ["/usr/share/applications", self._home + "/.local/share/applications"]
|
|
self._references = {}
|
|
|
|
def build_db(self):
|
|
"""Function which adds entries to the database.
|
|
returns dict with:
|
|
Name, json, disabled, type, "file" """
|
|
db = {}
|
|
for d in self._dirs:
|
|
for fi in _listdir(d):
|
|
if _isfile(_join(d, fi)):
|
|
fc = self._scan_file(_join(d, fi))
|
|
for k, v in fc.items():
|
|
db.update({k: {
|
|
"Name": k,
|
|
"json": v,
|
|
"disabled": (("NoDisplay" in v and v["NoDisplay"] == "true") or
|
|
("Hidden" in v and v["Hidden"] == "true")),
|
|
"file": v['file'],
|
|
"type": self.db_type
|
|
}})
|
|
return db
|
|
|
|
def update_db(self, database: dict):
|
|
"""Function which updates entries in the database.
|
|
returns dict with modified/deleted/added database entries"""
|
|
entries = self.build_db()
|
|
dbremove = []
|
|
# dbKey == id, dbValue dict of fileds
|
|
for dbKey, dbValue in database:
|
|
if dbValue["type"] == self.db_type:
|
|
if dbValue["Name"] not in entries:
|
|
dbremove.append(dbKey)
|
|
else:
|
|
# update all values managed by this module
|
|
for k, v in entries[dbValue["Name"]]:
|
|
dbValue[k] = v
|
|
# remove no more existing entries
|
|
for i in dbremove:
|
|
database.pop(i)
|
|
return database
|
|
|
|
def build_menu(self, items: dict):
|
|
"""Builds the menu entries.
|
|
return list of tuples (id, name, hits)"""
|
|
# we only get entries of our app type so no problem here
|
|
# json is already unjsonified
|
|
NAME_PREFIX="run "
|
|
NAME_POSTFIX=" (%PATH%)"
|
|
entries = []
|
|
for r in items:
|
|
identifier=(NAME_PREFIX + r['Name'] + NAME_POSTFIX).replace("%PATH%", r['json']['Exec'])
|
|
entries.append((r['ID'], identifier, r['hits']))
|
|
if ("Terminal" not in r["json"]):
|
|
r['json']["Terminal"] = "false"
|
|
self._references[identifier] = (r['json']["Exec"], r['json']["Terminal"], r['file'], r['Name'])
|
|
|
|
return entries
|
|
|
|
def call(self, cmd: str):
|
|
"""Handles the selected entry"""
|
|
# find the entry
|
|
reference = list(filter(lambda x: cmd.startswith(x), self._references.keys()))
|
|
entry = reference[0]
|
|
cmd = cmd.replace(entry, "").lstrip()
|
|
# Just call the program
|
|
_subprocess.Popen(_shlex.split(self._expand_fieldcodes(self._references[entry][0], cmd, reference)),
|
|
encoding="utf-8",
|
|
shell=(self._references[entry][1] == "true"))
|
|
|
|
def _scan_file(self, fi):
|
|
entries = {}
|
|
with open(fi, encoding="utf-8", mode="r") as f:
|
|
data = {}
|
|
for line in f:
|
|
line = line.strip()
|
|
if line.startswith("["): # and line.rstrip() != "[Desktop Entry]":
|
|
data["header"] = line.strip("[]")
|
|
if "Name" in data and "Exec" in data:
|
|
data['file'] = fi
|
|
entries[data["Name"]] = data
|
|
data = {}
|
|
if "=" in line:
|
|
s = line.split("=")
|
|
if "[" in s[0] and "]" in s[0]:
|
|
if "[" + self._lang + "]" in s[0]:
|
|
data[s[0].replace("[" + self._lang + "]", "").strip()] = s[1]
|
|
elif s[0] != "Name" or "Name" not in data.keys():
|
|
data[s[0]] = s[1]
|
|
|
|
if "Name" in data:
|
|
data['file'] = fi
|
|
entries[data["Name"]] = data
|
|
return entries
|
|
|
|
def _expand_fieldcodes(self, entry: str, cmd: str, reference):
|
|
fieldcodes = ['%f', '%F', '%u', '%U', '%i', '%c', '%k'] # todo implement %i as expand icon-key
|
|
for fc in range(0, len(fieldcodes)):
|
|
fieldcodes[fc] = fieldcodes[fc] in entry
|
|
if True in fieldcodes:
|
|
if '%k' in entry:
|
|
entry = entry.replace('%k', '"' + reference[2] + "'")
|
|
if '%c' in entry:
|
|
entry = entry.replace('%c', '"' + reference[3] + "'")
|
|
if '%i' in entry:
|
|
entry = entry.replace(' %i', "")
|
|
if '%f' in entry or '%F' in entry or '%u' in entry or '%U' in entry:
|
|
entry = entry.replace('%f', cmd)
|
|
entry = entry.replace('%F', cmd)
|
|
entry = entry.replace('%u', cmd)
|
|
entry = entry.replace('%U', cmd)
|
|
cmd = ""
|
|
return (entry + " " + cmd).rstrip()
|