Files
DemonEditor/app/ui/main_helper.py

707 lines
26 KiB
Python
Raw Normal View History

2021-08-30 15:04:15 +03:00
# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
2022-01-04 20:39:59 +03:00
# Copyright (c) 2018-2022 Dmitriy Yefremov
2021-08-30 15:04:15 +03:00
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Author: Dmitriy Yefremov
#
2021-11-03 12:30:23 +03:00
""" Helper module for the GUI. """
__all__ = ("insert_marker", "move_items", "rename", "ViewTarget", "set_flags", "locate_in_services",
2022-01-04 20:39:59 +03:00
"scroll_to", "get_base_model", "copy_picon_reference", "assign_picons", "remove_picon",
"is_only_one_item_selected", "gen_bouquets", "BqGenType", "get_selection",
"get_model_data", "remove_all_unused_picons", "get_picon_pixbuf", "get_base_itrs", "get_iptv_url",
"update_entry_data", "append_text_to_tview", "on_popup_menu")
2021-11-03 12:30:23 +03:00
2018-01-31 00:13:42 +03:00
import os
2018-02-01 14:02:59 +03:00
import shutil
2021-08-24 16:19:39 +03:00
from collections import defaultdict
2022-01-28 00:37:02 +03:00
from pathlib import Path
2020-06-22 19:45:30 +03:00
from urllib.parse import unquote
2019-01-27 23:28:53 +03:00
2018-08-18 10:21:40 +03:00
from gi.repository import GdkPixbuf, GLib
2018-01-31 00:13:42 +03:00
2018-01-01 23:42:40 +03:00
from app.eparser import Service
from app.eparser.ecommons import Flag, BouquetService, Bouquet, BqType
2018-01-01 17:28:19 +03:00
from app.eparser.enigma.bouquets import BqServiceType, to_bouquet_id
2022-01-04 20:39:59 +03:00
from app.settings import SettingsType, SEP, IS_WIN, IS_DARWIN, IS_LINUX
from .dialogs import show_dialog, DialogType, get_message
2020-01-12 00:33:33 +03:00
from .uicommons import ViewTarget, BqGenType, Gtk, Gdk, HIDE_ICON, LOCKED_ICON, KeyboardKey, Column
2017-12-20 16:46:15 +03:00
2017-12-24 01:40:30 +03:00
# ***************** Markers *******************#
2017-12-23 22:25:29 +03:00
2020-05-23 15:16:31 +03:00
def insert_marker(view, bouquets, selected_bouquet, services, parent_window, m_type=BqServiceType.MARKER):
2017-12-20 16:46:15 +03:00
"""" Inserts marker into bouquet services list. """
2020-05-23 15:16:31 +03:00
fav_id, text = "1:832:D:0:0:0:0:0:0:0:\n", None
2017-12-20 16:46:15 +03:00
2020-05-23 15:16:31 +03:00
if m_type is BqServiceType.MARKER:
response = show_dialog(DialogType.INPUT, parent_window)
if response == Gtk.ResponseType.CANCEL:
return
2017-12-20 16:46:15 +03:00
2020-05-23 15:16:31 +03:00
if not response.strip():
show_dialog(DialogType.ERROR, parent_window, "The text of marker is empty, please try again!")
return
2022-01-04 20:39:59 +03:00
fav_id = f"1:64:0:0:0:0:0:0:0:0::{response}\n#DESCRIPTION {response}\n"
2020-05-23 15:16:31 +03:00
text = response
s_type = m_type.name
2017-12-20 16:46:15 +03:00
model, paths = view.get_selection().get_selected_rows()
2020-05-23 15:16:31 +03:00
marker = (None, None, text, None, None, s_type, None, fav_id, None, None, None)
2018-02-06 13:56:17 +03:00
itr = model.insert_before(model.get_iter(paths[0]), marker) if paths else model.insert(0, marker)
2017-12-20 16:46:15 +03:00
bouquets[selected_bouquet].insert(model.get_path(itr)[0], fav_id)
2020-05-23 15:16:31 +03:00
services[fav_id] = Service(None, None, None, text, None, None, None, s_type, *[None] * 9, 0, fav_id, None)
2017-12-20 16:46:15 +03:00
2017-12-24 01:40:30 +03:00
# ***************** Movement *******************#
2017-12-23 22:25:29 +03:00
def move_items(key, view: Gtk.TreeView):
""" Move items in the tree view """
2017-12-23 22:25:29 +03:00
selection = view.get_selection()
model, paths = selection.get_selected_rows()
2020-09-24 23:17:15 +03:00
if not paths:
return
2017-12-23 22:25:29 +03:00
2020-09-24 23:17:15 +03:00
is_tree_store = type(model) is Gtk.TreeStore
mod_length = len(model)
if not is_tree_store and mod_length == len(paths):
return
2020-09-24 23:17:15 +03:00
cursor_path = view.get_cursor()[0]
max_path = Gtk.TreePath.new_from_indices((mod_length,))
min_path = Gtk.TreePath.new_from_indices((0,))
if is_tree_store:
is_tree_store = False
parent_paths = list(filter(lambda p: p.get_depth() == 1, paths))
if parent_paths:
paths = parent_paths
min_path = model.get_path(model.get_iter_first())
view.collapse_all()
if mod_length == len(paths):
return
else:
if not is_some_level(paths):
return
parent_itr = model.iter_parent(model.get_iter(paths[0]))
parent_index = model.get_path(parent_itr)
children_num = model.iter_n_children(parent_itr)
if key in (KeyboardKey.PAGE_DOWN, KeyboardKey.END, KeyboardKey.END_KP, KeyboardKey.PAGE_DOWN_KP):
children_num -= 1
2022-01-04 20:39:59 +03:00
min_path = Gtk.TreePath.new_from_string(f"{parent_index}:{0}")
max_path = Gtk.TreePath.new_from_string(f"{parent_index}:{children_num}")
2020-09-24 23:17:15 +03:00
is_tree_store = True
if key is KeyboardKey.UP:
top_path = Gtk.TreePath(paths[0])
set_cursor(top_path, paths, selection, view)
top_path.prev()
move_up(top_path, model, paths)
elif key is KeyboardKey.DOWN:
down_path = Gtk.TreePath(paths[-1])
set_cursor(down_path, paths, selection, view)
down_path.next()
if down_path < max_path:
move_down(down_path, model, paths)
else:
max_path.prev()
move_down(max_path, model, paths)
elif key in (KeyboardKey.PAGE_UP, KeyboardKey.HOME, KeyboardKey.PAGE_UP_KP, KeyboardKey.HOME_KP):
move_up(min_path if is_tree_store else cursor_path, model, paths)
elif key in (KeyboardKey.PAGE_DOWN, KeyboardKey.END, KeyboardKey.END_KP, KeyboardKey.PAGE_DOWN_KP):
move_down(max_path if is_tree_store else cursor_path, model, paths)
def move_up(top_path, model, paths):
top_iter = model.get_iter(top_path)
for path in paths:
itr = model.get_iter(path)
model.move_before(itr, top_iter)
top_path.next()
top_iter = model.get_iter(top_path)
def move_down(down_path, model, paths):
top_iter = model.get_iter(down_path)
for path in reversed(paths):
itr = model.get_iter(path)
model.move_after(itr, top_iter)
down_path.prev()
top_iter = model.get_iter(down_path)
def is_some_level(paths):
for i in range(1, len(paths)):
prev = paths[i - 1]
current = paths[i]
if len(prev) != len(current) or (len(prev) == 2 and len(current) == 2 and prev[0] != current[0]):
return
return True
2017-12-23 22:25:29 +03:00
2019-01-30 14:39:58 +03:00
def set_cursor(dest_path, paths, selection, view):
view.set_cursor(dest_path, view.get_column(0), False)
for p in paths:
selection.select_path(p)
# ***************** Rename *******************#
2017-12-24 01:40:30 +03:00
2018-10-25 16:00:25 +03:00
def rename(view, parent_window, target, fav_view=None, service_view=None, services=None):
selection = get_selection(view, parent_window)
if not selection:
2017-12-24 01:40:30 +03:00
return
model, paths = selection
2017-12-24 01:40:30 +03:00
itr = model.get_iter(paths)
2018-10-25 16:00:25 +03:00
f_id, srv_name, srv_type = None, None, None
2017-12-24 01:40:30 +03:00
if target is ViewTarget.SERVICES:
name, fav_id = model.get(itr, Column.SRV_SERVICE, Column.SRV_FAV_ID)
2017-12-24 01:40:30 +03:00
f_id = fav_id
response = show_dialog(DialogType.INPUT, parent_window, name)
if response == Gtk.ResponseType.CANCEL:
return
2018-10-25 16:00:25 +03:00
srv_name = response
model.set_value(itr, Column.SRV_SERVICE, response)
2017-12-24 01:40:30 +03:00
if fav_view is not None:
for row in fav_view.get_model():
if row[Column.FAV_ID] == fav_id:
row[Column.FAV_SERVICE] = response
2017-12-24 01:40:30 +03:00
break
elif target is ViewTarget.FAV:
name, srv_type, fav_id = model.get(itr, Column.FAV_SERVICE, Column.FAV_TYPE, Column.FAV_ID)
2017-12-24 01:40:30 +03:00
f_id = fav_id
response = show_dialog(DialogType.INPUT, parent_window, name)
if response == Gtk.ResponseType.CANCEL:
return
2018-10-25 16:00:25 +03:00
srv_name = response
if not model.get_value(itr, Column.FAV_BACKGROUND):
model.set_value(itr, Column.FAV_SERVICE, response)
2017-12-24 01:40:30 +03:00
if service_view is not None:
2018-02-06 13:56:17 +03:00
for row in get_base_model(service_view.get_model()):
if row[Column.SRV_FAV_ID] == fav_id:
row[Column.SRV_SERVICE] = response
2017-12-24 01:40:30 +03:00
break
2018-10-25 16:00:25 +03:00
old_srv = services.get(f_id, None)
if old_srv:
if srv_type == BqServiceType.IPTV.name or srv_type == BqServiceType.MARKER.name:
2018-10-26 19:28:40 +03:00
l, sep, r = f_id.partition("#DESCRIPTION")
old_name = old_srv.service.strip()
new_name = srv_name.strip()
new_fav_id = "".join((new_name.join(l.rsplit(old_name, 1)), sep, new_name.join(r.rsplit(old_name, 1))))
2018-10-25 16:00:25 +03:00
services[f_id] = old_srv._replace(service=srv_name, fav_id=new_fav_id)
else:
services[f_id] = old_srv._replace(service=srv_name)
2017-12-24 01:40:30 +03:00
def get_selection(view, parent):
""" Returns (model, paths) if possible """
model, paths = view.get_selection().get_selected_rows()
model = get_base_model(model)
if not paths:
return
elif len(paths) > 1:
show_dialog(DialogType.ERROR, parent, "Please, select only one item!")
return
return model, paths
2017-12-24 16:43:05 +03:00
# ***************** Flags *******************#
def set_flags(flag, services_view, fav_view, services, blacklist):
2017-12-24 16:43:05 +03:00
""" Updates flags for services. Returns True if any was changed. """
target = ViewTarget.SERVICES if services_view.is_focus() else ViewTarget.FAV if fav_view.is_focus() else None
if not target:
return
model, paths = None, None
if target is ViewTarget.SERVICES:
model, paths = services_view.get_selection().get_selected_rows()
elif target is ViewTarget.FAV:
model, paths = fav_view.get_selection().get_selected_rows()
2017-12-24 16:43:05 +03:00
if not paths:
return
2020-06-22 19:45:30 +03:00
paths = get_base_paths(paths, model)
2018-01-25 21:05:24 +03:00
model = get_base_model(model)
if flag is Flag.HIDE:
2017-12-29 19:49:01 +03:00
if target is ViewTarget.SERVICES:
set_hide(services, model, paths)
2017-12-29 19:49:01 +03:00
else:
fav_ids = [model.get_value(model.get_iter(path), Column.FAV_ID) for path in paths]
2018-01-25 21:05:24 +03:00
srv_model = get_base_model(services_view.get_model())
srv_paths = [row.path for row in srv_model if row[Column.SRV_FAV_ID] in fav_ids]
set_hide(services, srv_model, srv_paths)
elif flag is Flag.LOCK:
set_lock(blacklist, services, model, paths, target, services_model=get_base_model(services_view.get_model()))
2017-12-24 16:43:05 +03:00
update_fav_model(fav_view, services)
def update_fav_model(fav_view, services):
for row in get_base_model(fav_view.get_model()):
srv = services.get(row[Column.FAV_ID], None)
if srv:
row[Column.FAV_LOCKED], row[Column.FAV_HIDE] = srv.locked, srv.hide
2017-12-24 16:43:05 +03:00
def set_lock(blacklist, services, model, paths, target, services_model):
col_num = Column.SRV_LOCKED if target is ViewTarget.SERVICES else Column.FAV_LOCKED
2017-12-24 16:43:05 +03:00
locked = has_locked_hide(model, paths, col_num)
ids = []
2022-01-03 00:08:31 +03:00
skip_type = {BqServiceType.MARKER.name, BqServiceType.SPACE.name, BqServiceType.ALT.name}
2017-12-24 16:43:05 +03:00
for path in paths:
itr = model.get_iter(path)
fav_id = model.get_value(itr, Column.SRV_FAV_ID if target is ViewTarget.SERVICES else Column.FAV_ID)
srv = services.get(fav_id, None)
2020-06-22 19:45:30 +03:00
if srv and srv.service_type not in skip_type:
2020-07-18 20:55:15 +03:00
bq_id = srv.data_id if srv.service_type == BqServiceType.IPTV.name else to_bouquet_id(srv)
2018-01-28 23:10:54 +03:00
if not bq_id:
continue
2017-12-24 16:43:05 +03:00
blacklist.discard(bq_id) if locked else blacklist.add(bq_id)
model.set_value(itr, col_num, None if locked else LOCKED_ICON)
services[fav_id] = srv._replace(locked=None if locked else LOCKED_ICON)
ids.append(fav_id)
if target is ViewTarget.FAV and ids:
gen = update_services_model(ids, locked, services_model)
GLib.idle_add(lambda: next(gen, False))
def update_services_model(ids, locked, services_model):
for srv in services_model:
if srv[Column.SRV_FAV_ID] in ids:
srv[Column.SRV_LOCKED] = None if locked else LOCKED_ICON
yield True
2017-12-24 16:43:05 +03:00
def set_hide(services, model, paths):
col_num = Column.SRV_HIDE
2017-12-24 16:43:05 +03:00
hide = has_locked_hide(model, paths, col_num)
for path in paths:
itr = model.get_iter(path)
model.set_value(itr, col_num, None if hide else HIDE_ICON)
2017-12-24 16:43:05 +03:00
flags = [*model.get_value(itr, 0).split(",")]
index, flag = None, None
for i, fl in enumerate(flags):
if fl.startswith("f:"):
index = i
flag = fl
break
value = int(flag[2:]) if flag else 0
if not hide:
if Flag.is_hide(value):
2017-12-24 16:43:05 +03:00
continue # skip if already hidden
value += Flag.HIDE.value
2017-12-24 16:43:05 +03:00
else:
if not Flag.is_hide(value):
2017-12-24 16:43:05 +03:00
continue # skip if already allowed to show
value -= Flag.HIDE.value
2017-12-24 16:43:05 +03:00
2017-12-29 19:49:01 +03:00
if value == 0 and index is not None:
2018-01-02 17:38:01 +03:00
del flags[index]
2017-12-24 16:43:05 +03:00
else:
value = "f:{:02d}".format(value)
2017-12-29 19:49:01 +03:00
if index is not None:
flags[index] = value
else:
flags.append(value)
2017-12-24 16:43:05 +03:00
model.set_value(itr, 0, (",".join(reversed(sorted(flags)))))
fav_id = model.get_value(itr, Column.SRV_FAV_ID)
srv = services.get(fav_id, None)
if srv:
services[fav_id] = srv._replace(hide=None if hide else HIDE_ICON)
2017-12-24 16:43:05 +03:00
def has_locked_hide(model, paths, col_num):
for path in paths:
if model.get_value(model.get_iter(path), col_num):
return True
return False
# ***************** Location *******************#
2022-02-21 12:22:44 +03:00
def locate_in_services(fav_view, services_view, column, parent_window):
""" Locating and scrolling to the service """
model, paths = fav_view.get_selection().get_selected_rows()
if not paths:
return
elif len(paths) > 1:
show_dialog(DialogType.ERROR, parent_window, "Please, select only one item!")
return
fav_id = model.get_value(model.get_iter(paths[0]), Column.FAV_ID)
for index, row in enumerate(services_view.get_model()):
2022-02-21 12:22:44 +03:00
if row[column] == fav_id:
scroll_to(index, services_view)
break
2017-12-25 19:50:35 +03:00
def scroll_to(index, view, paths=None):
""" Scrolling to and selecting given index(path) """
2017-12-25 19:50:35 +03:00
if paths is not None:
view.expand_row(paths[0], 0)
view.scroll_to_cell(index, None)
selection = view.get_selection()
selection.unselect_all()
selection.select_path(index)
2022-01-04 20:39:59 +03:00
# ***************** Picons ********************* #
2018-01-31 00:13:42 +03:00
2022-01-04 20:39:59 +03:00
def get_picon_dialog(transient, title, button_text, multiple=True):
""" Returns a copy dialog with a preview of images [picons -> *.png]. """
dialog = Gtk.FileChooserNative.new(title, transient, Gtk.FileChooserAction.OPEN, button_text)
dialog.set_select_multiple(multiple)
dialog.set_modal(True)
# Filter.
file_filter = Gtk.FileFilter()
file_filter.set_name("*.png")
file_filter.add_pattern("*.png")
file_filter.add_mime_type("image/png") if IS_DARWIN else None
dialog.add_filter(file_filter)
if IS_LINUX:
preview_image = Gtk.Image(margin_right=10)
dialog.set_preview_widget(preview_image)
2018-01-31 00:13:42 +03:00
2022-01-04 20:39:59 +03:00
def update_preview_widget(dlg):
path = dialog.get_preview_filename()
if not path:
return
2018-01-31 00:13:42 +03:00
2022-01-04 20:39:59 +03:00
pix = get_picon_pixbuf(path, 220)
preview_image.set_from_pixbuf(pix)
dlg.set_preview_widget_active(bool(pix))
2018-08-18 10:21:40 +03:00
2022-01-04 20:39:59 +03:00
dialog.connect("update-preview", update_preview_widget)
2018-08-18 10:21:40 +03:00
2022-01-04 20:39:59 +03:00
return dialog
2018-01-31 00:13:42 +03:00
2020-06-06 09:36:11 +03:00
def assign_picons(target, srv_view, fav_view, transient, picons, settings, services, src_path=None, dst_path=None):
""" Assigning picons and returns picons files list. """
2018-02-01 21:43:44 +03:00
view = srv_view if target is ViewTarget.SERVICES else fav_view
model, paths = view.get_selection().get_selected_rows()
2020-06-06 09:36:11 +03:00
picons_files = []
2018-02-01 21:43:44 +03:00
if not src_path:
2022-01-04 20:39:59 +03:00
dialog = get_picon_dialog(transient, get_message("Picon selection"), get_message("Open"), False)
if dialog.run() in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT) or not dialog.get_filenames():
2020-06-06 09:36:11 +03:00
return picons_files
2018-01-31 00:13:42 +03:00
2022-01-04 20:39:59 +03:00
src_path = dialog.get_filenames()[0]
if IS_WIN:
src_path = src_path.lstrip("/")
dst_path = dst_path.lstrip("/") if dst_path else dst_path
if not str(src_path).endswith(".png") or not os.path.isfile(src_path):
2018-01-31 00:13:42 +03:00
show_dialog(DialogType.ERROR, transient, text="No png file is selected!")
2020-06-06 09:36:11 +03:00
return picons_files
2018-01-31 00:13:42 +03:00
2020-02-28 20:59:53 +03:00
p_pos = Column.SRV_PICON
col_num = Column.SRV_FAV_ID if target is ViewTarget.SERVICES else Column.FAV_ID
itrs = [model.get_iter(p) for p in paths]
if target is ViewTarget.SERVICES:
f_model = model.get_model()
itrs = [f_model.convert_iter_to_child_iter(model.convert_iter_to_child_iter(itr)) for itr in itrs]
model = get_base_model(model)
2018-02-01 21:43:44 +03:00
2020-02-28 20:59:53 +03:00
for itr in itrs:
fav_id = model.get_value(itr, col_num)
picon_id = services.get(fav_id)[Column.SRV_PICON_ID]
if picon_id:
2021-08-30 15:04:15 +03:00
picons_path = dst_path or settings.profile_picons_path
os.makedirs(os.path.dirname(picons_path), exist_ok=True)
picon_file = picons_path + picon_id
2020-08-31 22:20:56 +03:00
try:
shutil.copy(src_path, picon_file)
except shutil.SameFileError:
pass # NOP
2018-02-01 21:43:44 +03:00
else:
2020-08-31 22:20:56 +03:00
picons_files.append(picon_file)
2022-01-04 20:39:59 +03:00
picon = get_picon_pixbuf(picon_file, settings.list_picon_size)
2020-08-31 22:20:56 +03:00
picons[picon_id] = picon
model.set_value(itr, p_pos, picon)
if target is ViewTarget.SERVICES:
set_picon(fav_id, fav_view.get_model(), picon, Column.FAV_ID, p_pos)
else:
set_picon(fav_id, get_base_model(srv_view.get_model()), picon, Column.SRV_FAV_ID, p_pos)
2018-02-01 21:43:44 +03:00
2020-06-06 09:36:11 +03:00
return picons_files
2018-02-01 21:43:44 +03:00
def set_picon(fav_id, model, picon, fav_id_pos, picon_pos):
for row in model:
if row[fav_id_pos] == fav_id:
row[picon_pos] = picon
return True
return True
2018-02-01 21:43:44 +03:00
2018-01-31 00:13:42 +03:00
def remove_picon(target, srv_view, fav_view, picons, settings):
2018-02-01 13:10:06 +03:00
view = srv_view if target is ViewTarget.SERVICES else fav_view
model, paths = view.get_selection().get_selected_rows()
fav_ids = []
picon_ids = []
picon_pos = Column.SRV_PICON # picon position is equal for services and fav
2018-02-01 14:02:59 +03:00
2020-02-28 20:59:53 +03:00
itrs = [model.get_iter(p) for p in paths]
if target is ViewTarget.SERVICES:
f_model = model.get_model()
itrs = [f_model.convert_iter_to_child_iter(model.convert_iter_to_child_iter(itr)) for itr in itrs]
model = get_base_model(model)
for itr in itrs:
2018-02-01 13:10:06 +03:00
model.set_value(itr, picon_pos, None)
if target is ViewTarget.SERVICES:
fav_ids.append(model.get_value(itr, Column.SRV_FAV_ID))
picon_ids.append(model.get_value(itr, Column.SRV_PICON_ID))
2018-02-01 13:10:06 +03:00
else:
srv_type, fav_id = model.get(itr, Column.FAV_TYPE, Column.FAV_ID)
if srv_type == BqServiceType.IPTV.name:
picon_ids.append("{}_{}_{}_{}_{}_{}_{}_{}_{}_{}.png".format(*fav_id.split(":")[0:10]).strip())
else:
fav_ids.append(fav_id)
2018-02-01 13:10:06 +03:00
2020-02-28 20:59:53 +03:00
fav_id_column = Column.FAV_ID if target is ViewTarget.SERVICES else Column.SRV_FAV_ID
def remove(md, path, it):
2020-02-28 20:59:53 +03:00
if md.get_value(it, fav_id_column) in fav_ids:
md.set_value(it, picon_pos, None)
2018-02-01 13:10:06 +03:00
if target is ViewTarget.FAV:
picon_ids.append(md.get_value(it, Column.SRV_PICON_ID))
2018-02-01 13:10:06 +03:00
fav_view.get_model().foreach(remove) if target is ViewTarget.SERVICES else get_base_model(
srv_view.get_model()).foreach(remove)
remove_picons(settings, picon_ids, picons)
2018-02-01 13:10:06 +03:00
2018-01-31 00:13:42 +03:00
def copy_picon_reference(target, view, services, clipboard, transient):
""" Copying picon id to clipboard """
model, paths = view.get_selection().get_selected_rows()
2018-02-01 21:43:44 +03:00
if not is_only_one_item_selected(paths, transient):
2018-01-31 00:13:42 +03:00
return
if target is ViewTarget.SERVICES:
picon_id = model.get_value(model.get_iter(paths), Column.SRV_PICON_ID)
2018-01-31 00:13:42 +03:00
if picon_id:
clipboard.set_text(picon_id.rstrip(".png"), -1)
else:
show_dialog(DialogType.ERROR, transient, "No reference is present!")
elif target is ViewTarget.FAV:
fav_id = model.get_value(model.get_iter(paths), Column.FAV_ID)
2018-01-31 00:13:42 +03:00
srv = services.get(fav_id, None)
if srv and srv.picon_id:
clipboard.set_text(srv.picon_id.rstrip(".png"), -1)
else:
show_dialog(DialogType.ERROR, transient, "No reference is present!")
2022-01-28 00:37:02 +03:00
def remove_all_unused_picons(settings, services):
""" Removes picons from profile picons folder if there are no services for these picons. """
2019-03-03 12:50:40 +03:00
ids = {s.picon_id for s in services}
2022-01-28 00:37:02 +03:00
for p in Path(settings.profile_picons_path).glob("*.png"):
if p.name not in ids and p.is_file():
p.unlink()
2019-03-03 12:50:40 +03:00
def remove_picons(settings, picon_ids, picons):
2021-08-30 15:04:15 +03:00
pions_path = settings.profile_picons_path
2022-01-28 00:37:02 +03:00
backup_path = f"{settings.profile_backup_path}picons{SEP}"
2019-03-03 12:50:40 +03:00
os.makedirs(os.path.dirname(backup_path), exist_ok=True)
for p_id in picon_ids:
picons[p_id] = None
src = pions_path + p_id
if os.path.isfile(src):
shutil.move(src, backup_path + p_id)
2018-02-01 21:43:44 +03:00
def is_only_one_item_selected(paths, transient):
if len(paths) > 1:
show_dialog(DialogType.ERROR, transient, "Please, select only one item!")
return False
if not paths:
show_dialog(DialogType.ERROR, transient, "No selected item!")
return False
return True
2020-04-06 16:50:11 +03:00
def get_picon_pixbuf(path, size=32):
2020-01-12 00:33:33 +03:00
try:
2020-04-06 16:50:11 +03:00
return GdkPixbuf.Pixbuf.new_from_file_at_scale(path, width=size, height=size, preserve_aspect_ratio=True)
2020-01-12 00:33:33 +03:00
except GLib.GError as e:
pass
2018-02-01 21:43:44 +03:00
2021-08-24 16:19:39 +03:00
# ***************** Bouquets ********************* #
2018-04-03 22:47:29 +03:00
2021-04-03 20:51:14 +03:00
def gen_bouquets(view, bq_view, transient, gen_type, s_type, callback):
2021-08-24 16:19:39 +03:00
""" Auto-generate and append list of bouquets. """
model, paths = view.get_selection().get_selected_rows()
single_types = (BqGenType.SAT, BqGenType.PACKAGE, BqGenType.TYPE)
if gen_type in single_types:
if not is_only_one_item_selected(paths, transient):
return
fav_id_index = Column.SRV_FAV_ID
index = Column.SRV_TYPE
if gen_type in (BqGenType.PACKAGE, BqGenType.EACH_PACKAGE):
index = Column.SRV_PACKAGE
elif gen_type in (BqGenType.SAT, BqGenType.EACH_SAT):
index = Column.SRV_POS
2021-08-24 16:19:39 +03:00
# Splitting services [caching] by column value.
s_data = defaultdict(list)
for row in model:
s_data[row[index]].append(BouquetService(None, BqServiceType.DEFAULT, row[fav_id_index], 0))
2021-08-24 16:19:39 +03:00
bq_type = BqType.BOUQUET.value if s_type is SettingsType.NEUTRINO_MP else BqType.TV.value
2019-12-22 20:42:29 +03:00
bq_index = 0 if s_type is SettingsType.ENIGMA_2 else 1
2021-08-24 16:19:39 +03:00
bq_root_iter = bq_view.get_model().get_iter(bq_index)
srv = Service(*model[paths][:Column.SRV_TOOLTIP])
cond = srv.package if gen_type is BqGenType.PACKAGE else srv.pos if gen_type is BqGenType.SAT else srv.service_type
bq_view.expand_row(Gtk.TreePath(bq_index), 0)
2018-04-10 13:04:21 +03:00
2021-08-24 16:19:39 +03:00
bq_names = get_bouquets_names(bq_view.get_model())
2018-04-03 22:47:29 +03:00
2021-08-24 16:19:39 +03:00
if gen_type in single_types:
if cond in bq_names:
show_dialog(DialogType.ERROR, transient, "A bouquet with that name exists!")
else:
callback(Bouquet(cond, bq_type, s_data.get(cond)), bq_root_iter)
else:
# We add a bouquet only if the given name is missing [keys - names]!
for name in sorted(s_data.keys() - bq_names):
callback(Bouquet(name, BqType.TV.value, s_data.get(name)), bq_root_iter)
2018-04-10 13:04:21 +03:00
2018-04-03 22:47:29 +03:00
def get_bouquets_names(model):
""" Returns all current bouquets names """
2021-08-24 16:19:39 +03:00
bouquets_names = set()
2018-04-03 22:47:29 +03:00
for row in model:
itr = row.iter
if model.iter_has_child(itr):
num_of_children = model.iter_n_children(itr)
for num in range(num_of_children):
child_itr = model.iter_nth_child(itr, num)
2021-08-24 16:19:39 +03:00
bouquets_names.add(model[child_itr][0])
2018-04-03 22:47:29 +03:00
return bouquets_names
2018-01-11 17:59:59 +03:00
# ***************** Others *********************#
def update_entry_data(entry, dialog, settings):
2020-12-13 15:19:01 +03:00
""" Updates value in text entry from chooser dialog. """
response = show_dialog(dialog_type=DialogType.CHOOSER, transient=dialog, settings=settings, create_dir=True)
2018-01-11 17:59:59 +03:00
if response not in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
entry.set_text(response)
return response
return False
2018-01-25 21:05:24 +03:00
def get_base_model(model):
2020-06-22 19:45:30 +03:00
""" Returns base tree model if has wrappers [TreeModelSort, TreeModelFilter]. """
2018-01-25 21:05:24 +03:00
if type(model) is Gtk.TreeModelSort:
return model.get_model().get_model()
return model
2020-06-22 19:45:30 +03:00
def get_base_itrs(itrs, model):
""" Returns base iters from wrapper models. """
if type(model) is Gtk.TreeModelSort:
filter_model = model.get_model()
return [filter_model.convert_iter_to_child_iter(model.convert_iter_to_child_iter(itr)) for itr in itrs]
return itrs
def get_base_paths(paths, model):
""" Returns base paths from wrapper models. """
if type(model) is Gtk.TreeModelSort:
filter_model = model.get_model()
return [filter_model.convert_path_to_child_path(model.convert_path_to_child_path(p)) for p in paths]
return paths
2018-11-02 23:13:31 +03:00
def get_model_data(view):
""" Returns model name and base model from the given view """
model = get_base_model(view.get_model())
model_name = model.get_name() if model else ""
2018-11-02 23:13:31 +03:00
return model_name, model
2018-05-01 21:05:18 +03:00
def append_text_to_tview(char, view):
""" Appending text and scrolling to a given line in the text view. """
buf = view.get_buffer()
buf.insert_at_cursor(char)
insert = buf.get_insert()
view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
2019-12-22 20:42:29 +03:00
def get_iptv_url(row, s_type):
""" Returns url from iptv type row """
2019-12-22 20:42:29 +03:00
data = row[Column.FAV_ID].split(":" if s_type is SettingsType.ENIGMA_2 else "::")
if s_type is SettingsType.ENIGMA_2:
2018-08-19 10:55:41 +03:00
data = list(filter(lambda x: "http" in x, data))
if data:
url = data[0]
2020-06-22 19:45:30 +03:00
return unquote(url) if s_type is SettingsType.ENIGMA_2 else url
2018-10-21 11:10:45 +03:00
def on_popup_menu(menu, event):
""" Shows popup menu for the view """
if event.get_event_type() == Gdk.EventType.BUTTON_PRESS and event.button == Gdk.BUTTON_SECONDARY:
menu.popup(None, None, None, None, event.button, event.time)
2017-12-20 16:46:15 +03:00
if __name__ == "__main__":
pass