diff --git a/app/eparser/ecommons.py b/app/eparser/ecommons.py
index 026ae2ea..eadaaebc 100644
--- a/app/eparser/ecommons.py
+++ b/app/eparser/ecommons.py
@@ -65,6 +65,19 @@ class Flag(Enum):
return value & 1 << 5
+class Pids(Enum):
+ VIDEO = "c:00"
+ AUDIO = "c:01"
+ TELETEXT = "c:02"
+ PCR = "c:03"
+ AC3 = "c:04"
+ VIDEO_TYPE = "c:05"
+ AUDIO_CHANNEL = "c:06"
+ BIT_STREAM_DELAY = "c:07" # in ms
+ PCM_DELAY = "c:08" # in ms
+ SUBTITLE = "c:09"
+
+
class Inversion(Enum):
Off = "0"
On = "1"
diff --git a/app/ui/main_app_window.py b/app/ui/main_app_window.py
index 47f5cea4..100a60eb 100644
--- a/app/ui/main_app_window.py
+++ b/app/ui/main_app_window.py
@@ -907,7 +907,12 @@ class MainAppWindow:
if is_only_one_item_selected(paths, self.__main_window):
model_name = get_base_model(model).get_name()
if model_name == self._FAV_LIST_NAME:
+ srv_type = model.get_value(model.get_iter(paths), 5)
+ if srv_type == BqServiceType.IPTV.name or srv_type == BqServiceType.MARKER.name:
+ self.on_rename(view)
+ return
self.on_locate_in_services(view)
+
dialog = ServiceDetailsDialog(self.__main_window, self.__options, self.__services_view)
dialog.show()
diff --git a/app/ui/main_helper.py b/app/ui/main_helper.py
index 99c8a705..379ade6e 100644
--- a/app/ui/main_helper.py
+++ b/app/ui/main_helper.py
@@ -234,7 +234,7 @@ def set_hide(channels, model, paths):
if value == 0 and index is not None:
del flags[index]
else:
- value = "f:{}".format(value) if value > 10 else "f:0{}".format(value)
+ value = "f:{:02d}".format(value)
if index is not None:
flags[index] = value
else:
diff --git a/app/ui/service_details_dialog.glade b/app/ui/service_details_dialog.glade
index 53eb6739..4298b474 100644
--- a/app/ui/service_details_dialog.glade
+++ b/app/ui/service_details_dialog.glade
@@ -357,9 +357,9 @@
2
@@ -392,6 +392,8 @@
4
@@ -446,6 +448,7 @@
True
4
5
+
8
@@ -455,9 +458,11 @@
7
@@ -467,9 +472,11 @@
6
@@ -479,9 +486,11 @@
5
@@ -494,6 +503,7 @@
True
4
4
+
4
@@ -561,6 +571,7 @@
True
4
4
+
1
@@ -598,8 +609,8 @@
False
25
Delays (ms):
- 10
- 10
+ 11
+ 11
0
@@ -633,8 +644,9 @@
10
@@ -647,6 +659,7 @@
True
3
6
+
11
@@ -681,6 +694,7 @@
True
4
4
+
3
@@ -693,6 +707,7 @@
True
4
4
+
2
@@ -790,7 +805,8 @@
True
True
False
- 30
+ 26
+ 26
7
@@ -888,24 +904,6 @@
0
-
-
-
- 0
- 1
-
-
True
@@ -923,6 +921,7 @@
True
10
10
+
1
@@ -946,6 +945,7 @@
True
10
10
+
2
@@ -1075,6 +1075,9 @@
True
True
+ 15
+ 15
+
7
@@ -1092,6 +1095,24 @@
0
+
+
+ True
+ False
+ sat_pos_list_store
+ 0
+
+
+
+ 0
+
+
+
+
+ 0
+ 1
+
+
False
@@ -1123,8 +1144,9 @@
True
True
- 10
- 10
+ 5
+ 8
+
0
@@ -1146,8 +1168,9 @@
True
True
- 10
- 10
+ 7
+ 8
+
1
@@ -1290,8 +1313,9 @@
True
False
True
- 5
- 10
+ 7
+ 7
+
8
@@ -1315,7 +1339,8 @@
False
True
7
- 10
+ 8
+
6
@@ -1338,8 +1363,9 @@
True
False
True
- 5
- 10
+ 7
+ 8
+
7
diff --git a/app/ui/service_details_dialog.py b/app/ui/service_details_dialog.py
index a565fc77..74a25eca 100644
--- a/app/ui/service_details_dialog.py
+++ b/app/ui/service_details_dialog.py
@@ -1,26 +1,13 @@
-from enum import Enum
+import re
from functools import lru_cache
from app.commons import run_idle
from app.eparser import Service, get_satellites
-from app.eparser.ecommons import MODULATION, Inversion, ROLL_OFF, Pilot, Flag
+from app.eparser.ecommons import MODULATION, Inversion, ROLL_OFF, Pilot, Flag, Pids
from app.properties import Profile
from app.ui.dialogs import show_dialog, DialogType
-from . import Gtk, UI_RESOURCES_PATH
-from .main_helper import is_only_one_item_selected
-
-
-class Pids(Enum):
- VIDEO = "c:00"
- AUDIO = "c:01"
- TELETEXT = "c:02"
- PCR = "c:03"
- AC3 = "c:04"
- VIDEO_TYPE = "c:05"
- AUDIO_CHANNEL = "c:06"
- BIT_STREAM_DELAY = "c:07" # in ms
- PCM_DELAY = "c:08" # in ms
- SUBTITLE = "c:09"
+from app.ui.main_helper import get_base_model
+from . import Gtk, Gdk, UI_RESOURCES_PATH
@lru_cache(maxsize=1)
@@ -29,10 +16,17 @@ def get_sat_positions(path):
class ServiceDetailsDialog:
+
+ _DIGIT_ENTRY_ELEMENTS = ("id_entry", "bitstream_entry", "pcm_entry", "video_pid_entry", "pcr_pid_entry",
+ "audio_pid_entry", "ac3_pid_entry", "ac3plus_pid_entry", "acc_pid_entry", "freq_entry",
+ "he_acc_pid_entry", "teletext_pid_entry", "transponder_id_entry", "network_id_entry",
+ "rate_entry", "pls_code_entry", "stream_id_entry", "flags_entry", "namespace_entry")
+
def __init__(self, transient, options, view):
handlers = {"on_system_changed": self.on_system_changed,
"on_save": self.on_save,
- "on_create_new": self.on_create_new}
+ "on_create_new": self.on_create_new,
+ "on_digit_entry_changed": self.on_digit_entry_changed}
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "service_details_dialog.glade")
@@ -44,33 +38,47 @@ class ServiceDetailsDialog:
self._satellites_xml_path = options.get(self._profile.value)["data_dir_path"] + "satellites.xml"
self._services_view = view
self._old_service = None
+ self._current_model = None
+ self._pattern = re.compile("\D")
+ # style
+ self._style_provider = Gtk.CssProvider()
+ self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
+ # initialize only digit elements
+ self._digit_elements = {k: builder.get_object(k) for k in self._DIGIT_ENTRY_ELEMENTS}
+ for elem in self._digit_elements.values():
+ elem.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
+ Gtk.STYLE_PROVIDER_PRIORITY_USER)
+ self._id_entry = self._digit_elements.get("id_entry")
+ self._bitstream_entry = self._digit_elements.get("bitstream_entry")
+ self._pcm_entry = self._digit_elements.get("pcm_entry")
+ self._video_pid_entry = self._digit_elements.get("video_pid_entry")
+ self._pcr_pid_entry = self._digit_elements.get("pcr_pid_entry")
+ self._audio_pid_entry = self._digit_elements.get("audio_pid_entry")
+ self._ac3_pid_entry = self._digit_elements.get("ac3_pid_entry")
+ self._ac3plus_pid_entry = self._digit_elements.get("ac3plus_pid_entry")
+ self._acc_pid_entry = self._digit_elements.get("acc_pid_entry")
+ self._he_acc_pid_entry = self._digit_elements.get("he_acc_pid_entry")
+ self._teletext_pid_entry = self._digit_elements.get("teletext_pid_entry")
+ self._transponder_id_entry = self._digit_elements.get("transponder_id_entry")
+ self._network_id_entry = self._digit_elements.get("network_id_entry")
+ self._freq_entry = self._digit_elements.get("freq_entry")
+ self._rate_entry = self._digit_elements.get("rate_entry")
+ self._pls_code_entry = self._digit_elements.get("pls_code_entry")
+ self._stream_id_entry = self._digit_elements.get("stream_id_entry")
+ self._flags_entry = self._digit_elements.get("flags_entry")
+ self._namespace_entry = self._digit_elements.get("namespace_entry")
# Service elements
self._name_entry = builder.get_object("name_entry")
self._package_entry = builder.get_object("package_entry")
- self._id_entry = builder.get_object("id_entry")
self._service_type_combo_box = builder.get_object("service_type_combo_box")
self._cas_entry = builder.get_object("cas_entry")
- self._bitstream_entry = builder.get_object("bitstream_entry")
- self._pcm_entry = builder.get_object("pcm_entry")
self._reference_entry = builder.get_object("reference_entry")
- self._video_pid_entry = builder.get_object("video_pid_entry")
- self._pcr_pid_entry = builder.get_object("pcr_pid_entry")
- self._audio_pid_entry = builder.get_object("audio_pid_entry")
- self._ac3_pid_entry = builder.get_object("ac3_pid_entry")
- self._ac3plus_pid_entry = builder.get_object("ac3plus_pid_entry")
- self._acc_pid_entry = builder.get_object("acc_pid_entry")
- self._he_acc_pid_entry = builder.get_object("he_acc_pid_entry")
- self._teletext_pid_entry = builder.get_object("teletext_pid_entry")
self._keep_check_button = builder.get_object("keep_check_button")
self._hide_check_button = builder.get_object("hide_check_button")
self._use_pids_check_button = builder.get_object("use_pids_check_button")
self._new_check_button = builder.get_object("new_check_button")
# Transponder elements
self._sat_pos_combo_box = builder.get_object("sat_pos_combo_box")
- self._transponder_id_entry = builder.get_object("transponder_id_entry")
- self._network_id_entry = builder.get_object("network_id_entry")
- self._freq_entry = builder.get_object("freq_entry")
- self._rate_entry = builder.get_object("rate_entry")
self._pol_combo_box = builder.get_object("pol_combo_box")
self._fec_combo_box = builder.get_object("fec_combo_box")
self._sys_combo_box = builder.get_object("sys_combo_box")
@@ -79,12 +87,10 @@ class ServiceDetailsDialog:
self._rolloff_combo_box = builder.get_object("rolloff_combo_box")
self._pilot_combo_box = builder.get_object("pilot_combo_box")
self._pls_mode_combo_box = builder.get_object("pls_mode_combo_box")
- self._pls_code_entry = builder.get_object("pls_code_entry")
- self._stream_id_entry = builder.get_object("stream_id_entry")
- self._flags_entry = builder.get_object("flags_entry")
- self._namespace_entry = builder.get_object("namespace_entry")
+
self._DVB_S2_ELEMENTS = (self._mod_combo_box, self._rolloff_combo_box, self._pilot_combo_box,
self._pls_mode_combo_box, self._pls_code_entry, self._stream_id_entry)
+
self.update_data_elements()
@run_idle
@@ -92,6 +98,7 @@ class ServiceDetailsDialog:
model, paths = self._services_view.get_selection().get_selected_rows()
srv = Service(*model[paths][:])
self._old_service = srv
+ self._current_model = get_base_model(model)
# Service
self._name_entry.set_text(srv.service)
self._package_entry.set_text(srv.package)
@@ -112,20 +119,30 @@ class ServiceDetailsDialog:
@run_idle
def init_enigma2_service_data(self, srv):
""" Service data initialisation """
- flags = srv.flags_cas.split(",")
-
- cas = list(filter(lambda x: x.startswith("C:"), flags))
- if cas:
- self._cas_entry.set_text(",".join(cas))
-
- flags = list(filter(lambda x: x.startswith("f:"), flags))
+ flags = srv.flags_cas
if flags:
- value = int(flags[0][2:])
+ flags = flags.split(",")
+ self.init_enigma2_flags(flags)
+ self.init_enigma2_pids(flags)
+ self.init_enigma2_cas(flags)
+
+ self._reference_entry.set_text(srv.picon_id.replace("_", ":").rstrip(".png"))
+
+ def init_enigma2_flags(self, flags):
+ f_flags = list(filter(lambda x: x.startswith("f:"), flags))
+ if f_flags:
+ value = int(f_flags[0][2:])
self._keep_check_button.set_active(Flag.is_keep(value))
self._hide_check_button.set_active(Flag.is_hide(value))
self._use_pids_check_button.set_active(Flag.is_pids(value))
self._new_check_button.set_active(Flag.is_new(value))
+ def init_enigma2_cas(self, flags):
+ cas = list(filter(lambda x: x.startswith("C:"), flags))
+ if cas:
+ self._cas_entry.set_text(",".join(cas))
+
+ def init_enigma2_pids(self, flags):
pids = list(filter(lambda x: x.startswith("c:"), flags))
if pids:
for pid in pids:
@@ -150,8 +167,6 @@ class ServiceDetailsDialog:
elif pid.startswith(Pids.SUBTITLE.value):
pass
- self._reference_entry.set_text(srv.picon_id.replace("_", ":").rstrip(".png"))
-
@run_idle
def init_enigma2_transponder_data(self, srv):
""" Transponder data initialisation """
@@ -187,6 +202,10 @@ class ServiceDetailsDialog:
def on_system_changed(self, box):
for elem in self._DVB_S2_ELEMENTS:
elem.set_sensitive(box.get_active())
+ self._pls_code_entry.set_name("GtkEntry")
+ self._pls_code_entry.set_text("")
+ self._stream_id_entry.set_name("GtkEntry")
+ self._stream_id_entry.set_text("")
def show(self):
response = self._dialog.run()
@@ -200,27 +219,33 @@ class ServiceDetailsDialog:
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
return
- srv = Service(flags_cas=self.get_flags(),
- transponder_type="s",
- coded=None,
- service=self._name_entry.get_text(),
- locked=self._old_service.locked,
- hide=None,
- package=self._package_entry.get_text(),
- service_type=self._service_type_combo_box.get_active_id(),
- picon=self._old_service.picon,
- picon_id=self._old_service.picon_id,
- ssid=self._id_entry.get_text(),
- freq=self._freq_entry.get_text(),
- rate=self._rate_entry.get_text(),
- pol=self._pol_combo_box.get_active_id(),
- fec=self._fec_combo_box.get_active_id(),
- system=self._sys_combo_box.get_active_id(),
- pos=self._pol_combo_box.get_active_id(),
- data_id=self.get_data_id(),
- fav_id=self.get_fav_id(),
- transponder=self.get_transponder_data())
- show_dialog(DialogType.ERROR, transient=self._dialog, text="Not implemented yet!")
+ self.update_data_in_model(Service(flags_cas=self.get_flags(),
+ transponder_type="s",
+ coded=None,
+ service=self._name_entry.get_text(),
+ locked=self._old_service.locked,
+ hide=None,
+ package=self._package_entry.get_text(),
+ service_type=self._service_type_combo_box.get_active_id(),
+ picon=self._old_service.picon,
+ picon_id=self._old_service.picon_id,
+ ssid=self._id_entry.get_text(),
+ freq=self._freq_entry.get_text(),
+ rate=self._rate_entry.get_text(),
+ pol=self._pol_combo_box.get_active_id(),
+ fec=self._fec_combo_box.get_active_id(),
+ system=self._sys_combo_box.get_active_id(),
+ pos=self._sat_pos_combo_box.get_active_id(),
+ data_id=self.get_data_id(),
+ fav_id=self.get_fav_id(),
+ transponder=self.get_transponder_data()))
+
+ def update_data_in_model(self, srv: Service):
+ fav_id = self._old_service.fav_id
+ for row in get_base_model(self._current_model):
+ if row[18] == fav_id:
+ self._current_model.set(self._current_model.get_iter(row.path), {i: v for i, v in enumerate(srv)})
+ break
def on_create_new(self, item):
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
@@ -230,28 +255,69 @@ class ServiceDetailsDialog:
def get_flags(self):
if self._profile is Profile.ENIGMA_2:
- pass
+ return self.get_enigma2_flags()
elif self._profile is Profile.NEUTRINO_MP:
- pass
+ return self._old_service.flags_cas
+
+ def get_enigma2_flags(self):
+ flags = []
+ # cas
+ cas = self._cas_entry.get_text()
+ if cas:
+ flags.append(cas)
+ # pids
+ video_pid = self._video_pid_entry.get_text()
+ if video_pid:
+ flags.append("{}{:04x}".format(Pids.VIDEO.value, int(video_pid)))
+ audio_pid = self._audio_pid_entry.get_text()
+ if audio_pid:
+ flags.append("{}{:04x}".format(Pids.AUDIO.value, int(audio_pid)))
+ teletext_pid = self._teletext_pid_entry.get_text()
+ if teletext_pid:
+ flags.append("{}{:04x}".format(Pids.TELETEXT.value, int(teletext_pid)))
+ pcr_pid = self._pcr_pid_entry.get_text()
+ if pcr_pid:
+ flags.append("{}{:04x}".format(Pids.PCR.value, int(pcr_pid)))
+ ac3_pid = self._ac3_pid_entry.get_text()
+ if ac3_pid:
+ flags.append("{}{:04x}".format(Pids.AC3.value, int(ac3_pid)))
+ bitstream_pid = self._bitstream_entry.get_text()
+ if bitstream_pid:
+ flags.append("{}{:04x}".format(Pids.BIT_STREAM_DELAY.value, int(bitstream_pid)))
+ pcm_pid = self._pcm_entry.get_text()
+ if pcm_pid:
+ flags.append("{}{:04x}".format(Pids.PCM_DELAY.value, int(pcm_pid)))
+ # flags
+ f_flags = Flag.KEEP.value if self._keep_check_button.get_active() else 0
+ f_flags = f_flags + Flag.HIDE.value if self._hide_check_button.get_active() else f_flags
+ f_flags = f_flags + Flag.PIDS.value if self._use_pids_check_button.get_active() else f_flags
+ f_flags = f_flags + Flag.NEW.value if self._new_check_button.get_active() else f_flags
+ if f_flags:
+ flags.append("f:{:02x}".format(f_flags))
+
+ return ",".join(flags)
def get_data_id(self):
if self._profile is Profile.ENIGMA_2:
- pass
+ return self._old_service.data_id
elif self._profile is Profile.NEUTRINO_MP:
- pass
+ return self._old_service.data_id
def get_fav_id(self):
if self._profile is Profile.ENIGMA_2:
- pass
+ return self._old_service.fav_id
elif self._profile is Profile.NEUTRINO_MP:
- pass
+ return self._old_service.fav_id
def get_transponder_data(self):
if self._profile is Profile.ENIGMA_2:
if self._sys_combo_box.get_active_id() == "DVB-S2":
- pass
+ return self._old_service.transponder
elif self._profile is Profile.NEUTRINO_MP:
- pass
+ return self._old_service.transponder
+
+ def on_digit_entry_changed(self, entry):
+ entry.set_name("digit-entry" if self._pattern.search(entry.get_text()) else "GtkEntry")
if __name__ == "__main__":