Neutrino-MP settings profile skeleton

This commit is contained in:
Dmitriy Yefremov
2017-12-30 21:51:57 +03:00
parent 37d4cbe1f4
commit d723ecd7f7
8 changed files with 302 additions and 90 deletions

View File

@@ -1,4 +1,7 @@
# DemonEditor
Experimental branch! For support Neutrino-MP.
Enigma2 channel and satellites list editor for GNU/Linux.
Focused on the convenience of working in lists from the keyboard.
The mouse is also fully supported (Drag and Drop etc)

View File

@@ -1,25 +1,35 @@
import json
import os
from enum import Enum
from pathlib import Path
CONFIG_PATH = str(Path.home()) + "/.config/demon-editor/"
CONFIG_FILE = CONFIG_PATH + "config.json"
DATA_PATH = "data/"
class Profile(Enum):
""" Profiles for settings """
ENIGMA_2 = "0"
NEUTRINO_MP = "1"
def get_config():
os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True) # create dir if not exist
os.makedirs(os.path.dirname(DATA_PATH), exist_ok=True)
if not os.path.isfile(CONFIG_FILE) or os.stat(CONFIG_FILE).st_size == 0:
with open(CONFIG_FILE, "w") as default_config_file:
json.dump(get_default_settings(), default_config_file)
reset_config()
with open(CONFIG_FILE, "r") as config_file:
return json.load(config_file)
def reset_config():
with open(CONFIG_FILE, "w") as default_config_file:
json.dump(get_default_settings(), default_config_file)
def write_config(config):
assert isinstance(config, dict)
with open(CONFIG_FILE, "w") as config_file:
@@ -27,12 +37,22 @@ def write_config(config):
def get_default_settings():
return {"host": "127.0.0.1", "port": "21",
return {
Profile.ENIGMA_2.value: {
"host": "127.0.0.1", "port": "21",
"user": "root", "password": "root",
"services_path": "/etc/enigma2/",
"user_bouquet_path": "/etc/enigma2/",
"satellites_xml_path": "/etc/tuxbox/",
"data_dir_path": DATA_PATH}
"data_dir_path": DATA_PATH},
Profile.NEUTRINO_MP.value: {
"host": "127.0.0.1", "port": "21",
"user": "root", "password": "root",
"services_path": "/var/tuxbox/config/zapit/",
"user_bouquet_path": "/var/tuxbox/config/zapit/",
"satellites_xml_path": "/var/tuxbox/config/",
"data_dir_path": DATA_PATH},
"profile": Profile.ENIGMA_2.value}
if __name__ == "__main__":

View File

@@ -9,7 +9,7 @@
<property name="icon_name">system-help</property>
<property name="type_hint">normal</property>
<property name="program_name">DemonEditor</property>
<property name="version">0.1.2 Pre-alpha</property>
<property name="version">0.2.0 Pre-alpha</property>
<property name="copyright" translatable="yes">2017 Dmitriy Yefremov
dmitry.v.yefremov@gmail.com
</property>
@@ -613,7 +613,10 @@ dmitry.v.yefremov@gmail.com
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox3">
<property name="can_focus">False</property>
<property name="margin_left">2</property>
<property name="margin_right">2</property>
<property name="margin_top">5</property>
<property name="margin_bottom">2</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
@@ -628,11 +631,12 @@ dmitry.v.yefremov@gmail.com
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">0</property>
</packing>
</child>
<child>
@@ -642,6 +646,7 @@ dmitry.v.yefremov@gmail.com
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
@@ -733,7 +738,7 @@ dmitry.v.yefremov@gmail.com
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">root</property>
<property name="primary_icon_name">emblem-personal</property>
<property name="primary_icon_name">avatar-default-symbolic</property>
<property name="primary_icon_activatable">False</property>
</object>
<packing>
@@ -748,7 +753,7 @@ dmitry.v.yefremov@gmail.com
<property name="visibility">False</property>
<property name="invisible_char">●</property>
<property name="text" translatable="yes">root</property>
<property name="primary_icon_name">emblem-nowrite</property>
<property name="primary_icon_name">emblem-readonly</property>
<property name="primary_icon_activatable">False</property>
<property name="input_purpose">password</property>
</object>
@@ -778,74 +783,177 @@ dmitry.v.yefremov@gmail.com
</packing>
</child>
<child>
<object class="GtkGrid" id="grid2">
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label5">
<object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Services and Bouquets files:</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Services and Bouquets files:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="services_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/etc/enigma2/</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">User bouquet files:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="user_bouquet_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/etc/enigma2/</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Satellites.xml file:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="satellites_xml_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/etc/tuxbox/</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="services_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/etc/enigma2/</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label6">
<object class="GtkSeparator" id="separator5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">User bouquet files:</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="user_bouquet_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/etc/enigma2/</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<object class="GtkBox" id="box3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Satellites.xml file:</property>
<property name="margin_right">5</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Active profile:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="enigma_radio_button">
<property name="label" translatable="yes">Enigma2 </property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">neutrino_radio_button</property>
<signal name="toggled" handler="on_profile_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="neutrino_radio_button">
<property name="label" translatable="yes">Neutrino-MP
(experimental)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">enigma_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="reset_button">
<property name="label" translatable="yes">Reset profile</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="xalign">0.49000000953674316</property>
<signal name="clicked" handler="on_reset" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="satellites_xml_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/etc/tuxbox/</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>

