Compare commits

...

24 Commits

Author SHA1 Message Date
DYefremov
cf6fc09a20 fix dnd 2021-04-30 10:38:25 +03:00
DYefremov
e3df33e50f archives extraction fix 2021-04-28 20:49:30 +03:00
DYefremov
cece51e069 README update 2021-04-28 18:08:07 +03:00
DYefremov
cb6fbb5107 builder creation refactoring 2021-04-28 14:58:16 +03:00
DYefremov
8329149b1f code adaptation 2021-04-28 10:37:35 +03:00
DYefremov
137ee213dc Merge branch 'development-mac' into experimental-win
# Conflicts:
#	app/tools/media.py
#	app/ui/app_menu_bar.ui
#	app/ui/main_app_window.py
#	app/ui/main_window.glade
#	app/ui/settings_dialog.py
2021-04-26 10:57:45 +03:00
DYefremov
a34798f215 some gui corrections 2021-04-07 23:24:52 +03:00
DYefremov
d6738826d3 playback adaptation 2021-04-07 12:41:33 +03:00
DYefremov
a437ec6030 copy de *.mo file 2021-04-06 23:06:45 +03:00
Thomas Schmidt
9cc8605994 Update german translation 2021-04-06 23:06:38 +03:00
DYefremov
a972ee353f minor fixes 2021-04-06 23:06:10 +03:00
DYefremov
be2d64e480 sid value fix for some picons 2021-04-03 22:16:02 +03:00
DYefremov
76e732c8a0 fixed width for provider name 2021-04-03 22:15:58 +03:00
DYefremov
e81e13a5c0 minor fixes 2021-04-03 00:08:56 +03:00
DYefremov
5b12777223 Merge branch 'development-mac' into experimental-win
# Conflicts:
#	DemonEditor.spec
#	app/tools/media.py
#	app/ui/dialogs.glade
#	app/ui/main_app_window.py
#	app/ui/main_window.glade
#	app/ui/satellites_dialog.glade
#	app/ui/settings_dialog.glade
#	app/ui/settings_dialog.py
#	app/ui/uicommons.py
2021-04-02 21:51:05 +03:00
DYefremov
653ef1422f some minor fixes 2021-03-06 14:32:33 +03:00
DYefremov
5f79b27daa streams playback improvements 2021-03-01 13:07:58 +03:00
DYefremov
3b23ddc1a7 setting encoding for file opening 2021-02-28 21:22:22 +03:00
DYefremov
a0e3566bec enabled language selection 2021-02-28 17:05:28 +03:00
DYefremov
1cada0408f appending providers fix 2021-02-26 13:11:19 +03:00
DYefremov
e1a5b8e39d reworking of built-in player [GStreamer support] 2021-02-26 12:36:19 +03:00
DYefremov
a46c6ae816 keyboard codes adaptation 2021-02-26 08:50:36 +03:00
DYefremov
33137ee879 basic adaptation of the code and gui 2021-02-25 11:45:29 +03:00
DYefremov
51181057b1 adaptation to Python 3.4 2021-02-23 11:10:06 +03:00
46 changed files with 532 additions and 759 deletions

View File