View File

@@ -25,11 +25,12 @@ def show_dialog(dialog_type: DialogType, transient, text=None, options=None, act
dialog.set_action(action_type)
if file_filter is not None:
dialog.add_filter(file_filter)
dialog.set_current_folder(options["data_dir_path"])
path = options.get(options.get("profile")).get("data_dir_path")
dialog.set_current_folder(path)
response = dialog.run()
if response == -12: # -12 for fix assertion 'gtk_widget_get_can_default (widget)' failed
path = options["data_dir_path"]
if dialog.get_filename():
path = dialog.get_filename()
if action_type is not Gtk.FileChooserAction.OPEN:

View File

@@ -7,7 +7,7 @@ from app.eparser import get_blacklist, write_blacklist, parse_m3u
from app.eparser import get_channels, get_bouquets, write_bouquets, write_channels, Bouquets, Bouquet, Channel
from app.eparser.__constants import CAS, FLAG
from app.eparser.bouquets import BqServiceType
from app.properties import get_config, write_config
from app.properties import get_config, write_config, Profile
from . import Gtk, Gdk, UI_RESOURCES_PATH
from .dialogs import show_dialog, DialogType
from .download_dialog import show_download_dialog
@@ -83,6 +83,7 @@ class MainAppWindow:
"on_locate_in_services": self.on_locate_in_services}
self.__options = get_config()
self.__profile = self.__options.get("profile")
# Used for copy/paste. When adding the previous data will not be deleted.
# Clearing only after the insertion!
self.__rows_buffer = []
@@ -105,7 +106,9 @@ class MainAppWindow:
self.__services_model = builder.get_object("services_list_store")
self.__bouquets_model = builder.get_object("bouquets_tree_store")
self.__status_bar = builder.get_object("status_bar")
self.__status_bar.push(0, "Current IP: " + self.__options["host"])
self.__profile_label = builder.get_object("profile_label")
self.__status_bar.push(0, "Current IP: " + self.__options.get(self.__profile).get("host"))
# dynamically active elements depending on the selected view
self.__tool_elements = {k: builder.get_object(k) for k in self.__DYNAMIC_ELEMENTS}
self.__cas_label = builder.get_object("cas_label")
@@ -581,8 +584,11 @@ class MainAppWindow:
v.get_selection().unselect_all()
def on_preferences(self, item):
show_settings_dialog(self.__main_window, self.__options)
self.__status_bar.push(0, "Current IP: " + self.__options["host"])
response = show_settings_dialog(self.__main_window, self.__options)
if response != Gtk.ResponseType.CANCEL:
profile = self.__options.get("profile")
self.__status_bar.push(0, "Current IP: " + self.__options.get(profile).get("host"))
self.__profile_label.set_text("Enigma 2 v.4" if Profile(profile) is Profile.ENIGMA_2 else "Neutrino-MP")
def on_tree_view_key_release(self, view, event):
""" Handling keystrokes """

View File

@@ -1660,13 +1660,46 @@
<property name="spacing">2</property>
<property name="homogeneous">True</property>
<child>
<placeholder/>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Profile:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="profile_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Enigma 2 v.4</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ver_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Ver. 0.1.2 Pre-alpha</property>
<property name="label" translatable="yes">Ver. 0.2.0 Pre-alpha</property>
<property name="xalign">0.94999998807907104</property>
</object>
<packing>

View File