@@ -1,16 +1,12 @@
import os
import datetime
import distutils.util
# -*- mode: python ; coding: utf-8 -*-
EXE_NAME = 'start.py'
DIR_PATH = os.getcwd()
COMPILING_PLATFORM = distutils.util.get_platform()
PATH_EXE = [os.path.join(DIR_PATH, EXE_NAME)]
STRIP = True
BUILD_DATE = datetime.datetime.now().strftime("%Y%m%d")
block_cipher = None
excludes = ['app.tools.mpv',
'gi.repository.Gst',
'gi.repository.GstBase',
@@ -18,57 +14,44 @@ excludes = ['app.tools.mpv',
'youtube_dl',
'tkinter']
ui_files = [('app/ui/*.glade', 'ui'),
('app/ui/*.css', 'ui'),
('app/ui/*.ui', 'ui'),
('app/ui/lang*', 'share/locale'),
('app/ui/icons*', 'share/icons')
ui_files = [('app\\ui\\*.glade', 'ui'),
('app\\ui\\*.css', 'ui'),
('app\\ui\\*.ui', 'ui'),
('app\\ui\\lang*', 'share\\locale'),
('app\\ui\\icons*', 'share\\icons')
]
a = Analysis([EXE_NAME],
pathex=PATH_EXE,
binaries=None,
binaries=[],
datas=ui_files,
hiddenimports=['fileinput', 'uuid'],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=excludes,
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
pyz = PYZ(a.pure,
a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='DemonEditor',
debug=False,
strip=STRIP,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False)
console=False, icon='icon.ico')
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=STRIP,
strip=False,
upx=True,
upx_exclude=[],
name='DemonEditor')
app = BUNDLE(coll,
name='DemonEditor.app',
icon='icon.icns',
bundle_identifier=None,
info_plist={
'NSPrincipalClass': 'NSApplication',
'CFBundleName': 'DemonEditor',
'CFBundleDisplayName': 'DemonEditor',
'CFBundleGetInfoString': "Enigma2 channel and satellites editor",
'LSApplicationCategoryType': 'public.app-category.utilities',
'CFBundleShortVersionString': "1.0.7 Beta (Build: {})".format(BUILD_DATE),
'NSHumanReadableCopyright': u"Copyright © 2021, Dmitriy Yefremov",
'NSRequiresAquaSystemAppearance': 'false'
})

View File

@@ -1,8 +1,8 @@
# <img src="app/ui/icons/hicolor/96x96/apps/demon-editor.png" width="32" /> DemonEditor
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) ![platform](https://img.shields.io/badge/platform-macos-lightgrey)
## Enigma2 channel and satellite list editor for macOS (experimental).
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) ![platform](https://img.shields.io/badge/platform-windows-lightgrey)
## Enigma2 channel and satellite list editor for MS Windows (experimental).
![Main app window in macOS Big Sur.](https://user-images.githubusercontent.com/7511379/92320982-9b20c780-f02e-11ea-8a43-fc0c70503573.png)
[<img src="https://user-images.githubusercontent.com/7511379/116426009-6bd3fa80-a84b-11eb-81ea-3407396a0c4b.png" width="850"/>](https://user-images.githubusercontent.com/7511379/116426009-6bd3fa80-a84b-11eb-81ea-3407396a0c4b.png)
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc).
@@ -18,65 +18,40 @@ Focused on the convenience of working in lists from the keyboard. The mouse is a
* Import to bouquet(Neutrino WEBTV) from m3u.
* Export of bouquets with IPTV services in m3u.
* Assignment of EPGs from DVB or XML for IPTV services (only Enigma2, experimental).
* Preview (playback) of IPTV or other streams directly from the bouquet list (should be installed [VLC](https://www.videolan.org/vlc/)).
* Preview (playback) of IPTV or other streams directly from the bouquet list.
* Control panel with the ability to view EPG and manage timers (via HTTP API, experimental).
* Simple FTP client (experimental).
#### Keyboard shortcuts
* **&#8984; + X** - only in bouquet list.
* **&#8984; + C** - only in services list.
Clipboard is **"rubber"**. There is an accumulation before the insertion!
* **&#8984; + E** - edit.
* **&#8984; + R, F2** - rename.
* **&#8984; + S, T** in Satellites edit tool for create satellite or transponder.
* **&#8984; + L** - parental lock.
* **&#8984; + H** - hide/skip.
* **&#8984; + P** - start play IPTV or other stream in the bouquet list.
* **&#8984; + Z** - switch(**zap**) the channel(works when the HTTP API is enabled, Enigma2 only).
* **&#8984; + W** - switch to the channel and watch in the program.
* **&#8984; + Up/Down** - move selected items in the list.
* **&#8984; + O** - (re)load user data from current dir.
* **&#8984; + D** - load data from receiver.
* **&#8984; + U/B** - upload data/bouquets to receiver.
* **&#8984; + F** - show/hide search bar.
* **&#8679; + &#8984; + F** - show/hide filter bar.
* **Left/Right** - remove selection.
#### Keyboard shortcuts
* **Ctrl + X** - only in bouquet list.
* **Ctrl + C** - only in services list.
Clipboard is **"rubber"**. There is an accumulation before the insertion!
* **Ctrl + Insert** - copies the selected channels from the main list to the bouquet
beginning or inserts (creates) a new bouquet.
* **Ctrl + BackSpace** - copies the selected channels from the main list to the bouquet end.
* **Ctrl + E** - edit.
* **Ctrl + R, F2** - rename.
* **Ctrl + S, T** in Satellites edit tool for create satellite or transponder.
* **Ctrl + L** - parental lock.
* **Ctrl + H** - hide/skip.
* **Ctrl + P** - start play IPTV or other stream in the bouquet list.
* **Ctrl + Z** - switch(**zap**) the channel(works when the HTTP API is enabled, Enigma2 only).
* **Ctrl + W** - switch to the channel and watch in the program.
* **Space** - select/deselect.
* **Left/Right** - remove selection.
* **Ctrl + Up, Down, PageUp, PageDown, Home, End**- move selected items in the list.
* **Ctrl + O** - (re)load user data from current dir.
* **Ctrl + D** - load data from receiver.
* **Ctrl + U/B** - upload data/bouquets to receiver.
* **Ctrl + I** - extra info, details.
* **Ctrl + F** - show/hide search bar.
* **Ctrl + Shift + F** - show/hide filter bar.
For **multiple** selection with the mouse, press and hold the **&#8984;** key!
For **multiple** selection with the mouse, press and hold the **Ctrl** key!
## Minimum requirements
*Python >= 3.5.2, GTK+ >= 3.16 with PyGObject bindings, python3-requests.*
*Python >= 3.5.2, GTK+ >= 3.22 with PyGObject bindings, python3-requests.*
## Installation and Launch
To run the program on macOS, you need to install [brew](https://brew.sh/).
Then install the required components via terminal:
```brew install python3 gtk+3 pygobject3 adwaita-icon-theme```
```pip3 install requests```
#### Optional:
```brew install wget```
```pip3 install pillow, pyobjc```
To start the program, just download the [archive](https://github.com/DYefremov/DemonEditor/archive/experimental-mac.zip), unpack and run it from the terminal
with the command: ```./start.py```
## Standalone package
You can also download the ready-made package as a ***.dmg** file from the [releases](https://github.com/DYefremov/DemonEditor/releases) page.
Recommended copy the package to the **Application** directory.
Perhaps in the security settings it will be necessary to allow the launch of this application!
**The package may not contain all the latest changes. Not all features can be supported and tested!**
THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY.
AUTHOR IS NOT LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY CONNECTION WITH THIS SOFTWARE.
The package may contain components distributed under the GPL [v3](http://www.gnu.org/licenses/gpl-3.0.html) or lower license.
By downloading and using this package you agree to the terms of this [license](http://www.gnu.org/licenses/gpl-3.0.html) and the possible inconvenience associated with this!
#### Building your own package
Install [PyInstaller](https://www.pyinstaller.org/) with the command from the terminal:
```pip3 install pyinstaller```
and in the root dir run command:
```pyinstaller DemonEditor.spec```
## Important
**This version is not fully tested and has experimental status!**
@@ -88,6 +63,7 @@ When using the multiple import feature, from *lamedb* will be taken data **only
If you need full set of the data, including *[satellites, terrestrial, cables].xml* (current files will be overwritten),
just load your data via *"File/Open"* and press *"Save"*. When importing separate bouquet files, only those services
(excluding IPTV) that are in the **current open lamedb** (main list of services) will be imported.
#### Command line arguments:
* **-l** - write logs to file.
* **-d on/off** - turn on/off debug mode. Allows to display more information in the logs.

View File

@@ -67,7 +67,7 @@ def run_with_delay(timeout=5):
timer.cancel()
def run():
GLib.idle_add(func, *args, **kwargs, priority=GLib.PRIORITY_LOW)
GLib.idle_add(func, priority=GLib.PRIORITY_LOW, *args, **kwargs)
timer = Timer(interval=timeout, function=run)
timer.start()

View File

@@ -6,7 +6,6 @@ import urllib
import xml.etree.ElementTree as ETree
from enum import Enum
from ftplib import FTP, CRLF, Error, error_perm
from http.client import RemoteDisconnected
from telnetlib import Telnet
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
@@ -654,7 +653,7 @@ def get_response(req_type, url, data=None):
if req_type is HttpAPI.Request.TEST:
raise e
return {"error_code": e.code}
except (URLError, RemoteDisconnected, ConnectionResetError) as e:
except (URLError, ConnectionResetError) as e:
if req_type is HttpAPI.Request.TEST:
raise e
except ETree.ParseError as e:
@@ -713,7 +712,7 @@ def test_http(host, port, user, password, timeout=5, use_ssl=False, skip_message
try:
return get_response(HttpAPI.Request.TEST, "{}/web/{}".format(base_url, params), data).get("e2statetext", "")
except (RemoteDisconnected, URLError, HTTPError) as e:
except (URLError, HTTPError) as e:
raise TestException(e)

View File

@@ -9,14 +9,15 @@ __FILE_NAME = "blacklist"
def get_blacklist(path):
with suppress(FileNotFoundError):
with open(path + __FILE_NAME, "r") as file:
with open(path + __FILE_NAME, "r", encoding="utf-8") as file:
# filter empty values and "\n"
return {*list(filter(None, (x.strip() for x in file.readlines())))}
return {}
return set(filter(None, (x.strip() for x in file.readlines())))
return set()
def write_blacklist(path, channels):
with open(path + __FILE_NAME, "w") as file:
with open(path + __FILE_NAME, "w", encoding="utf-8") as file:
if channels:
file.writelines("\n".join(channels))

View File

@@ -283,7 +283,7 @@ class LameDbWriter:
def write(self):
if self._fmt == 4:
# Writing lamedb file ver.4
with open(self._path + _FILE_NAME, "w") as file:
with open(self._path + _FILE_NAME, "w", encoding="utf-8") as file:
file.writelines(LameDbReader.get_services_lines(self._services))
elif self._fmt == 5:
self.write_to_lamedb5()
@@ -308,7 +308,7 @@ class LameDbWriter:
lines.extend(services_lines)
lines.append(_END_LINE)
with open(self._path + "lamedb5", "w") as file:
with open(self._path + "lamedb5", "w", encoding="utf-8") as file:
file.writelines(lines)

View File

@@ -68,7 +68,8 @@ def parse_m3u(path, s_type, detect_encoding=True, params=None):
groups.add(grp_name)
fav_id = MARKER_FORMAT.format(marker_counter, grp_name, grp_name)
marker_counter += 1
mr = Service(None, None, None, grp_name, *aggr[0:3], BqServiceType.MARKER.name, *aggr, fav_id, None)
mr = Service(None, None, None, grp_name, None, None, None, BqServiceType.MARKER.name, None, None,
None, None, None, None, None, None, None, None, fav_id, None)
services.append(mr)
elif line.startswith("#EXTGRP") and s_type is SettingsType.ENIGMA_2:
grp_name = line.strip("#EXTGRP:").strip()
@@ -76,7 +77,8 @@ def parse_m3u(path, s_type, detect_encoding=True, params=None):
groups.add(grp_name)
fav_id = MARKER_FORMAT.format(marker_counter, grp_name, grp_name)
marker_counter += 1
mr = Service(None, None, None, grp_name, *aggr[0:3], BqServiceType.MARKER.name, *aggr, fav_id, None)
mr = Service(None, None, None, grp_name, None, None, None, BqServiceType.MARKER.name, None, None,
None, None, None, None, None, None, None, None, fav_id, None)
services.append(mr)
elif not line.startswith("#"):
url = line.strip()
@@ -84,7 +86,8 @@ def parse_m3u(path, s_type, detect_encoding=True, params=None):
sid_counter += 1
fav_id = get_fav_id(url, name, s_type, params)
if all((name, url, fav_id)):
srv = Service(None, None, IPTV_ICON, name, *aggr[0:3], st, picon, p_id, *s_aggr, url, fav_id, None)
srv = Service(None, None, IPTV_ICON, name, None, None, None, st, picon, p_id, None, None, None,
None, None, None, None, url, fav_id, None)
services.append(srv)
else:
log("*.m3u* parse error ['{}']: name[{}], url[{}], fav id[{}]".format(path, name, url, fav_id))
@@ -120,7 +123,9 @@ def get_fav_id(url, service_name, settings_type, params=None, stream_type=None,
if settings_type is SettingsType.ENIGMA_2:
stream_type = stream_type or StreamType.NONE_TS.value
params = params or (0, 0, 0, 0)
return ENIGMA2_FAV_ID_FORMAT.format(stream_type, s_type, *params, quote(url), service_name, service_name, None)
v1, v2, v3, v4 = params
return ENIGMA2_FAV_ID_FORMAT.format(stream_type, s_type, v1, v2, v3, v4, quote(url),
service_name, service_name, None)
elif settings_type is SettingsType.NEUTRINO_MP:
return NEUTRINO_FAV_ID_FORMAT.format(url, "", 0, None, None, None, None, "", "", 1)

View File

@@ -5,16 +5,17 @@ import os
import sys
from enum import Enum, IntEnum
from functools import lru_cache
from pathlib import Path
from pprint import pformat
from textwrap import dedent
HOME_PATH = str(Path.home())
CONFIG_PATH = HOME_PATH + "/.config/demon-editor/"
SEP = os.sep
HOME_PATH = os.path.expanduser("~")
CONFIG_PATH = HOME_PATH + "{}.config{}demon-editor{}".format(SEP, SEP, SEP)
CONFIG_FILE = CONFIG_PATH + "config.json"
DATA_PATH = HOME_PATH + "/DemonEditor/data/"
DATA_PATH = HOME_PATH + "{}DemonEditor{}data{}".format(SEP, SEP, SEP)
IS_DARWIN = sys.platform == "darwin"
IS_WIN = sys.platform == "win32"
class Defaults(Enum):
@@ -24,7 +25,7 @@ class Defaults(Enum):
BACKUP_BEFORE_SAVE = True
V5_SUPPORT = False
FORCE_BQ_NAMES = False
HTTP_API_SUPPORT = False
HTTP_API_SUPPORT = IS_WIN
ENABLE_YT_DL = False
ENABLE_SEND_TO = False
USE_COLORS = True
@@ -34,18 +35,18 @@ class Defaults(Enum):
LIST_PICON_SIZE = 32
FAV_CLICK_MODE = 0
PLAY_STREAMS_MODE = 1 if IS_DARWIN else 0
STREAM_LIB = "vlc"
STREAM_LIB = "mpv" if IS_WIN else "vlc"
PROFILE_FOLDER_DEFAULT = False
RECORDS_PATH = DATA_PATH + "records/"
RECORDS_PATH = DATA_PATH + "records{}".format(SEP)
ACTIVATE_TRANSCODING = False
ACTIVE_TRANSCODING_PRESET = "720p TV/device"
ACTIVE_TRANSCODING_PRESET = "720p TV{}device".format(SEP)
def get_settings():
if not os.path.isfile(CONFIG_FILE) or os.stat(CONFIG_FILE).st_size == 0:
write_settings(get_default_settings())
with open(CONFIG_FILE, "r") as config_file:
with open(CONFIG_FILE, "r", encoding="utf-8") as config_file:
return json.load(config_file)
@@ -79,18 +80,18 @@ def get_default_transcoding_presets():
def write_settings(config):
os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True)
with open(CONFIG_FILE, "w") as config_file:
with open(CONFIG_FILE, "w", encoding="utf-8") as config_file:
json.dump(config, config_file, indent=" ")
def set_local_paths(settings, profile_name, data_path=DATA_PATH, use_profile_folder=False):
settings["data_local_path"] = "{}{}/".format(data_path, profile_name)
settings["data_local_path"] = "{}{}{}".format(data_path, profile_name, SEP)
if use_profile_folder:
settings["picons_local_path"] = "{}{}/{}/".format(data_path, profile_name, "picons")
settings["backup_local_path"] = "{}{}/{}/".format(data_path, profile_name, "backup")
settings["picons_local_path"] = "{}{}{}{}{}".format(data_path, profile_name, SEP, "picons", SEP)
settings["backup_local_path"] = "{}{}{}{}{}".format(data_path, profile_name, SEP, "backup", SEP)
else:
settings["picons_local_path"] = "{}{}/{}/".format(data_path, "picons", profile_name)
settings["backup_local_path"] = "{}{}/{}/".format(data_path, "backup", profile_name)
settings["picons_local_path"] = "{}{}{}{}{}".format(data_path, "picons", SEP, profile_name, SEP)
settings["backup_local_path"] = "{}{}{}{}{}".format(data_path, "backup", SEP, profile_name, SEP)
class SettingsType(IntEnum):
@@ -100,28 +101,29 @@ class SettingsType(IntEnum):
def get_default_settings(self):
""" Returns default settings for current type """
if self is self.ENIGMA_2:
if self is SettingsType.ENIGMA_2:
return {"setting_type": self.value,
"host": "127.0.0.1", "port": "21", "timeout": 5,
"user": "root", "password": "root",
"http_port": "80", "http_timeout": 5, "http_use_ssl": False,
"telnet_port": "23", "telnet_timeout": 5,
"services_path": "/etc/enigma2/", "user_bouquet_path": "/etc/enigma2/",
"satellites_xml_path": "/etc/tuxbox/", "data_local_path": DATA_PATH + "enigma2/",
"satellites_xml_path": "/etc/tuxbox/", "data_local_path": "{}enigma2{}".format(DATA_PATH, SEP),
"picons_path": "/usr/share/enigma2/picon/",
"picons_local_path": DATA_PATH + "enigma2/picons/",
"backup_local_path": DATA_PATH + "enigma2/backup/"}
elif self is self.NEUTRINO_MP:
"picons_local_path": "{}enigma2{}picons{}".format(DATA_PATH, SEP, SEP),
"backup_local_path": "{}enigma2{}backup{}".format(DATA_PATH, SEP, SEP)}
elif self is SettingsType.NEUTRINO_MP:
return {"setting_type": self,
"host": "127.0.0.1", "port": "21", "timeout": 5,
"user": "root", "password": "root",
"http_port": "80", "http_timeout": 2, "http_use_ssl": False,
"telnet_port": "23", "telnet_timeout": 1,
"services_path": "/var/tuxbox/config/zapit/", "user_bouquet_path": "/var/tuxbox/config/zapit/",
"satellites_xml_path": "/var/tuxbox/config/", "data_local_path": DATA_PATH + "neutrino/",
"satellites_xml_path": "/var/tuxbox/config/",
"data_local_path": "{}neutrino{}".format(DATA_PATH, SEP),
"picons_path": "/usr/share/tuxbox/neutrino/icons/logo/",
"picons_local_path": DATA_PATH + "neutrino/picons/",
"backup_local_path": DATA_PATH + "neutrino/backup/"}
"picons_local_path": "{}neutrino{}picons{}".format(DATA_PATH, SEP, SEP),
"backup_local_path": "{}neutrino{}backup{}".format(DATA_PATH, SEP, SEP)}
class SettingsException(Exception):
@@ -183,7 +185,7 @@ class Settings:
self._cp_settings[k] = v
def_path = self.default_data_path
def_path += "enigma2/" if self.setting_type is SettingsType.ENIGMA_2 else "neutrino/"
def_path += "enigma2{}".format(SEP) if self.setting_type is SettingsType.ENIGMA_2 else "neutrino{}".format(SEP)
set_local_paths(self._cp_settings, self._current_profile, def_path, self.profile_folder_is_default)
if force_write:
@@ -617,13 +619,8 @@ class Settings:
self._settings["extra_color"] = value
@property
@lru_cache(1)
def dark_mode(self):
import subprocess
cmd = ["defaults", "read", "-g", "AppleInterfaceStyle"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
return "Dark" in str(p[0])
return self._settings.get("dark_mode", False)
@dark_mode.setter
def dark_mode(self, value):
@@ -664,7 +661,7 @@ class Settings:
@property
@lru_cache(1)
def themes_path(self):
return "{}/.themes/".format(HOME_PATH)
return "{}{}.themes{}".format(HOME_PATH, SEP, SEP)
@property
def icon_theme(self):
@@ -677,7 +674,7 @@ class Settings:
@property
@lru_cache(1)
def icon_themes_path(self):
return "{}/.icons/".format(HOME_PATH)
return "{}{}.icons{}".format(HOME_PATH, SEP, SEP)
@property
def is_darwin(self):

View File

@@ -206,11 +206,6 @@ class GstPlayer(Player):
from gi.repository import Gst, GstVideo
# Initialization of GStreamer.
Gst.init(sys.argv)
gtk_sink = Gst.ElementFactory.make("gtksink")
if not gtk_sink:
msg = "GStreamer error: gtksink plugin not installed!"
log(msg)
raise ImportError(msg)
except (OSError, ValueError) as e:
log("{}: Load library error: {}".format(__class__.__name__, e))
raise ImportError("No GStreamer is found. Check that it is installed!")
@@ -225,11 +220,10 @@ class GstPlayer(Player):
self._is_playing = False
self._player = Gst.ElementFactory.make("playbin", "player")
# Initialization of the playback widget.
self._player.set_property("video-sink", gtk_sink)
vid_widget = gtk_sink.get_property("widget")
vid_widget.connect("motion-notify-event", self.on_mouse_motion)
vid_widget = self.get_video_widget(widget)
widget.add(vid_widget)
vid_widget.show()
self._player.set_window_handle(self.get_window_handle(vid_widget))
bus = self._player.get_bus()
bus.add_signal_watch()

View File

@@ -6,12 +6,12 @@ import re
import shutil
import sys
from html.parser import HTMLParser
from json import JSONDecodeError
from urllib.error import URLError
from urllib.parse import unquote
from urllib.request import Request, urlopen, urlretrieve
from app.commons import log
from app.settings import SEP
from app.ui.uicommons import show_notification
_YT_PATTERN = re.compile(r"https://www.youtube.com/.+(?:v=)([\w-]{11}).*")
@@ -100,7 +100,7 @@ class YouTube:
if player_resp:
try:
resp = json.loads(player_resp)
except JSONDecodeError as e:
except Exception as e:
log("{}: Parsing player response error: {}".format(__class__.__name__, e))
else:
det = resp.get("videoDetails", None)
@@ -170,7 +170,7 @@ class PlayListParser(HTMLParser):
try:
resp = json.loads(data)
except JSONDecodeError as e:
except YouTubeException as e:
log("{}: Parsing data error: {}".format(__class__.__name__, e))
else:
sb = resp.get("sidebar", None)
@@ -230,7 +230,7 @@ class YouTubeDL:
"cookiefile": "cookies.txt"} # File name where cookies should be read from and dumped to.
def __init__(self, settings, callback):
self._path = settings.default_data_path + "tools/"
self._path = settings.default_data_path + "tools{}".format(SEP)
self._update = settings.enable_yt_dl_update
self._supported = {"22", "18"}
self._dl = None
@@ -247,7 +247,7 @@ class YouTubeDL:
return cls._DL_INSTANCE
def init(self):
if not os.path.isfile(self._path + "youtube_dl/version.py"):
if not os.path.isfile(self._path + "youtube_dl{}version.py".format(SEP)):
self.get_latest_release()
if self._path not in sys.path:
@@ -314,7 +314,7 @@ class YouTubeDL:
os.makedirs(os.path.dirname(self._path), exist_ok=True)
for info in arch.infolist():
pref, sep, f = info.filename.partition("/youtube_dl/")
pref, sep, f = info.filename.partition("{}youtube_dl{}".format(SEP, SEP))
if sep:
arch.extract(info.filename)
shutil.move(info.filename, "{}{}{}".format(self._path, sep, f))

View File

@@ -1,25 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="app-menu">
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.on_about_app</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Settings</attribute>
<attribute name="action">app.on_settings</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Exit</attribute>
<attribute name="action">app.on_close_app</attribute>
</item>
</section>
</menu>
<menu id="menu_bar">
<submenu>
<attribute name="label" translatable="yes">File</attribute>
@@ -68,21 +48,33 @@
<attribute name="action">app.on_download</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Settings</attribute>
<attribute name="action">app.on_settings</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Exit</attribute>
<attribute name="action">app.on_close_app</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">Edit</attribute>
<attribute name="action">app.hide_menu_bar</attribute>
<attribute name="hidden-when">action-disabled</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Lock</attribute>
<attribute name="action">app.on_locked</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Hide</attribute>
<attribute name="action">app.on_hide</attribute>
</item>
</section>
<item>
<attribute name="label" translatable="yes">Lock</attribute>
<attribute name="action">app.on_locked</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Hide</attribute>
<attribute name="action">app.on_hide</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">View</attribute>
@@ -166,5 +158,14 @@
<attribute name="action">app.on_ftp_client_close</attribute>
</item>
</submenu>
<submenu>
<attribute name="label" translatable="yes">Help</attribute>
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.on_about_app</attribute>
</item>
</section>
</submenu>
</menu>
</interface>

View File

@@ -8,7 +8,7 @@ from enum import Enum
from app.commons import run_idle
from app.settings import SettingsType
from app.ui.dialogs import show_dialog, DialogType
from app.ui.dialogs import show_dialog, DialogType, get_builder
from app.ui.main_helper import append_text_to_tview
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK
@@ -30,10 +30,7 @@ class BackupDialog:
"on_resize": self.on_resize,
"on_key_release": self.on_key_release}
builder = Gtk.Builder()
builder.set_translation_domain("demon-editor")
builder.add_from_file(UI_RESOURCES_PATH + "backup_dialog.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "backup_dialog.glade", handlers)
self._settings = settings
self._s_type = settings.setting_type

View File

@@ -57,7 +57,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_restore_bouquets" swapped="no"/>
<accelerator key="r" signal="activate" modifiers="Primary"/>
<accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -67,7 +67,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_restore_all" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -115,7 +115,6 @@ Author: Dmitriy Yefremov
<property name="window_position">center-on-parent</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">document-revert</property>
<property name="gravity">center</property>
<signal name="check-resize" handler="on_resize" swapped="no"/>
<child>
<placeholder/>
@@ -297,7 +296,7 @@ Author: Dmitriy Yefremov
<property name="always_show_image">True</property>
<property name="draw_indicator">False</property>
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
<accelerator key="i" signal="clicked" modifiers="Primary"/>
<accelerator key="i" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -431,7 +431,9 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="margin_bottom">10</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkButton" id="standby_button">
@@ -1176,7 +1178,7 @@ audio-volume-medium-symbolic</property>
<object class="GtkEntry" id="timer_service_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -1187,7 +1189,7 @@ audio-volume-medium-symbolic</property>
<object class="GtkEntry" id="timer_desc_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -1198,7 +1200,7 @@ audio-volume-medium-symbolic</property>
<object class="GtkEntry" id="timer_name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -1485,7 +1487,7 @@ audio-volume-medium-symbolic</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
</child>
<style>
@@ -1556,7 +1558,7 @@ audio-volume-medium-symbolic</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
</child>
<style>
@@ -1605,7 +1607,7 @@ audio-volume-medium-symbolic</property>
<property name="spacing">5</property>
<child>
<object class="GtkImage" id="timer_location_image">
<property name="visible">True</property>
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="icon_name">document-edit-symbolic</property>
</object>
@@ -1638,7 +1640,7 @@ audio-volume-medium-symbolic</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="placeholder_text" translatable="yes">Default</property>
</object>
<packing>

View File

@@ -6,7 +6,9 @@ from urllib.parse import quote
from gi.repository import GLib
from .dialogs import get_dialogs_string, show_dialog, DialogType, get_message
from app.settings import IS_WIN
from .dialogs import get_builder
from .dialogs import show_dialog, DialogType, get_message
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Column
from ..commons import run_task, run_with_delay, log, run_idle
from ..connections import HttpAPI
@@ -84,8 +86,7 @@ class ControlBox(Gtk.HBox):
self._timer = timer
builder = Gtk.Builder()
builder.add_from_string(get_dialogs_string(self._UI_PATH))
builder = get_builder(self._UI_PATH, None, use_str=True)
row_box = builder.get_object("timer_row_box")
name_label = builder.get_object("timer_name_label")
description_label = builder.get_object("timer_description_label")
@@ -130,9 +131,7 @@ class ControlBox(Gtk.HBox):
"on_timers_press": self.on_timers_press,
"on_timers_drag_data_received": self.on_timers_drag_data_received}
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "control.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "control.glade", handlers)
self.add(builder.get_object("main_box_frame"))
self._stack = builder.get_object("stack")
@@ -313,18 +312,17 @@ class ControlBox(Gtk.HBox):
img = data.get("img_data", None)
if img:
is_darwin = self._settings.is_darwin
GLib.idle_add(self._screenshot_button_box.set_sensitive, is_darwin)
path = os.path.expanduser("~/Desktop") if is_darwin else None
GLib.idle_add(self._screenshot_button_box.set_sensitive, IS_WIN)
path = os.path.expanduser("~/Desktop") if IS_WIN else None
try:
import tempfile
import subprocess
with tempfile.NamedTemporaryFile(mode="wb", suffix=".jpg", dir=path, delete=not is_darwin) as tf:
with tempfile.NamedTemporaryFile(mode="wb", suffix=".jpg", dir=path, delete=not IS_WIN) as tf:
tf.write(img)
cmd = ["open" if is_darwin else "xdg-open", tf.name]
subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
f_name = tf.name
subprocess.Popen([f_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
finally:
GLib.idle_add(self._screenshot_button_box.set_sensitive, True)

View File

@@ -1,43 +0,0 @@
* {
-GtkDialog-action-area-border: 5em;
}
entry {
min-height: 2em;
}
button {
min-height: 1.5em;
padding-left: 0.5em;
padding-right: 0.5em;
padding-top: 0.1em;
padding-bottom: 0.1em;
}
spinbutton {
min-height: 1.5em;
}
toolbutton {
padding: 0.1em;
}
spinner {
padding-left: 1em;
padding-right: 1em;
}
infobar {
min-height: 2em;
}
switch slider {
min-height: 1.5em;
min-width: 1.5em;
}
paned > separator {
background-repeat: no-repeat;
background-position: center;
background-size: 1px 24px;
}

View File

@@ -40,16 +40,16 @@ Author: Dmitriy Yefremov
<property name="icon_name">system-help</property>
<property name="type_hint">normal</property>
<property name="program_name">DemonEditor</property>
<property name="version">1.0.7 Beta</property>
<property name="version">1.0.7 Alpha</property>
<property name="copyright">2018-2021 Dmitriy Yefremov
</property>
<property name="comments" translatable="yes">Enigma2 channel and satellite list editor for MacOS.
(Experimental)</property>
<property name="website">https://github.com/DYefremov/DemonEditor/tree/experimental-mac</property>
</property>
<property name="comments" translatable="yes">Enigma2 channel and satellite list editor for MS Windows.
(Experimental)</property>
<property name="website">https://github.com/DYefremov/DemonEditor/tree/experimental-win</property>
<property name="license" translatable="yes">Это приложение распространяется без каких-либо гарантий.
Подробнее в &lt;a href="http://opensource.org/licenses/mit-license.php"&gt;The MIT License (MIT)&lt;/a&gt;.</property>
Подробнее в &lt;a href="http://opensource.org/licenses/mit-license.php"&gt;The MIT License (MIT)&lt;/a&gt;.</property>
<property name="authors">Dmitriy Yefremov
</property>
</property>
<property name="translator_credits" translatable="yes">translator-credits</property>
<property name="artists">Program logo: &lt;a href="http://ihad.tv"&gt;mfgeg&lt;/a&gt;</property>
<property name="logo_icon_name">demon-editor</property>
@@ -92,7 +92,6 @@ Author: Dmitriy Yefremov
<property name="type_hint">utility</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child type="titlebar">
<placeholder/>
</child>
@@ -126,6 +125,7 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkButton" id="input_dialog_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="width_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -153,7 +153,7 @@ Author: Dmitriy Yefremov
<property name="margin_right">2</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="secondary_icon_sensitive">False</property>
@@ -181,10 +181,6 @@ Author: Dmitriy Yefremov
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="decorated">False</property>
<property name="gravity">center</property>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkBox" id="wait_dialog_box">
<property name="width_request">100</property>
@@ -222,7 +218,7 @@ Author: Dmitriy Yefremov
</packing>
</child>
</object>
</child>
</child> <!-- NOP -->
<style>
<class name="app-notification"/>
</style>

View File

@@ -5,6 +5,7 @@ from functools import lru_cache
from pathlib import Path
from app.commons import run_idle
from app.settings import SEP, IS_WIN
from .uicommons import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN, IS_GNOME_SESSION
@@ -17,12 +18,11 @@ class Dialog(Enum):
<property name="use-header-bar">{use_header}</property>
<property name="can_focus">False</property>
<property name="modal">True</property>
<property name="default_width">320</property>
<property name="width_request">250</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<property name="message_type">{message_type}</property>
<property name="buttons">{buttons_type}</property>
</object>
@@ -104,10 +104,12 @@ def get_chooser_dialog(transient, settings, name, patterns, title=None):
def get_file_chooser_dialog(transient, text, settings, action_type, file_filter, buttons=None, title=None, dirs=False):
text = get_message(text) if text else ""
action_type = Gtk.FileChooserAction.SELECT_FOLDER if action_type is None else action_type
dialog = Gtk.FileChooserNative.new(get_message(title) if title else "", transient, action_type)
buttons = buttons or (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
dialog = Gtk.FileChooserDialog(text, transient, action_type, buttons, use_header_bar=IS_GNOME_SESSION)
dialog.set_title(get_message(title) if title else "")
dialog.set_create_folders(dirs)
dialog.set_modal(True)
if file_filter is not None:
dialog.add_filter(file_filter)
@@ -115,10 +117,10 @@ def get_file_chooser_dialog(transient, text, settings, action_type, file_filter,
dialog.set_current_folder(settings.data_local_path)
response = dialog.run()
if response == Gtk.ResponseType.ACCEPT:
if response not in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
path = Path(dialog.get_filename() or dialog.get_current_folder())
if path.is_dir():
response = "{}/".format(path.resolve())
response = "{}{}".format(path.resolve(), SEP)
elif path.is_file():
response = str(path.resolve())
dialog.destroy()
@@ -179,9 +181,52 @@ def get_message(message):
@lru_cache(maxsize=5)
def get_dialogs_string(path):
with open(path, "r") as f:
with open(path, "r", encoding="utf-8") as f:
return "".join(f)
def get_builder(path, handlers=None, use_str=False, objects=None):
""" Creates and returns a Gtk.Builder instance. """
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
if use_str:
if objects:
builder.add_objects_from_string(get_dialogs_string(path).format(use_header=IS_GNOME_SESSION), objects)
else:
builder.add_from_string(get_dialogs_string(path).format(use_header=IS_GNOME_SESSION))
else:
if objects:
builder.add_objects_from_file(path, objects)
else:
builder.add_from_file(path)
builder.connect_signals(handlers or {})
if IS_WIN:
translate_objects(builder.get_objects())
return builder
def translate_objects(objects):
"""
Used to translate GUI from * .glade files in MS Windows.
More info: https://gitlab.gnome.org/GNOME/gtk/-/issues/569
"""
for o in objects:
if hasattr(o, "get_label"):
label = o.get_label()
if label:
o.set_label(get_message(label))
t_text = o.get_tooltip_text()
if t_text:
o.set_tooltip_text(get_message(t_text))
elif hasattr(o, "get_title"):
title = o.get_title()
if title:
o.set_title(get_message(title))
if __name__ == "__main__":
pass

View File

@@ -55,7 +55,6 @@ Author: Dmitriy Yefremov
<property name="icon_name">mail-send-receive</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child type="titlebar">
<placeholder/>
</child>
@@ -372,7 +371,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Options</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_settings" swapped="no"/>
</object>
<packing>

View File

@@ -8,7 +8,7 @@ from app.settings import SettingsType
from app.ui.backup import backup_data, restore_data
from app.ui.main_helper import append_text_to_tview
from app.ui.settings_dialog import show_settings_dialog
from .dialogs import show_dialog, DialogType, get_message
from .dialogs import show_dialog, DialogType, get_message, get_builder
from .uicommons import Gtk, UI_RESOURCES_PATH
@@ -27,9 +27,7 @@ class DownloadDialog:
"on_remove_unused_bouquets_toggled": self.on_remove_unused_bouquets_toggled,
"on_info_bar_close": self.on_info_bar_close}
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "download_dialog.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "download_dialog.glade", handlers)
self._dialog_window = builder.get_object("download_dialog_window")
self._dialog_window.set_transient_for(transient)

View File

@@ -87,7 +87,7 @@ Author: Dmitriy Yefremov
<property name="image">copy_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_copy_ref" swapped="no"/>
<accelerator key="c" signal="activate" modifiers="Primary"/>
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
</object>
@@ -118,7 +118,7 @@ Author: Dmitriy Yefremov
<property name="image">insert_link_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_assign_ref" swapped="no"/>
<accelerator key="v" signal="activate" modifiers="Primary"/>
<accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -436,7 +436,7 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/data/epg/</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Select</property>
@@ -466,7 +466,7 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/etc/enigma2/</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
</object>
<packing>
@@ -601,7 +601,6 @@ Author: Dmitriy Yefremov
<property name="destroy_with_parent">True</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<signal name="check-resize" handler="on_resize" swapped="no"/>
<signal name="delete-event" handler="on_close_dialog" swapped="no"/>
<child>

View File

@@ -8,13 +8,14 @@ from enum import Enum
from urllib.error import HTTPError, URLError
from gi.repository import GLib
from app.commons import run_idle, run_task
from app.connections import download_data, DownloadType
from app.eparser.ecommons import BouquetService, BqServiceType
from app.tools.epg import EPG, ChannelsParser
from app.ui.dialogs import get_message, show_dialog, DialogType
from app.ui.dialogs import get_message, show_dialog, DialogType, get_builder
from .main_helper import on_popup_menu, update_entry_data
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, Column, EPG_ICON, KeyboardKey, MOD_MASK
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Column, EPG_ICON, KeyboardKey, MOD_MASK
class RefsSource(Enum):
@@ -66,10 +67,7 @@ class EpgDialog:
self._show_tooltips = True
self._download_xml_is_active = False
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_from_file(UI_RESOURCES_PATH + "epg_dialog.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "epg_dialog.glade", handlers)
self._dialog = builder.get_object("epg_dialog_window")
self._dialog.set_transient_for(transient)
@@ -185,7 +183,7 @@ class EpgDialog:
def init_bouquet_data(self):
for r in self._ex_fav_model:
row = [*r[:]]
row = list(r[:])
fav_id = r[Column.FAV_ID]
self._services[fav_id] = self._ex_services[fav_id].fav_id
yield self._bouquet_model.append(row)

View File

@@ -582,7 +582,7 @@ Author: Dmitriy Yefremov
<property name="image">rename_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_ftp_edit" object="ftp_name_column_renderer" swapped="no"/>
<accelerator key="r" signal="activate" modifiers="Primary"/>
<accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="F2" signal="activate"/>
</object>
</child>
@@ -631,7 +631,7 @@ Author: Dmitriy Yefremov
<property name="image">rename_image_2</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_file_edit" object="file_name_column_renderer" swapped="no"/>
<accelerator key="r" signal="activate" modifiers="Primary"/>
<accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="F2" signal="activate"/>
</object>
</child>

View File

@@ -12,7 +12,8 @@ from gi.repository import GLib
from app.commons import log, run_task, run_idle
from app.connections import UtfFTP
from app.ui.dialogs import show_dialog, DialogType
from app.settings import IS_WIN, SEP
from app.ui.dialogs import show_dialog, DialogType, get_builder
from app.ui.main_helper import on_popup_menu
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK
@@ -68,9 +69,7 @@ class FtpClientBox(Gtk.HBox):
"on_view_press": self.on_view_press,
"on_view_release": self.on_view_release}
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "ftp.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "ftp.glade", handlers)
self.add(builder.get_object("main_frame"))
self._ftp_info_label = builder.get_object("ftp_info_label")
@@ -233,22 +232,21 @@ class FtpClientBox(Gtk.HBox):
def open_file(self, path):
GLib.idle_add(self._file_view.set_sensitive, False)
try:
cmd = ["open" if self._settings.is_darwin else "xdg-open", path]
subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
cmd = ["start" if IS_WIN else "xdg-open", path]
subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=IS_WIN).communicate()
finally:
GLib.idle_add(self._file_view.set_sensitive, True)
@run_task
def open_ftp_file(self, f_path):
is_darwin = self._settings.is_darwin
GLib.idle_add(self._ftp_view.set_sensitive, False)
try:
import tempfile
import os
path = os.path.expanduser("~/Desktop") if is_darwin else None
path = os.path.expanduser("~/Desktop") if IS_WIN else None
with tempfile.NamedTemporaryFile(mode="wb", dir=path, delete=not is_darwin) as tf:
with tempfile.NamedTemporaryFile(mode="wb", dir=path, delete=not IS_WIN) as tf:
msg = "Downloading file: {}. Status: {}"
try:
status = self._ftp.retrbinary("RETR " + f_path, tf.write)
@@ -257,8 +255,8 @@ class FtpClientBox(Gtk.HBox):
self.update_ftp_info(msg.format(f_path, e))
tf.flush()
cmd = ["open" if is_darwin else "xdg-open", tf.name]
subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
cmd = ["start" if IS_WIN else "xdg-open", tf.name]
subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=IS_WIN).communicate()
finally:
GLib.idle_add(self._ftp_view.set_sensitive, True)
@@ -429,11 +427,12 @@ class FtpClientBox(Gtk.HBox):
def on_ftp_drag_data_get(self, view, context, data, info, time):
model, paths = view.get_selection().get_selected_rows()
if len(paths) > 0:
sep = self.URI_SEP if self._settings.is_darwin else "\n"
sep = self.URI_SEP if IS_WIN else "\n"
uris = []
for r in [model[p][:] for p in paths]:
if r[self.Column.SIZE] != self.LINK and r[self.Column.NAME] != self.ROOT:
uris.append(Path("/{}:{}".format(r[self.Column.NAME], r[self.Column.ATTR])).as_uri())
path = Path("/{}:{}".format(r[self.Column.NAME], r[self.Column.ATTR]))
uris.append(str(path.resolve()) if IS_WIN else path.as_uri())
data.set_uris([sep.join(uris)])
@run_task
@@ -446,12 +445,12 @@ class FtpClientBox(Gtk.HBox):
GLib.idle_add(self._app._wait_dialog.show)
uris = data.get_uris()
if self._settings.is_darwin and len(uris) == 1:
if IS_WIN and len(uris) == 1:
uris = uris[0].split(self.URI_SEP)
for uri in uris:
uri = urlparse(unquote(uri)).path
path = Path(uri)
uri = urlparse(unquote(uri)).path.strip()
path = Path(uri.lstrip("/") if IS_WIN else uri)
if path.is_dir():
try:
self._ftp.mkd(path.name)
@@ -473,18 +472,18 @@ class FtpClientBox(Gtk.HBox):
def on_file_drag_data_get(self, view, context, data: Gtk.SelectionData, info, time):
model, paths = view.get_selection().get_selected_rows()
if len(paths) > 0:
sep = self.URI_SEP if self._settings.is_darwin else "\n"
sep = self.URI_SEP if IS_WIN else "\n"
uris = [sep.join([Path(model[p][self.Column.ATTR]).as_uri() for p in paths])]
data.set_uris(uris)
@run_task
def on_file_drag_data_received(self, view, context, x, y, data, info, time):
cur_path = self._file_model.get_value(self._file_model.get_iter_first(), self.Column.ATTR) + "/"
cur_path = self._file_model.get_value(self._file_model.get_iter_first(), self.Column.ATTR) + SEP
try:
GLib.idle_add(self._app._wait_dialog.show)
uris = data.get_uris()
if self._settings.is_darwin and len(uris) == 1:
if IS_WIN and len(uris) == 1:
uris = uris[0].split(self.URI_SEP)
for uri in uris:

View File

@@ -101,7 +101,6 @@ Author: Dmitriy Yefremov
<property name="default_height">320</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="gravity">center</property>
<signal name="check-resize" handler="on_resize" swapped="no"/>
<child>
<placeholder/>

View File

@@ -6,7 +6,7 @@ from app.eparser import get_bouquets, get_services, BouquetsReader
from app.eparser.ecommons import BqType, BqServiceType, Bouquet
from app.eparser.neutrino.bouquets import parse_webtv, parse_bouquets as get_neutrino_bouquets
from app.settings import SettingsType
from app.ui.dialogs import show_dialog, DialogType, get_chooser_dialog, get_message
from app.ui.dialogs import show_dialog, DialogType, get_chooser_dialog, get_message, get_builder
from app.ui.main_helper import on_popup_menu
from .uicommons import Gtk, UI_RESOURCES_PATH, KeyboardKey, Column
@@ -84,10 +84,7 @@ class ImportDialog:
"on_resize": self.on_resize,
"on_key_press": self.on_key_press}
builder = Gtk.Builder()
builder.set_translation_domain("demon-editor")
builder.add_from_file(UI_RESOURCES_PATH + "import_dialog.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "import_dialog.glade", handlers)
self._bq_services = {}
self._services = {}
@@ -128,7 +125,7 @@ class ImportDialog:
for bq in bqs.bouquets:
self._main_model.append((bq.name, bq.type, True))
self._bq_services[(bq.name, bq.type)] = bq.services
if self._profile is SettingsType.ENIGMA_2:
services = get_services(path, self._profile, 5 if self._settings.v5_support else 4)
elif self._profile is SettingsType.NEUTRINO_MP:

View File

@@ -75,7 +75,6 @@ Author: Dmitriy Yefremov
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="decorated">False</property>
<property name="gravity">center</property>
<signal name="response" handler="on_response" swapped="no"/>
<child internal-child="vbox">
<object class="GtkBox" id="search_unavailable_dialog_box">
@@ -268,7 +267,6 @@ Author: Dmitriy Yefremov
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<signal name="response" handler="on_response" swapped="no"/>
<child internal-child="vbox">
<object class="GtkBox" id="iptv_list_configuration_dialog_box">
@@ -458,7 +456,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -501,7 +499,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -544,7 +542,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -587,7 +585,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -630,7 +628,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">1</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -919,7 +917,7 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -942,7 +940,7 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -1042,7 +1040,7 @@ Author: Dmitriy Yefremov
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_bottom">5</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Link to YouTube resource.</property>
<signal name="changed" handler="on_url_changed" swapped="no"/>
</object>
@@ -1169,7 +1167,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">1</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1184,7 +1182,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1199,7 +1197,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1214,7 +1212,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1229,7 +1227,7 @@ Author: Dmitriy Yefremov
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1337,7 +1335,6 @@ Author: Dmitriy Yefremov
<property name="destroy_with_parent">True</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child type="titlebar">
<placeholder/>
</child>

View File

@@ -15,10 +15,9 @@ from app.eparser.iptv import (NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID
parse_m3u)
from app.settings import SettingsType
from app.tools.yt import YouTubeException, YouTube
from app.ui.dialogs import Action, show_dialog, DialogType, get_dialogs_string, get_message
from app.ui.dialogs import Action, show_dialog, DialogType, get_message, get_builder
from app.ui.main_helper import get_base_model, get_iptv_url, on_popup_menu, get_picon_pixbuf
from app.ui.uicommons import (Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON, Column, IS_GNOME_SESSION,
KeyboardKey, get_yt_icon)
from app.ui.uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, IPTV_ICON, Column, KeyboardKey, get_yt_icon)
_DIGIT_ENTRY_NAME = "digit-entry"
_ENIGMA2_REFERENCE = "{}:0:{}:{:X}:{:X}:{:X}:{:X}:0:0:0"
@@ -67,11 +66,8 @@ class IptvDialog:
self._yt_links = None
self._yt_dl = None
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION),
("iptv_dialog", "stream_type_liststore", "yt_quality_liststore"))
builder.connect_signals(handlers)
builder = get_builder(_UI_PATH, handlers, use_str=True,
objects=("iptv_dialog", "stream_type_liststore", "yt_quality_liststore"))
self._dialog = builder.get_object("iptv_dialog")
self._dialog.set_transient_for(transient)
@@ -298,14 +294,14 @@ class IptvDialog:
self._bouquet[self._paths[0][0]] = fav_id
self._model.set(self._model.get_iter(self._paths), {Column.FAV_SERVICE: name, Column.FAV_ID: fav_id})
else:
aggr = [None] * 10
s_type = BqServiceType.IPTV.name
srv = (None, None, name, None, None, s_type, None, fav_id, *aggr[0:3])
srv = (None, None, name, None, None, s_type, None, fav_id, None, None, None)
itr = self._model.insert_after(self._model.get_iter(self._paths[0]),
srv) if self._paths else self._model.insert(0, srv)
self._model.set_value(itr, 1, IPTV_ICON)
self._bouquet.insert(self._model.get_path(itr)[0], fav_id)
self._services[fav_id] = Service(None, None, IPTV_ICON, name, *aggr[0:3], s_type, *aggr, fav_id, None)
self._services[fav_id] = Service(None, None, IPTV_ICON, name, None, None, None, s_type, None,
None, None, None, None, None, None, None, None, None, fav_id, None)
@run_idle
def on_info_bar_close(self, bar=None, resp=None):
@@ -323,10 +319,8 @@ class SearchUnavailableDialog:
def __init__(self, transient, model, fav_bouquet, iptv_rows, s_type):
handlers = {"on_response": self.on_response}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_file(UI_RESOURCES_PATH + "iptv.glade", ("search_unavailable_streams_dialog",))
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "iptv.glade", handlers,
objects=("search_unavailable_streams_dialog",))
self._dialog = builder.get_object("search_unavailable_streams_dialog")
self._dialog.set_transient_for(transient)
@@ -421,11 +415,8 @@ class IptvListDialog:
self._s_type = s_type
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION),
("iptv_list_configuration_dialog", "stream_type_liststore"))
builder.connect_signals(handlers)
builder = get_builder(_UI_PATH, handlers, use_str=True,
objects=("iptv_list_configuration_dialog", "stream_type_liststore"))
self._dialog = builder.get_object("iptv_list_configuration_dialog")
self._dialog.set_transient_for(transient)
@@ -813,13 +804,10 @@ class YtListImportDialog:
self._settings = settings
self._yt = None
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION),
("yt_import_dialog_window", "yt_liststore", "yt_quality_liststore",
"yt_popup_menu", "remove_selection_image", "yt_receive_image",
"yt_import_image"))
builder.connect_signals(handlers)
builder = get_builder(_UI_PATH, handlers, use_str=True,
objects=("yt_import_dialog_window", "yt_liststore", "yt_quality_liststore",
"yt_popup_menu", "remove_selection_image", "yt_receive_image",
"yt_import_image"))
self._dialog = builder.get_object("yt_import_dialog_window")
self._dialog.set_transient_for(transient)
@@ -920,13 +908,13 @@ class YtListImportDialog:
@run_idle
def append_services(self, links):
aggr = [None] * 9
srvs = []
if self._yt_list_title:
title = self._yt_list_title
fav_id = MARKER_FORMAT.format(0, title, title)
mk = Service(None, None, None, title, *aggr[0:3], BqServiceType.MARKER.name, *aggr, 0, fav_id, None)
mk = Service(None, None, None, title, None, None, None, BqServiceType.MARKER.name, None,
None, None, None, None, None, None, None, None, 0, fav_id, None)
srvs.append(mk)
act = self._quality_model.get_value(self._quality_box.get_active_iter(), 0)
@@ -936,7 +924,8 @@ class YtListImportDialog:
continue
ln = lnk.get(act) if act in lnk else lnk[sorted(lnk, key=lambda x: int(x.rstrip("p")), reverse=True)[0]]
fav_id = get_fav_id(ln, title, self._s_type)
srv = Service(None, None, IPTV_ICON, title, *aggr[0:3], BqServiceType.IPTV.name, *aggr, None, fav_id, None)
srv = Service(None, None, IPTV_ICON, title, None, None, None, BqServiceType.IPTV.name, None, None, None,
None, None, None, None, None, None, None, fav_id, None)
srvs.append(srv)
self.appender(srvs)

View File

@@ -17,12 +17,12 @@ from app.eparser.ecommons import CAS, Flag, BouquetService
from app.eparser.enigma.bouquets import BqServiceType
from app.eparser.iptv import export_to_m3u
from app.eparser.neutrino.bouquets import BqType
from app.settings import SettingsType, Settings, SettingsException, PlayStreamsMode, SettingsReadException
from app.settings import SettingsType, Settings, SettingsException, PlayStreamsMode, SettingsReadException, IS_WIN
from app.tools.media import Player, Recorder
from app.ui.epg_dialog import EpgDialog
from app.ui.transmitter import LinksTransmitter
from .backup import BackupDialog, backup_data, clear_data_path
from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog, get_message
from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog, get_message, get_builder
from .download_dialog import DownloadDialog
from .imports import ImportDialog, import_bouquet
from .iptv import IptvDialog, SearchUnavailableDialog, IptvListConfigurationDialog, YtListImportDialog, M3uImportDialog
@@ -36,7 +36,7 @@ from .search import SearchProvider
from .service_details_dialog import ServiceDetailsDialog, Action
from .settings_dialog import show_settings_dialog
from .uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS, KeyboardKey, Column,
FavClickMode, MOD_MASK, APP_FONT)
FavClickMode, MOD_MASK, TEXT_DOMAIN, APP_FONT)
class Application(Gtk.Application):
@@ -218,9 +218,7 @@ class Application(Gtk.Application):
self._NEW_COLOR = None # Color for new services in the main list
self._EXTRA_COLOR = None # Color for services with a extra name for the bouquet
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "main_window.glade")
builder.connect_signals(self._handlers)
builder = get_builder(UI_RESOURCES_PATH + "main_window.glade", self._handlers)
self._main_window = builder.get_object("main_window")
main_window_size = self._settings.get("window_size")
# Setting the last size of the window if it was saved
@@ -343,78 +341,25 @@ class Application(Gtk.Application):
style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
self._status_bar_box.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
# Layout
if self._settings.is_darwin and self._settings.alternate_layout:
self._main_paned = builder.get_object("main_data_paned")
self._fav_paned = builder.get_object("fav_bouquets_paned")
self._fav_box = self._fav_paned.get_child1()
self._bouquets_box = self._fav_paned.get_child2()
self._left_ar_bq_button = builder.get_object("left_arrow_bq_button")
self._left_ar_bq_button.bind_property("visible", builder.get_object("right_arrow_bq_button"), "visible", 4)
self._left_ar_bq_button.set_visible(True)
self.init_layout(builder)
def init_layout(self, builder):
""" Initializes an alternate layout, if enabled. """
control_box = builder.get_object("control_button_box")
control_box.set_child_packing(self._control_button, False, True, 0, Gtk.PackType.END)
extra_box = builder.get_object("toolbar_extra_box")
extra_box.set_child_packing(self._toolbar_extra_tools_box, False, True, 0, Gtk.PackType.END)
self._toolbar_search_box.reorder_child(builder.get_object("search_tool_button"), 0)
self._top_box.set_child_packing(extra_box, False, True, 0, Gtk.PackType.START)
self._top_box.set_child_packing(self._toolbar_search_box, False, True, 0, Gtk.PackType.END)
self._top_box.reorder_child(extra_box, 0)
center_box = builder.get_object("center_box")
center_box.reorder_child(self._control_revealer, 0)
center_box.reorder_child(self._ftp_revealer, 1)
center_box.reorder_child(self._main_box, 2)
center_box.set_child_packing(self._control_revealer, False, True, 0, Gtk.PackType.START)
builder.get_object("fs_box").set_child_packing(self._filter_box, False, True, 0, Gtk.PackType.END)
top_toolbar = builder.get_object("top_toolbar")
top_toolbar.set_child_packing(self._toolbar_search_box, False, True, 0, Gtk.PackType.END)
services_box = self._main_paned.get_child1()
self._main_paned.remove(services_box)
self._main_paned.remove(self._fav_paned)
self._main_paned.pack1(self._fav_paned, True, True)
self._main_paned.pack2(services_box, True, True)
self._left_ar_bq_button.set_visible(not self._settings.bq_details_first)
self.init_bq_position()
def init_bq_position(self):
self._fav_paned.remove(self._fav_box)
self._fav_paned.remove(self._bouquets_box)
if self._settings.bq_details_first:
self._fav_paned.pack1(self._fav_box, False, False)
self._fav_paned.pack2(self._bouquets_box, False, False)
else:
self._fav_paned.pack1(self._bouquets_box, False, False)
self._fav_paned.pack2(self._fav_box, False, False)
pack = Gtk.PackType.END if self._settings.bq_details_first else Gtk.PackType.START
self._toolbar_extra_tools_box.set_child_packing(self._add_bouquet_button, False, True, 0, pack)
# Menu bar
main_box = builder.get_object("main_window_box")
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_from_file(UI_RESOURCES_PATH + "app_menu_bar.ui")
menu_bar = Gtk.MenuBar.new_from_model(builder.get_object("menu_bar"))
menu_bar.set_visible(True)
main_box.pack_start(menu_bar, False, False, 0)
main_box.reorder_child(menu_bar, 0)
self._main_data_box.bind_property("visible", menu_bar, "visible")
self._player_box.bind_property("visible", menu_bar, "sensitive", 4)
if self._settings.get("telnet"):
self.init_telnet(builder)
def do_startup(self):
Gtk.Application.do_startup(self)
self.init_keys()
self.set_accels()
builder = Gtk.Builder()
builder.set_translation_domain("demon-editor")
builder.add_from_file(UI_RESOURCES_PATH + "app_menu_bar.ui")
self.set_menubar(builder.get_object("menu_bar"))
self.set_app_menu(builder.get_object("app-menu"))
if self._settings.get("telnet"):
self.init_telnet(builder)
self.update_profile_label()
self.init_drag_and_drop()
self.init_appearance()
@@ -1297,15 +1242,18 @@ class Application(Gtk.Application):
if txt:
if txt.startswith("file://") and name == self.SERVICE_MODEL_NAME:
self.on_import_data(urlparse(unquote(txt)).path.strip())
path = urlparse(unquote(txt)).path
self.on_import_data(path.lstrip("/") if IS_WIN else path.strip())
elif name == self.FAV_MODEL_NAME:
self.receive_selection(view=view, drop_info=view.get_dest_row_at_pos(x, y), data=txt)
if uris:
src, sep, dest = uris[0].partition("::::")
src_path = urlparse(unquote(src)).path
src_path = src_path.lstrip("/") if IS_WIN else src_path.strip()
if dest:
dest_path = urlparse(unquote(dest)).path + "/"
dest_path = urlparse(unquote(dest)).path
dest_path = dest_path.lstrip("/") + "/" if IS_WIN else dest_path.strip()
self.picons_buffer = self.on_assign_picon(view, src_path, dest_path)
elif name == self.SERVICE_MODEL_NAME:
self.on_import_data(src_path)
@@ -1317,7 +1265,9 @@ class Application(Gtk.Application):
uris = data.get_uris()
if uris:
self.on_import_bouquet(None, file_path=urlparse(unquote(uris[0])).path.strip())
path = urlparse(unquote(uris[0])).path
path = path.lstrip("/") if IS_WIN else path.strip()
self.on_import_bouquet(None, file_path=path)
return
data = data.get_text()
@@ -1325,7 +1275,9 @@ class Application(Gtk.Application):
return
if data.startswith("file://"):
self.on_import_bouquet(None, file_path=urlparse(unquote(data)).path.strip())
path = urlparse(unquote(data)).path
path = path.lstrip("/") if IS_WIN else path.strip()
self.on_import_bouquet(None, file_path=path)
return
itr_str, sep, source = data.partition(self.DRAG_SEP)
@@ -1528,8 +1480,12 @@ class Application(Gtk.Application):
""" Opening the data archive via "File/Open archive". """
file_filter = Gtk.FileFilter()
file_filter.set_name("*.zip, *.gz")
file_filter.add_mime_type("application/zip")
file_filter.add_mime_type("application/gzip")
if IS_WIN:
file_filter.add_pattern("*.zip")
file_filter.add_pattern("*.gz")
else:
file_filter.add_mime_type("application/zip")
file_filter.add_mime_type("application/gzip")
response = show_dialog(DialogType.CHOOSER, self._main_window,
action_type=Gtk.FileChooserAction.OPEN,
@@ -1573,8 +1529,10 @@ class Application(Gtk.Application):
except (UnicodeEncodeError, UnicodeDecodeError) as e:
log("Filename [{}] error in zip archive: {}".format(zip_info.filename, e))
else:
zip_info.filename = os.path.basename(f_name)
zip_file.extract(zip_info, path=tmp_path_name)
base_name = os.path.basename(f_name)
if base_name:
zip_info.filename = os.path.basename(f_name)
zip_file.extract(zip_info, path=tmp_path_name)
elif tarfile.is_tarfile(data_path):
with tarfile.open(data_path) as tar:
for mb in tar.getmembers():
@@ -2423,6 +2381,7 @@ class Application(Gtk.Application):
self.import_data(response)
def import_data(self, path, force=None, callback=None):
path = os.path.normpath(path)
if os.path.isdir(path) and not path.endswith(os.sep):
path += os.sep
elif os.path.isfile(path):

View File

@@ -37,7 +37,7 @@ def insert_marker(view, bouquets, selected_bouquet, services, parent_window, m_t
marker = (None, None, text, None, None, s_type, None, fav_id, None, None, None)
itr = model.insert_before(model.get_iter(paths[0]), marker) if paths else model.insert(0, marker)
bouquets[selected_bouquet].insert(model.get_path(itr)[0], fav_id)
services[fav_id] = Service(None, None, None, text, None, None, None, s_type, *[None] * 9, 0, fav_id, None)
services[fav_id] = Service(None, None, None, text, None, None, None, s_type, None, None, None, None, None, None, None, None, None, 0, fav_id, None)
# ***************** Movement *******************#
@@ -280,7 +280,7 @@ def set_hide(services, model, paths):
for path in paths:
itr = model.get_iter(path)
model.set_value(itr, col_num, None if hide else HIDE_ICON)
flags = [*model.get_value(itr, 0).split(",")]
flags = list(model.get_value(itr, 0).split(","))
index, flag = None, None
for i, fl in enumerate(flags):
if fl.startswith("f:"):

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2
<!-- Generated with glade 3.22.2
The MIT License (MIT)
@@ -110,7 +110,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Cut</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_bouquets_cut" object="bouquets_tree_view" swapped="no"/>
<accelerator key="x" signal="activate" modifiers="Primary"/>
<accelerator key="x" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -121,7 +121,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Copy</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_bouquets_copy" object="bouquets_tree_view" swapped="no"/>
<accelerator key="c" signal="activate" modifiers="Primary"/>
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -132,7 +132,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Paste</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_bouquets_paste" object="bouquets_tree_view" swapped="no"/>
<accelerator key="v" signal="activate" modifiers="Primary"/>
<accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -149,7 +149,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Edit</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_edit" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -166,7 +166,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Remove</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_delete" object="bouquets_tree_view" swapped="no"/>
<accelerator key="Delete" signal="activate"/>
<accelerator key="Delete" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
</object>
@@ -228,7 +228,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Cut</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_fav_cut" object="fav_tree_view" swapped="no"/>
<accelerator key="x" signal="activate" modifiers="Primary"/>
<accelerator key="x" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -239,7 +239,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Copy</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_fav_copy" object="fav_tree_view" swapped="no"/>
<accelerator key="c" signal="activate" modifiers="Primary"/>
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -250,7 +250,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Paste</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_fav_paste" object="fav_tree_view" swapped="no"/>
<accelerator key="v" signal="activate" modifiers="Primary"/>
<accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -266,7 +266,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Edit</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_edit" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -610,7 +610,7 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkCellRendererToggle" id="filter_satellite_renderer_toggle">
<property name="xalign">0.98</property>
<property name="xalign">0.98000001907348633</property>
<signal name="toggled" handler="on_filter_satellite_toggled" swapped="no"/>
</object>
<attributes>
@@ -925,7 +925,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Copy</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_services_copy" object="services_tree_view" swapped="no"/>
<accelerator key="c" signal="activate" modifiers="Primary"/>
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -935,7 +935,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Edit</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_edit" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -1115,10 +1115,9 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="window_position">center</property>
<property name="icon_name">demon-editor</property>
<property name="gravity">center</property>
<property name="startup_id">DemonEditor</property>
<signal name="delete-event" handler="on_close_app" swapped="no"/>
<child>
<child type="titlebar">
<placeholder/>
</child>
<child>
@@ -1132,65 +1131,13 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="spacing">10</property>
<child>
<object class="GtkButtonBox" id="toolbar_search_box">
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_left">15</property>
<property name="margin_right">15</property>
<property name="homogeneous">True</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkToggleButton" id="filter_tool_button">
<property name="label" translatable="yes">Filter</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<property name="valign">center</property>
<property name="action_name">win.filter</property>
<property name="image">filter_image</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="search_tool_button">
<property name="label" translatable="yes">Search</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Search</property>
<property name="valign">center</property>
<property name="action_name">win.search</property>
<property name="image">find_image</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child type="center">
<object class="GtkBox" id="top_toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="spacing">5</property>
@@ -1200,7 +1147,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="focus_on_click">False</property>
<property name="tooltip_text" translatable="yes">Profile</property>
<property name="valign">center</property>
<property name="active">0</property>
<signal name="changed" handler="on_profile_changed" swapped="no"/>
</object>
@@ -1215,7 +1161,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="open_tool_button">
@@ -1223,7 +1168,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Open</property>
<property name="valign">center</property>
<property name="action_name">app.on_data_open</property>
<property name="image">open_image</property>
<property name="always_show_image">True</property>
@@ -1242,7 +1186,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">FTP-transfer</property>
<property name="valign">center</property>
<property name="action_name">app.on_download</property>
<property name="image">ftp_image</property>
<property name="always_show_image">True</property>
@@ -1275,7 +1218,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Save</property>
<property name="valign">center</property>
<property name="action_name">app.on_data_save</property>
<property name="image">save_image</property>
<property name="always_show_image">True</property>
@@ -1293,7 +1235,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Backups</property>
<property name="valign">center</property>
<property name="action_name">app.on_backup_tool_show</property>
<property name="image">backups_image</property>
<property name="always_show_image">True</property>
@@ -1311,20 +1252,68 @@ Author: Dmitriy Yefremov
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="toolbar_search_box">
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="homogeneous">True</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkToggleButton" id="filter_tool_button">
<property name="label" translatable="yes">Filter</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<property name="action_name">win.filter</property>
<property name="image">filter_image</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="search_tool_button">
<property name="label" translatable="yes">Search</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Search</property>
<property name="action_name">win.search</property>
<property name="image">find_image</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="toolbar_tools_box">
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="homogeneous">True</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="sat_editor_tool_button">
<property name="label" translatable="yes">Satellites</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Satellites editor</property>
<property name="valign">center</property>
<property name="action_name">app.on_satellite_editor_show</property>
<property name="image">sat_editor_image</property>
<property name="always_show_image">True</property>
@@ -1339,10 +1328,9 @@ Author: Dmitriy Yefremov
<object class="GtkButton" id="picons_manager_tool_button">
<property name="label" translatable="yes">Picons</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Picons manager</property>
<property name="valign">center</property>
<property name="action_name">app.on_picons_manager_show</property>
<property name="image">picons_image</property>
<property name="always_show_image">True</property>
@@ -1356,10 +1344,9 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkMenuButton" id="iptv_tools_menu_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">IPTV tools</property>
<property name="valign">center</property>
<property name="popup">toolbar_iptv_menu</property>
<child>
<object class="GtkBox" id="iptv_tools_menu_button_box">
@@ -1422,27 +1409,28 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_left">15</property>
<property name="margin_right">15</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="spacing">20</property>
<child>
<object class="GtkButtonBox" id="toolbar_extra_tools_box">
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="halign">center</property>
<property name="homogeneous">True</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="lock_tool_button">
<property name="width_request">48</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Parent lock</property>
<property name="valign">center</property>
<property name="action_name">app.on_locked</property>
<property name="image">lock_image</property>
<property name="always_show_image">True</property>
<accelerator key="l" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">True</property>
@@ -1456,10 +1444,10 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Hide/Skip</property>
<property name="valign">center</property>
<property name="action_name">app.on_hide</property>
<property name="image">hide_image</property>
<property name="always_show_image">True</property>
<accelerator key="h" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">True</property>
@@ -1469,7 +1457,6 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkButton" id="add_bouquet_tool_button">
<property name="width_request">32</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
@@ -1505,22 +1492,20 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="homogeneous">True</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkToggleButton" id="control_button">
<property name="width_request">32</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Control</property>
<property name="action_name">app.on_remote</property>
<property name="image">control_image</property>
<property name="always_show_image">True</property>
<accelerator key="t" signal="clicked"/>
<accelerator key="t" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
@@ -1528,7 +1513,6 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkToggleButton" id="ftp_button">
<property name="label" translatable="yes">FTP</property>
<property name="width_request">32</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -1546,6 +1530,7 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
@@ -1554,7 +1539,7 @@ Author: Dmitriy Yefremov
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
</object>
@@ -3286,7 +3271,7 @@ Author: Dmitriy Yefremov
<object class="GtkLabel" id="app_ver_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">1.0.7 Beta</property>
<property name="label" translatable="yes">1.0.7 Alpha</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>

View File

@@ -275,7 +275,6 @@ Author: Dmitriy Yefremov
<property name="destroy_with_parent">True</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<signal name="delete-event" handler="on_close" swapped="no"/>
<child>
<placeholder/>
@@ -1613,7 +1612,7 @@ Author: Dmitriy Yefremov
<property name="image">filter_image</property>
<property name="always_show_image">True</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | Primary"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>
@@ -1629,7 +1628,7 @@ Author: Dmitriy Yefremov
<property name="receives_default">True</property>
<property name="image">info_toggle_button_image</property>
<property name="always_show_image">True</property>
<accelerator key="i" signal="clicked" modifiers="Primary"/>
<accelerator key="i" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">True</property>
@@ -1660,7 +1659,7 @@ Author: Dmitriy Yefremov
<property name="image">cancel_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_cancel" swapped="no"/>
<accelerator key="z" signal="clicked" modifiers="Primary"/>
<accelerator key="z" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -12,10 +12,10 @@ from app.connections import upload_data, DownloadType, download_data, remove_pic
from app.settings import SettingsType, Settings
from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to, download_picon
from app.tools.satellites import SatellitesParser, SatelliteSource
from .dialogs import show_dialog, DialogType, get_message
from .dialogs import show_dialog, DialogType, get_message, get_builder
from .main_helper import update_entry_data, append_text_to_tview, scroll_to, on_popup_menu, get_base_model, set_picon, \
get_picon_pixbuf
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TV_ICON, Column, GTK_PATH, KeyboardKey
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TV_ICON, Column, KeyboardKey
class PiconsDialog:
@@ -76,9 +76,7 @@ class PiconsDialog:
"on_tree_view_key_press": self.on_tree_view_key_press,
"on_popup_menu": on_popup_menu}
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "picons_manager.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "picons_manager.glade", handlers)
self._dialog = builder.get_object("picons_dialog")
self._dialog.set_transient_for(transient)
@@ -509,7 +507,8 @@ class PiconsDialog:
@run_idle
def append_providers(self, providers, model):
for p in providers:
model.append((self.get_pixbuf(p[0]) if p[0] else TV_ICON, *p[1:]))
prv = p._replace(logo=self.get_pixbuf(p[0]) if p[0] else TV_ICON)
model.append(prv)
self.update_receive_button_state()
def get_pixbuf(self, img_data):
@@ -560,7 +559,7 @@ class PiconsDialog:
picons.extend(pic)
# Getting picon images.
futures = {executor.submit(download_picon, *pic, self.append_output): pic for pic in picons}
futures = {executor.submit(download_picon, pic[0], pic[1], self.append_output): pic for pic in picons}
done, not_done = concurrent.futures.wait(futures, timeout=0)
while self._is_downloading and not_done:
done, not_done = concurrent.futures.wait(not_done, timeout=5)

View File

@@ -269,7 +269,7 @@ Author: Dmitriy Yefremov
<property name="image">popup_menu_add_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_satellite_add" swapped="no"/>
<accelerator key="s" signal="activate" modifiers="Primary"/>
<accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -280,7 +280,7 @@ Author: Dmitriy Yefremov
<property name="image">popup_menu_add_image_2</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_transponder_add" swapped="no"/>
<accelerator key="t" signal="activate" modifiers="Primary"/>
<accelerator key="t" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -297,7 +297,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_edit" object="satellites_editor_tree_view" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
@@ -436,7 +436,6 @@ Author: Dmitriy Yefremov
<property name="icon_name">applications-utilities</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<signal name="check-resize" handler="on_resize" swapped="no"/>
<child>
<object class="GtkBox" id="sat_editor_main_box">
@@ -779,7 +778,6 @@ Author: Dmitriy Yefremov
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child internal-child="vbox">
<object class="GtkBox" id="satelitte_dialog_vbox">
<property name="can_focus">False</property>
@@ -869,7 +867,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="sat_name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="secondary_icon_sensitive">False</property>
@@ -970,7 +967,6 @@ Author: Dmitriy Yefremov
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child internal-child="vbox">
<object class="GtkBox" id="tr_dialog_vbox">
<property name="can_focus">False</property>
@@ -1112,7 +1108,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">12</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="secondary_icon_sensitive">False</property>
@@ -1131,7 +1126,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">12</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="placeholder_text" translatable="yes">27500000</property>
<property name="input_purpose">digits</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
@@ -1287,7 +1281,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">5</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="placeholder_text" translatable="yes">0 - 262142</property>
<property name="input_purpose">digits</property>
@@ -1304,7 +1297,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">5</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="placeholder_text" translatable="yes">0 - 255</property>
<property name="input_purpose">digits</property>
@@ -1408,7 +1400,6 @@ Author: Dmitriy Yefremov
<property name="destroy_with_parent">True</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<signal name="delete-event" handler="on_quit" swapped="no"/>
<child>
<placeholder/>
@@ -1458,7 +1449,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Cancel</property>
<property name="valign">center</property>
<property name="image">sat_update_cancel_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_cancel_receive" swapped="no"/>
@@ -1496,7 +1486,7 @@ Author: Dmitriy Yefremov
<property name="image">sat_update_filter_image</property>
<property name="always_show_image">True</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | Primary"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>
@@ -1514,7 +1504,7 @@ Author: Dmitriy Yefremov
<property name="image">sat_update_search_image</property>
<property name="always_show_image">True</property>
<signal name="toggled" handler="on_find_toggled" swapped="no"/>
<accelerator key="f" signal="clicked" modifiers="Primary"/>
<accelerator key="f" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -9,10 +9,10 @@ from app.commons import run_idle, run_task, log
from app.eparser import get_satellites, write_satellites, Satellite, Transponder
from app.eparser.ecommons import PLS_MODE, get_key_by_value
from app.tools.satellites import SatellitesParser, SatelliteSource, ServicesParser
from .dialogs import show_dialog, DialogType, get_dialogs_string, get_chooser_dialog, get_message
from .dialogs import show_dialog, DialogType, get_chooser_dialog, get_message, get_builder
from .main_helper import move_items, scroll_to, append_text_to_tview, get_base_model, on_popup_menu
from .search import SearchProvider
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, MOVE_KEYS, KeyboardKey, IS_GNOME_SESSION, MOD_MASK
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, MOVE_KEYS, KeyboardKey, MOD_MASK
_UI_PATH = UI_RESOURCES_PATH + "satellites_dialog.glade"
@@ -44,13 +44,10 @@ class SatellitesDialog:
"on_resize": self.on_resize,
"on_quit": self.on_quit}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH),
("satellites_editor_window", "satellites_tree_store", "popup_menu",
"left_header_menu", "popup_menu_add_image", "popup_menu_add_image_2",
"sat_editor_save_image", "sat_editor_update_image"))
builder.connect_signals(handlers)
builder = get_builder(_UI_PATH, handlers, use_str=True,
objects=("satellites_editor_window", "satellites_tree_store", "popup_menu",
"left_header_menu", "popup_menu_add_image", "popup_menu_add_image_2",
"sat_editor_save_image", "sat_editor_update_image"))
self._window = builder.get_object("satellites_editor_window")
self._window.set_transient_for(transient)
@@ -185,7 +182,8 @@ class SatellitesDialog:
model.set(edited_itr, {0: sat.name, 10: sat.flags, 11: sat.position})
else:
index = self.get_sat_position_index(sat.position, model)
model.insert(None, index, [sat.name, *self._aggr, sat.flags, sat.position])
model.insert(None, index,
[sat.name, None, None, None, None, None, None, None, None, None, sat.flags, sat.position])
scroll_to(index, view)
def on_transponder(self, transponder=None, edited_itr=None):
@@ -210,7 +208,8 @@ class SatellitesDialog:
4: tr.fec_inner, 5: tr.system, 6: tr.modulation,
7: tr.pls_mode, 8: tr.pls_code, 9: tr.is_id})
else:
row = ["Transponder:", *tr, None, None]
row = ["Transponder:", tr.frequency, tr.symbol_rate, tr.polarization, tr.fec_inner,
tr.system, tr.modulation, tr.pls_mode, tr.pls_code, tr.is_id, None, None]
model, paths = view.get_selection().get_selected_rows()
itr = model.get_iter(paths[0])
view.expand_row(paths[0], 0)
@@ -316,13 +315,8 @@ class TransponderDialog:
def __init__(self, transient, transponder: Transponder = None):
handlers = {"on_entry_changed": self.on_entry_changed}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION),
("transponder_dialog", "pol_store", "fec_store", "mod_store", "system_store",
"pls_mode_store"))
builder.connect_signals(handlers)
objects = ("transponder_dialog", "pol_store", "fec_store", "mod_store", "system_store", "pls_mode_store")
builder = get_builder(_UI_PATH, handlers, use_str=True, objects=objects)
self._dialog = builder.get_object("transponder_dialog")
self._dialog.set_transient_for(transient)
@@ -401,10 +395,7 @@ class SatelliteDialog:
""" Shows dialog for adding or edit satellite """
def __init__(self, transient, satellite: Satellite = None):
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION),
("satellite_dialog", "side_store", "pos_adjustment"))
builder = get_builder(_UI_PATH, use_str=True, objects=("satellite_dialog", "side_store", "pos_adjustment"))
self._dialog = builder.get_object("satellite_dialog")
self._dialog.set_transient_for(transient)
@@ -466,16 +457,13 @@ class UpdateDialog:
self._parser = None
self._size_name = "{}_window_size".format("_".join(re.findall("[A-Z][^A-Z]*", self.__class__.__name__))).lower()
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_file(UI_RESOURCES_PATH + "satellites_dialog.glade",
("satellites_update_window", "update_source_store", "update_sat_list_store",
builder = get_builder(UI_RESOURCES_PATH + "satellites_dialog.glade", handlers,
objects=("satellites_update_window", "update_source_store", "update_sat_list_store",
"update_sat_list_model_filter", "update_sat_list_model_sort", "side_store",
"pos_adjustment", "pos_adjustment2", "satellites_update_popup_menu",
"remove_selection_image", "sat_update_cancel_image", "sat_receive_image",
"sat_update_filter_image", "sat_update_search_image", "sat_update_image",
"update_transponder_store", "update_service_store"))
builder.connect_signals(handlers)
self._window = builder.get_object("satellites_update_window")
self._window.set_transient_for(transient)
@@ -729,7 +717,8 @@ class SatellitesUpdateDialog(UpdateDialog):
self._main_model.remove(ch.iter)
for tr in sat[3]:
self._main_model.append(itr, ["Transponder:", *tr, None, None])
self._main_model.append(itr, ["Transponder:", tr.frequency, tr.symbol_rate, tr.polarization, tr.fec_inner,
tr.system, tr.modulation, tr.pls_mode, tr.pls_code, tr.is_id, None, None])
class ServicesUpdateDialog(UpdateDialog):
@@ -956,9 +945,10 @@ class ServicesUpdateDialog(UpdateDialog):
def append_satellite(model, sat):
""" Common function for append satellite to the model """
name, flags, pos, transponders = sat
parent = model.append(None, [name, *(None,) * 9, flags, pos])
for transponder in transponders:
model.append(parent, ["Transponder:", *transponder, None, None])
parent = model.append(None, [name, None, None, None, None, None, None, None, None, None, flags, pos])
for tr in transponders:
model.append(parent, ["Transponder:", tr.frequency, tr.symbol_rate, tr.polarization, tr.fec_inner, tr.system,
tr.modulation, tr.pls_mode, tr.pls_code, tr.is_id, None, None])
if __name__ == "__main__":

View File

@@ -272,7 +272,6 @@ Author: Dmitriy Yefremov
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child type="titlebar">
<placeholder/>
</child>
@@ -380,7 +379,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -402,7 +400,7 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="package_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -426,7 +424,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">10</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="key-release-event" handler="update_reference" swapped="no"/>
</object>
@@ -471,7 +469,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">7</property>
<property name="max_width_chars">7</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="changed" handler="update_reference" swapped="no"/>
</object>
@@ -909,7 +907,7 @@ Author: Dmitriy Yefremov
<property name="tooltip_text">C:0000,C:a1b2,etc.</property>
<property name="width_chars">15</property>
<property name="max_width_chars">26</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="placeholder_text" translatable="yes">C:0000,C:a1b2,etc.</property>
<signal name="changed" handler="on_cas_entry_changed" swapped="no"/>
</object>
@@ -1012,7 +1010,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1038,7 +1036,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1117,7 +1115,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="key-release-event" handler="update_reference" swapped="no"/>
</object>
@@ -1155,7 +1153,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="key-release-event" handler="update_reference" swapped="no"/>
</object>
@@ -1182,7 +1180,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="key-release-event" handler="update_reference" swapped="no"/>
</object>
@@ -1391,7 +1389,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1417,7 +1415,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1443,7 +1441,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1569,7 +1567,7 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkImage" id="tr_edit_switch_image">
<property name="visible">True</property>
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="icon_name">document-edit-symbolic</property>
@@ -1629,7 +1627,6 @@ Author: Dmitriy Yefremov
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child>
<placeholder/>
</child>

View File

@@ -8,9 +8,9 @@ from app.eparser.ecommons import (MODULATION, Inversion, ROLL_OFF, Pilot, Flag,
TrType, SystemCable, T_SYSTEM, BANDWIDTH, TRANSMISSION_MODE, GUARD_INTERVAL, T_FEC,
HIERARCHY, A_MODULATION)
from app.settings import SettingsType
from .dialogs import show_dialog, DialogType, Action, get_dialogs_string
from .dialogs import show_dialog, DialogType, Action, get_builder
from .main_helper import get_base_model
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, HIDE_ICON, TEXT_DOMAIN, CODED_ICON, Column, IS_GNOME_SESSION
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, HIDE_ICON, CODED_ICON, Column
_UI_PATH = UI_RESOURCES_PATH + "service_details_dialog.glade"
@@ -46,10 +46,7 @@ class ServiceDetailsDialog:
"on_non_empty_entry_changed": self.on_non_empty_entry_changed,
"on_cancel": lambda item: self._dialog.destroy()}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION))
builder.connect_signals(handlers)
builder = get_builder(_UI_PATH, handlers, use_str=True)
self._builder = builder
self._dialog = builder.get_object("service_details_dialog")
@@ -386,7 +383,6 @@ class ServiceDetailsDialog:
def on_new(self):
""" Create new service. """
service = self.get_service(*self.get_srv_data(), self.get_satellite_transponder_data())
show_dialog(DialogType.ERROR, transient=self._dialog, text="Not implemented yet!")
return True
@@ -875,10 +871,7 @@ class ServiceDetailsDialog:
class TransponderServicesDialog:
def __init__(self, transient, services_view, transponder, tr_iters):
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION),
("tr_services_dialog", "transponder_services_liststore"))
builder = get_builder(_UI_PATH, use_str=True, objects=("tr_services_dialog", "transponder_services_liststore"))
self._dialog = builder.get_object("tr_services_dialog")
self._dialog.set_transient_for(transient)
self._srv_model = builder.get_object("transponder_services_liststore")

View File

@@ -142,7 +142,6 @@ Author: Dmitriy Yefremov
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<signal name="response" handler="on_response" swapped="no"/>
<child internal-child="vbox">
<object class="GtkBox" id="main_box">
@@ -165,7 +164,7 @@ Author: Dmitriy Yefremov
<property name="tooltip_text" translatable="yes">Apply profile settings</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_apply_profile_settings" swapped="no"/>
<accelerator key="s" signal="clicked" modifiers="Primary"/>
<accelerator key="s" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>
@@ -396,7 +395,7 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkButton" id="profile_edit_button">
<property name="visible">True</property>
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Rename</property>
@@ -455,7 +454,7 @@ Author: Dmitriy Yefremov
<property name="icon_name">emblem-default</property>
</object>
</child>
<accelerator key="d" signal="clicked" modifiers="Primary"/>
<accelerator key="d" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>
@@ -856,8 +855,7 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child>
<object class="GtkSpinner" id="test_spinner">
<property name="visible">True</property>
<object class="GtkSpinner" id="test_spinner"><property name="visible">False</property>
<property name="can_focus">False</property>
</object>
<packing>
@@ -1037,7 +1035,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text">/etc/enigma2/</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -1059,7 +1056,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="user_bouquet_field">
<property name="can_focus">True</property>
<property name="text">/etc/enigma2/</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -1083,7 +1079,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text">/etc/tuxbox/</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -1107,7 +1102,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text">/usr/share/enigma2/picon</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -1162,7 +1156,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="picons_dir_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Select</property>
@@ -1191,7 +1184,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="data_dir_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Select</property>
@@ -1219,7 +1211,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="backup_dir_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Select</property>
@@ -1355,7 +1346,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="default_data_dir_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Select</property>
@@ -1417,7 +1407,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="record_data_dir_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Select</property>
@@ -2722,7 +2711,6 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkBox" id="layout_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Enables an alternate layout of the main window elements.</property>
<child>