@@ -20,7 +20,7 @@ class SatellitesDialog:
_aggr = [None for x in range(9)] # aggregate
def __init__(self, transient, options):
self._data_path = options["data_dir_path"] + "satellites.xml"
self._data_path = options.get(options.get("profile")).get("data_dir_path") + "satellites.xml"
self._options = options
handlers = {"on_open": self.on_open,

View File

@@ -1,55 +1,96 @@
from app.properties import write_config
from app.properties import write_config, Profile, get_default_settings
from app.ui.dialogs import show_dialog, DialogType
from . import Gtk, UI_RESOURCES_PATH
def show_settings_dialog(transient, options):
SettingsDialog(transient, options)
return SettingsDialog(transient, options).show()
class SettingsDialog:
def __init__(self, transient, options):
handlers = {"on_data_dir_field_icon_press": self.on_data_dir_field_icon_press}
handlers = {"on_data_dir_field_icon_press": self.on_data_dir_field_icon_press,
"on_profile_changed": self.on_profile_changed,
"on_reset": self.on_reset}
builder = Gtk.Builder()
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade", ("settings_dialog", ))
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade", ("settings_dialog",))
builder.connect_signals(handlers)
self._options = options
self._dialog = builder.get_object("settings_dialog")
self._dialog.set_transient_for(transient)
self._host_field = builder.get_object("host_field")
self._host_field.set_text(options["host"])
self._port_field = builder.get_object("port_field")
self._port_field.set_text(options["port"])
self._login_field = builder.get_object("login_field")
self._login_field.set_text(options["user"])
self._password_field = builder.get_object("password_field")
self._password_field.set_text(options["password"])
self._services_field = builder.get_object("services_field")
self._services_field.set_text(options["services_path"])
self._user_bouquet_field = builder.get_object("user_bouquet_field")
self._user_bouquet_field.set_text(options["user_bouquet_path"])
self._satellites_xml_field = builder.get_object("satellites_xml_field")
self._satellites_xml_field.set_text(options["satellites_xml_path"])
self._data_dir_field = builder.get_object("data_dir_field")
self._data_dir_field.set_text(options["data_dir_path"])
self._enigma_radio_button = builder.get_object("enigma_radio_button")
self._neutrino_radio_button = builder.get_object("neutrino_radio_button")
if self._dialog.run() == Gtk.ResponseType.OK:
options["host"] = self._host_field.get_text()
options["port"] = self._port_field.get_text()
options["user"] = self._login_field.get_text()
options["password"] = self._password_field.get_text()
options["services_path"] = self._services_field.get_text()
options["user_bouquet_path"] = self._user_bouquet_field.get_text()
options["satellites_xml_path"] = self._satellites_xml_field.get_text()
options["data_dir_path"] = self._data_dir_field.get_text()
write_config(options)
self._options = options
self._active_profile = options.get("profile")
self.set_settings()
self._neutrino_radio_button.set_active(Profile(self._active_profile) is Profile.NEUTRINO_MP)
def show(self):
response = self._dialog.run()
if response == Gtk.ResponseType.OK:
self.apply_settings()
write_config(self._options)
self._dialog.destroy()
return response
def on_data_dir_field_icon_press(self, entry, icon, event_button):
response = show_dialog(dialog_type=DialogType.CHOOSER, transient=self._dialog, options=self._options)
if response != Gtk.ResponseType.CANCEL:
entry.set_text(response)
def on_profile_changed(self, item):
self.set_profile(Profile.ENIGMA_2 if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP)
def set_profile(self, profile):
self._active_profile = profile.value
self.set_settings()
def on_reset(self, item):
def_settings = get_default_settings()
for key in def_settings:
current = self._options.get(key)
if type(current) is str:
continue
default = def_settings.get(key)
for k in default:
current[k] = default.get(k)
self.set_settings()
def set_settings(self):
options = self._options.get(self._active_profile)
self._host_field.set_text(options.get("host"))
self._port_field.set_text(options.get("port"))
self._login_field.set_text(options.get("user"))
self._password_field.set_text(options.get("password"))
self._services_field.set_text(options.get("services_path"))
self._user_bouquet_field.set_text(options.get("user_bouquet_path"))
self._satellites_xml_field.set_text(options.get("satellites_xml_path"))
self._data_dir_field.set_text(options.get("data_dir_path"))
def apply_settings(self):
profile = Profile.ENIGMA_2.value if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP.value
self._active_profile = profile
self._options["profile"] = profile
options = self._options.get(self._active_profile)
options["host"] = self._host_field.get_text()
options["port"] = self._port_field.get_text()
options["user"] = self._login_field.get_text()
options["password"] = self._password_field.get_text()
options["services_path"] = self._services_field.get_text()
options["user_bouquet_path"] = self._user_bouquet_field.get_text()
options["satellites_xml_path"] = self._satellites_xml_field.get_text()
options["data_dir_path"] = self._data_dir_field.get_text()
if __name__ == "__main__":
pass