View File

@@ -3,8 +3,8 @@ import re
from app.commons import run_task, run_idle, log
from app.connections import test_telnet, test_ftp, TestException, test_http, HttpApiException
from app.settings import SettingsType, Settings, PlayStreamsMode
from app.ui.dialogs import show_dialog, DialogType, get_message, get_chooser_dialog
from app.settings import SettingsType, Settings, PlayStreamsMode, IS_WIN
from app.ui.dialogs import show_dialog, DialogType, get_message, get_chooser_dialog, get_builder
from .main_helper import update_entry_data, scroll_to, get_picon_pixbuf
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, DEFAULT_ICON, APP_FONT
@@ -64,9 +64,7 @@ class SettingsDialog:
self._profiles = self._settings.profiles
self._s_type = self._settings.setting_type
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "settings_dialog.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "settings_dialog.glade", handlers)
self._dialog = builder.get_object("settings_dialog")
self._dialog.set_transient_for(transient)
@@ -182,14 +180,17 @@ class SettingsDialog:
self.init_ui_elements(self._s_type)
self.init_profiles()
if self._settings.is_darwin:
if IS_WIN or True:
self._gst_lib_button.set_visible(False)
self._vlc_lib_button.set_sensitive(self._settings.is_enable_experimental)
# Themes
builder.get_object("style_frame").set_visible(True)
builder.get_object("themes_support_frame").set_visible(True)
enable_exp = self._settings.is_enable_experimental
builder.get_object("style_frame").set_visible(enable_exp)
builder.get_object("themes_support_frame").set_visible(enable_exp)
self._layout_switch = builder.get_object("layout_switch")
self._layout_switch.set_active(self._ext_settings.alternate_layout)
self._theme_frame = builder.get_object("theme_frame")
self._theme_frame.set_visible(True)
self._theme_frame.set_visible(enable_exp)
self._theme_thumbnail_image = builder.get_object("theme_thumbnail_image")
self._theme_combo_box = builder.get_object("theme_combo_box")
self._icon_theme_combo_box = builder.get_object("icon_theme_combo_box")
@@ -355,7 +356,7 @@ class SettingsDialog:
self._ext_settings.tooltip_logo_size = int(self._tooltip_logo_size_button.get_active_id())
self._ext_settings.list_font = self._list_font_button.get_font()
if self._ext_settings.is_darwin:
if IS_WIN:
self._ext_settings.alternate_layout = self._layout_switch.get_active()
self._ext_settings.is_themes_support = self._themes_support_switch.get_active()
self._ext_settings.theme = self._theme_combo_box.get_active_id()

View File

@@ -1,10 +1,16 @@
#digit-entry {
border-color: Red;
border-width: 0.15em;
}
#status-bar-button {
margin: 0.1em;
padding: 1px;
margin: 1px;
}
paned > separator {
background-repeat: no-repeat;
background-position: center;
background-size: 2px 24px;
}
.red-button {
@@ -27,27 +33,14 @@
background-color: blue;
}
#textview-large {
font-size: 14px;
}
.time-entry {
padding: 0px;
margin: 0px;
}
.arrow-button {
padding: 0px;
margin: 1px;
min-width: 12px;
min-height: 12px;
}
.group {}
.group :first-child {
padding-left: 0.5em;
padding-right: 0.5em;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}

View File

@@ -42,7 +42,6 @@ Author: Dmitriy Yefremov
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="decorated">False</property>
<property name="gravity">center</property>
<property name="has_resize_grip">True</property>
<child>
<placeholder/>

View File

@@ -5,9 +5,10 @@ import gi
from gi.repository import GLib
from app.commons import log
from app.settings import IS_DARWIN
from app.connections import HttpAPI
from app.settings import IS_WIN
from app.tools.yt import YouTube
from app.ui.dialogs import get_builder
from app.ui.iptv import get_yt_icon
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH
@@ -35,9 +36,7 @@ class LinksTransmitter:
self._app_window = app_window
self._is_status_icon = True
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "transmitter.glade")
builder.connect_signals(handlers)
builder = get_builder(UI_RESOURCES_PATH + "transmitter.glade", handlers)
self._main_window = builder.get_object("main_window")
self._url_entry = builder.get_object("url_entry")
@@ -48,7 +47,7 @@ class LinksTransmitter:
self._status_passive = None
self._yt = YouTube.get_instance(settings)
if IS_DARWIN:
if IS_WIN:
self._tray = builder.get_object("status_icon")
else:
try:

View File

@@ -1,7 +1,9 @@
import locale
import os
from enum import Enum, IntEnum
from functools import lru_cache
from app.settings import Settings, SettingsException, IS_DARWIN
from app.settings import Settings, SettingsException, IS_WIN, SEP
import gi
@@ -10,9 +12,10 @@ gi.require_version("Gdk", "3.0")
from gi.repository import Gtk, Gdk, GLib
# Setting mod mask for keyboard depending on platform
MOD_MASK = Gdk.ModifierType.MOD2_MASK if IS_DARWIN else Gdk.ModifierType.CONTROL_MASK
MOD_MASK = Gdk.ModifierType.CONTROL_MASK
# Path to *.glade files
UI_RESOURCES_PATH = "app/ui/" if os.path.exists("app/ui/") else "ui/"
UI_PATH = "app{}ui{}".format(SEP, SEP)
UI_RESOURCES_PATH = UI_PATH if os.path.exists(UI_PATH) else "ui{}".format(SEP)
LANG_PATH = UI_RESOURCES_PATH + "lang"
GTK_PATH = os.environ.get("GTK_PATH", None)
NOTIFY_IS_INIT = False
@@ -26,45 +29,18 @@ try:
except SettingsException:
pass
else:
locale.setlocale(locale.LC_NUMERIC, "C")
os.environ["LANGUAGE"] = settings.language
st = Gtk.Settings().get_default()
APP_FONT = st.get_property("gtk-font-name")
st.set_property("gtk-application-prefer-dark-theme", settings.dark_mode)
if settings.is_themes_support:
st.set_property("gtk-theme-name", settings.theme)
st.set_property("gtk-icon-theme-name", settings.icon_theme)
else:
style_provider = Gtk.CssProvider()
s_path = "{}default_style.css".format(GTK_PATH + "/" + UI_RESOURCES_PATH if GTK_PATH else UI_RESOURCES_PATH)
style_provider.load_from_path(s_path)
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
if IS_DARWIN:
import gettext
if GTK_PATH:
LANG_PATH = GTK_PATH + "/share/locale"
gettext.bindtextdomain(TEXT_DOMAIN, LANG_PATH)
# For launching from the bundle.
if os.getcwd() == "/" and GTK_PATH:
os.chdir(GTK_PATH)
else:
import locale
locale.bindtextdomain(TEXT_DOMAIN, LANG_PATH)
# Init notify
try:
gi.require_version("Notify", "0.7")
from gi.repository import Notify
except ImportError:
pass
else:
NOTIFY_IS_INIT = Notify.init("DemonEditor")
theme = Gtk.IconTheme.get_default()
theme.append_search_path(GTK_PATH + "/share/icons" if GTK_PATH else UI_RESOURCES_PATH + "icons")
theme.append_search_path(GTK_PATH + "{}share{}icons".format(SEP, SEP) if GTK_PATH else UI_RESOURCES_PATH + "icons")
def get_theme_icon(icon_theme, name, size):
@@ -95,9 +71,11 @@ def get_yt_icon(icon_name, size=24):
return default_theme.load_icon(icon_name, size, 0)
n_theme = Gtk.IconTheme.new()
p_path = "{}usr{}share{}icons{}*".format(SEP, SEP, SEP, SEP)
import glob
for theme_name in map(os.path.basename, filter(os.path.isdir, glob.glob("/usr/share/icons/*"))):
for theme_name in map(os.path.basename, filter(os.path.isdir, glob.glob(p_path))):
theme.set_custom_theme(theme_name)
if n_theme.has_icon(icon_name):
return n_theme.load_icon(icon_name, size, 0)
@@ -113,47 +91,38 @@ def show_notification(message, timeout=10000, urgency=1):
@param timeout: milliseconds
@param urgency: 0 - low, 1 - normal, 2 - critical
"""
if IS_DARWIN:
# Since NSUserNotification has been deprecated, osascript will be used.
os.system("""osascript -e 'display notification "{}" with title "DemonEditor"'""".format(message))
elif NOTIFY_IS_INIT:
notify = Notify.Notification.new("DemonEditor", message, "demon-editor")
notify.set_urgency(urgency)
notify.set_timeout(timeout)
notify.show()
pass
class KeyboardKey(Enum):
""" The raw(hardware) codes of the keyboard keys. """
F = 3 if IS_DARWIN else 41
E = 14 if IS_DARWIN else 26
R = 15 if IS_DARWIN else 27
T = 17 if IS_DARWIN else 28
P = 35 if IS_DARWIN else 33
S = 1 if IS_DARWIN else 39
H = 4 if IS_DARWIN else 43
L = 37 if IS_DARWIN else 46
X = 7 if IS_DARWIN else 53
C = 8 if IS_DARWIN else 54
V = 9 if IS_DARWIN else 55
W = 13 if IS_DARWIN else 25
Z = 6 if IS_DARWIN else 52
INSERT = -1 if IS_DARWIN else 118
HOME = -1 if IS_DARWIN else 110
END = -1 if IS_DARWIN else 115
UP = 126 if IS_DARWIN else 111
DOWN = 125 if IS_DARWIN else 116
PAGE_UP = -1 if IS_DARWIN else 112
PAGE_DOWN = -1 if IS_DARWIN else 117
LEFT = 123 if IS_DARWIN else 113
RIGHT = 123 if IS_DARWIN else 114
F2 = 120 if IS_DARWIN else 68
F7 = 98 if IS_DARWIN else 73
SPACE = 49 if IS_DARWIN else 65
DELETE = 51 if IS_DARWIN else 119
BACK_SPACE = 76 if IS_DARWIN else 22
CTRL_L = 55 if IS_DARWIN else 37
CTRL_R = 55 if IS_DARWIN else 105
E = 69 if IS_WIN else 26
R = 82 if IS_WIN else 27
T = 84 if IS_WIN else 28
P = 80 if IS_WIN else 33
S = 83 if IS_WIN else 39
F = 70 if IS_WIN else 41
X = 88 if IS_WIN else 53
C = 67 if IS_WIN else 54
V = 86 if IS_WIN else 55
W = 87 if IS_WIN else 25
Z = 90 if IS_WIN else 52
INSERT = 45 if IS_WIN else 118
HOME = 36 if IS_WIN else 110
END = 35 if IS_WIN else 115
UP = 38 if IS_WIN else 111
DOWN = 40 if IS_WIN else 116
PAGE_UP = 33 if IS_WIN else 112
PAGE_DOWN = 34 if IS_WIN else 117
LEFT = 37 if IS_WIN else 113
RIGHT = 39 if IS_WIN else 114
F2 = 113 if IS_WIN else 68
F7 = 118 if IS_WIN else 73
SPACE = 32 if IS_WIN else 65
DELETE = 46 if IS_WIN else 119
BACK_SPACE = 8 if IS_WIN else 22
CTRL_L = 17 if IS_WIN else 37
CTRL_R = 163 if IS_WIN else 105
# Laptop codes
HOME_KP = 79
END_KP = 87

BIN
icon.icns

Binary file not shown.

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -1,19 +1,7 @@
#!/usr/bin/env python3
try:
from Cocoa import NSBundle
except ImportError as e:
print(e)
else:
ns_bundle = NSBundle.mainBundle()
if ns_bundle:
ns_bundle = ns_bundle.localizedInfoDictionary() or ns_bundle.infoDictionary()
if ns_bundle:
ns_bundle["CFBundleName"] = "DemonEditor"
if __name__ == "__main__":
from multiprocessing import set_start_method
from multiprocessing import freeze_support
from app.ui.main_app_window import start_app
set_start_method("fork") # For compatibility [Python > 3.7]
freeze_support()
start_app()