added picons multiple assignment

This commit is contained in:
DYefremov
2020-02-28 20:59:53 +03:00
parent aa4b31edfc
commit b0ec8e5483
5 changed files with 440 additions and 144 deletions

View File

@@ -99,6 +99,8 @@ class Application(Gtk.Application):
"on_to_fav_end_copy": self.on_to_fav_end_copy,
"on_view_drag_begin": self.on_view_drag_begin,
"on_view_drag_data_get": self.on_view_drag_data_get,
"on_services_view_drag_drop": self.on_services_view_drag_drop,
"on_services_view_drag_data_received": self.on_services_view_drag_data_received,
"on_view_drag_data_received": self.on_view_drag_data_received,
"on_bq_view_drag_data_received": self.on_bq_view_drag_data_received,
"on_view_press": self.on_view_press,
@@ -243,6 +245,7 @@ class Application(Gtk.Application):
self._filter_types_model = builder.get_object("filter_types_list_store")
self._filter_sat_positions_model = builder.get_object("filter_sat_positions_list_store")
self._filter_only_free_button = builder.get_object("filter_only_free_button")
self._filter_bar.bind_property("search-mode-enabled", self._filter_bar, "visible")
# Player
self._player_box = builder.get_object("player_box")
self._player_scale = builder.get_object("player_scale")
@@ -269,6 +272,7 @@ class Application(Gtk.Application):
self._player_frame = builder.get_object("player_frame")
# Search
self._search_bar = builder.get_object("search_bar")
self._search_bar.bind_property("search-mode-enabled", self._search_bar, "visible")
self._search_entry = builder.get_object("search_entry")
self._search_provider = SearchProvider((self._services_view, self._fav_view, self._bouquets_view),
builder.get_object("search_down_button"),
@@ -385,19 +389,25 @@ class Application(Gtk.Application):
""" Enable drag-and-drop """
target = []
bq_target = []
self._services_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, target, Gdk.DragAction.COPY)
self._services_view.enable_model_drag_dest([], Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
self._fav_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, target,
Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
self._fav_view.enable_model_drag_dest(target, Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
self._bouquets_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, bq_target,
Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
self._bouquets_view.enable_model_drag_dest(bq_target, Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
self._fav_view.drag_dest_set_target_list(None)
self._fav_view.drag_source_set_target_list(None)
self._fav_view.drag_dest_add_text_targets()
self._fav_view.drag_source_add_text_targets()
self._fav_view.drag_dest_add_uri_targets()
self._services_view.drag_source_set_target_list(None)
self._services_view.drag_source_add_text_targets()
self._services_view.drag_dest_add_uri_targets()
self._bouquets_view.drag_dest_set_target_list(None)
self._bouquets_view.drag_source_set_target_list(None)
self._bouquets_view.drag_dest_add_text_targets()
@@ -749,9 +759,24 @@ class Application(Gtk.Application):
if selection:
data.set_text(selection, -1)
def on_services_view_drag_drop(self, view, drag_context, x, y, time):
view.stop_emission_by_name("drag_drop")
# https://stackoverflow.com/q/7661016 [Some data was dropped, get the data!]
view.drag_get_data(drag_context, drag_context.list_targets()[-1], time)
def on_services_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
# Needs for the GtkTreeView when using models [filter, sort]
# that don't support the GtkTreeDragDest interface.
view.stop_emission_by_name("drag_data_received")
self.on_view_drag_data_received(view, drag_context, x, y, data, info, time)
def on_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
self.receive_selection(view=view, drop_info=view.get_dest_row_at_pos(x, y), data=data.get_text())
return False
txt = data.get_text()
uris = data.get_uris()
if txt:
self.receive_selection(view=view, drop_info=view.get_dest_row_at_pos(x, y), data=txt)
elif len(uris) == 1:
self.on_assign_picon(view, uris[0])
def on_bq_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
model_name, model = get_model_data(view)
@@ -1958,9 +1983,10 @@ class Application(Gtk.Application):
if value:
self.update_filter_sat_positions()
self._filter_entry.grab_focus()
else:
self._filter_entry.set_text("")
self._filter_bar.set_search_mode(value)
self._filter_bar.set_visible(value)
def init_sat_positions(self):
self._sat_positions.clear()
@@ -2202,27 +2228,28 @@ class Application(Gtk.Application):
data = r[Column.SRV_PICON_ID].split("_")
ids["{}:{}:{}".format(data[3], data[5], data[6])] = r[Column.SRV_PICON_ID]
PiconsDialog(self._main_window, self._settings, ids, self._sat_positions).show()
self.update_picons()
PiconsDialog(self._main_window, self._settings, ids, self._sat_positions, self.update_picons).show()
@run_task
def update_picons(self):
update_picons_data(self._settings.picons_local_path, self._picons)
append_picons(self._picons, self._services_model)
def on_assign_picon(self, view):
def on_assign_picon(self, view, path=None):
assign_picon(self.get_target_view(view),
self._services_view,
self._fav_view,
self._main_window,
self._picons,
self._settings,
self._services)
self._services,
path)
def on_remove_picon(self, view):
remove_picon(self.get_target_view(view),
self._services_view,
self._fav_view, self._picons,
self._fav_view,
self._picons,
self._settings)
def on_reference_picon(self, view):

View File

@@ -362,39 +362,44 @@ def append_picons(picons, model):
GLib.idle_add(lambda: next(app, False), priority=GLib.PRIORITY_LOW)
def assign_picon(target, srv_view, fav_view, transient, picons, settings, services):
def assign_picon(target, srv_view, fav_view, transient, picons, settings, services, p_path=None):
view = srv_view if target is ViewTarget.SERVICES else fav_view
model, paths = view.get_selection().get_selected_rows()
if not is_only_one_item_selected(paths, transient):
return
response = get_chooser_dialog(transient, settings, "*.png", "png files")
if response == Gtk.ResponseType.CANCEL:
return
if not p_path:
p_path = get_chooser_dialog(transient, settings, "*.png", "png files")
if p_path == Gtk.ResponseType.CANCEL:
return
if not str(response).endswith(".png"):
if not str(p_path).endswith(".png") or not os.path.isfile(p_path):
show_dialog(DialogType.ERROR, transient, text="No png file is selected!")
return
picon_pos = Column.SRV_PICON
model = get_base_model(model)
itr = model.get_iter(paths)
fav_id = model.get_value(itr, Column.SRV_FAV_ID if target is ViewTarget.SERVICES else Column.FAV_ID)
picon_id = services.get(fav_id)[Column.SRV_PICON_ID]
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 picon_id:
if os.path.isfile(response):
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:
fav_id = model.get_value(itr, col_num)
picon_id = services.get(fav_id)[Column.SRV_PICON_ID]
if picon_id:
picons_path = settings.picons_local_path
os.makedirs(os.path.dirname(picons_path), exist_ok=True)
picon_file = picons_path + picon_id
shutil.copy(response, picon_file)
shutil.copy(p_path, picon_file)
picon = get_picon_pixbuf(picon_file)
picons[picon_id] = picon
model.set_value(itr, picon_pos, 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, picon_pos)
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, picon_pos)
set_picon(fav_id, get_base_model(srv_view.get_model()), picon, Column.SRV_FAV_ID, p_pos)
def set_picon(fav_id, model, picon, fav_id_pos, picon_pos):
@@ -407,14 +412,19 @@ def set_picon(fav_id, model, picon, fav_id_pos, picon_pos):
def remove_picon(target, srv_view, fav_view, picons, settings):
view = srv_view if target is ViewTarget.SERVICES else fav_view
model, paths = view.get_selection().get_selected_rows()
model = get_base_model(model)
fav_ids = []
picon_ids = []
picon_pos = Column.SRV_PICON # picon position is equal for services and fav
for path in paths:
itr = model.get_iter(path)
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:
model.set_value(itr, picon_pos, None)
if target is ViewTarget.SERVICES:
fav_ids.append(model.get_value(itr, Column.SRV_FAV_ID))
@@ -426,8 +436,10 @@ def remove_picon(target, srv_view, fav_view, picons, settings):
else:
fav_ids.append(fav_id)
fav_id_column = Column.FAV_ID if target is ViewTarget.SERVICES else Column.SRV_FAV_ID
def remove(md, path, it):
if md.get_value(it, Column.FAV_ID if target is ViewTarget.SERVICES else Column.SRV_FAV_ID) in fav_ids:
if md.get_value(it, fav_id_column) in fav_ids:
md.set_value(it, picon_pos, None)
if target is ViewTarget.FAV:
picon_ids.append(md.get_value(it, Column.SRV_PICON_ID))

View File

@@ -1242,7 +1242,7 @@ Author: Dmitriy Yefremov
<object class="GtkImage" id="sat_editor_header_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-all</property>
<property name="stock">gtk-edit</property>
</object>
</child>
</object>
@@ -1581,7 +1581,6 @@ Author: Dmitriy Yefremov
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar" id="search_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="search_bar_box">
@@ -1748,18 +1747,6 @@ Author: Dmitriy Yefremov
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="top_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkPaned" id="main_data_paned">
<property name="height_request">250</property>
@@ -1767,6 +1754,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="margin_left">1</property>
<property name="margin_right">1</property>
<property name="margin_top">2</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkBox" id="services_main_box">
@@ -1777,6 +1765,8 @@ Author: Dmitriy Yefremov
<object class="GtkLabel" id="services_header_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="label" translatable="yes">Services</property>
<attributes>
<attribute name="weight" value="bold"/>
@@ -1808,6 +1798,8 @@ Author: Dmitriy Yefremov
<signal name="button-press-event" handler="on_view_press" swapped="no"/>
<signal name="drag-begin" handler="on_view_drag_begin" swapped="no"/>
<signal name="drag-data-get" handler="on_view_drag_data_get" swapped="no"/>
<signal name="drag-data-received" handler="on_services_view_drag_data_received" swapped="no"/>
<signal name="drag-drop" handler="on_services_view_drag_drop" swapped="no"/>
<signal name="focus-in-event" handler="on_view_focus" swapped="no"/>
<signal name="key-press-event" handler="on_tree_view_key_press" swapped="no"/>
<signal name="key-release-event" handler="on_tree_view_key_release" swapped="no"/>
@@ -2326,6 +2318,8 @@ Author: Dmitriy Yefremov
<object class="GtkLabel" id="fav_header_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="label" translatable="yes">Bouquet details</property>
<attributes>
<attribute name="weight" value="bold"/>
@@ -2599,6 +2593,8 @@ Author: Dmitriy Yefremov
<object class="GtkLabel" id="bouquets_header_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="label" translatable="yes">Bouquets</property>
<attributes>
<attribute name="weight" value="bold"/>

View File

@@ -3,7 +3,7 @@
The MIT License (MIT)
Copyright (c) 2018-2019 Dmitriy Yefremov
Copyright (c) 2018-2020 Dmitriy Yefremov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -26,13 +26,27 @@ THE SOFTWARE.
Author: Dmitriy Yefremov
-->
<interface>
<interface domain="demon-editor">
<requires lib="gtk+" version="3.16"/>
<!-- interface-css-provider-path style.css -->
<!-- interface-license-type mit -->
<!-- interface-name DemonEditor -->
<!-- interface-copyright 2018-2019 Dmitriy Yefremov -->
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkListStore" id="picons_list_store">
<columns>
<!-- column-name picon -->
<column type="GdkPixbuf"/>
<!-- column-name title -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeModelFilter" id="picons_filter_model">
<property name="child_model">picons_list_store</property>
</object>
<object class="GtkTreeModelSort" id="picons_sort_model">
<property name="model">picons_filter_model</property>
</object>
<object class="GtkListStore" id="providers_list_store">
<columns>
<!-- column-name logo -->
@@ -68,7 +82,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_select_all" object="providers_tree_view" swapped="no"/>
<signal name="activate" handler="on_select_all" object="providers_view" swapped="no"/>
</object>
</child>
<child>
@@ -78,7 +92,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="image">remove_selection_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_unselect_all" object="providers_tree_view" swapped="no"/>
<signal name="activate" handler="on_unselect_all" object="providers_view" swapped="no"/>
</object>
</child>
</object>
@@ -92,13 +106,11 @@ Author: Dmitriy Yefremov
<column type="gchararray"/>
</columns>
</object>
<object class="GtkDialog" id="picons_dialog">
<property name="use-header-bar">1</property>
<object class="GtkWindow" id="picons_dialog">
<property name="can_focus">False</property>
<property name="modal">True</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">emblem-photos</property>
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<signal name="delete-event" handler="on_close" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
@@ -131,7 +143,6 @@ Author: Dmitriy Yefremov
<property name="spacing">2</property>
<child>
<object class="GtkButton" id="load_providers_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -153,20 +164,8 @@ Author: Dmitriy Yefremov
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="receive_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -182,6 +181,16 @@ Author: Dmitriy Yefremov
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="download_box_separator">
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
@@ -204,17 +213,6 @@ Author: Dmitriy Yefremov
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
@@ -226,7 +224,7 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Download picons from the receiver</property>
<property name="tooltip_text" translatable="yes">Download from the receiver</property>
<signal name="clicked" handler="on_download" swapped="no"/>
<child>
<object class="GtkImage" id="download_button_image">
@@ -247,7 +245,7 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Remove picons from the receiver</property>
<property name="tooltip_text" translatable="yes">Remove all picons from the receiver</property>
<signal name="clicked" handler="on_remove" swapped="no"/>
<child>
<object class="GtkImage" id="remove_button_image">
@@ -289,31 +287,192 @@ Author: Dmitriy Yefremov
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="picons_dialog_vbox">
<property name="width_request">640</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog_action_area">
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<property name="layout_style">spread</property>
<child>
<object class="GtkToggleButton" id="filter_button">
<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>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<child>
<object class="GtkImage" id="filter_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<property name="stock">gtk-select-all</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="pack_type">end</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkNotebook" id="notebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="switch-page" handler="on_notebook_switch_page" swapped="no"/>
<child>
<object class="GtkBox" id="explorer_main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar" id="search_bar">
<property name="can_focus">False</property>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<child>
<object class="GtkSearchEntry" id="picons_search_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSearchBar" id="filter_bar">
<property name="can_focus">False</property>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<child>
<object class="GtkSearchEntry" id="picons_filter_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_stock">gtk-spell-check</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
<signal name="search-changed" handler="on_picons_filter_changed" swapped="no"/>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="explorer_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label_xalign">0.5</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkBox" id="explorer_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkFileChooserButton" id="explorer_path_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="action">select-folder</property>
<property name="title" translatable="yes"/>
<signal name="current-folder-changed" handler="on_picons_folder_changed" swapped="no"/>
<signal name="file-set" handler="on_picons_folder_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="picons_view_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkIconView" id="picons_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin">5</property>
<property name="model">picons_sort_model</property>
<property name="row_spacing">5</property>
<property name="column_spacing">5</property>
<property name="tooltip_column">1</property>
<property name="item_padding">5</property>
<signal name="drag-data-get" handler="on_view_drag_data_get" swapped="no"/>
<signal name="realize" handler="on_picons_view_realize" swapped="no"/>
<child>
<object class="GtkCellRendererPixbuf" id="picon_renderer">
<property name="width">128</property>
</object>
<attributes>
<attribute name="pixbuf">0</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText" id="picon_title_renderer">
<property name="alignment">center</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="picons_path_labe">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Current picons path:</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="explorer_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Explorer</property>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox" id="downloader_box">
<property name="visible">True</property>
@@ -328,6 +487,7 @@ Author: Dmitriy Yefremov
<object class="GtkBox" id="providers_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkFrame" id="satellites_frame">
@@ -345,7 +505,7 @@ Author: Dmitriy Yefremov
<property name="margin_bottom">5</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="satellites_tree_view">
<object class="GtkTreeView" id="satellites_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">satellites_list_store</property>
@@ -355,7 +515,7 @@ Author: Dmitriy Yefremov
<signal name="realize" handler="on_satellites_view_realize" swapped="no"/>
<signal name="row-activated" handler="on_satellite_selection" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection" id="satellites_tree_selection"/>
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="sat_name_column">
@@ -417,7 +577,6 @@ Author: Dmitriy Yefremov
<object class="GtkLabel" id="loading_data_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">2</property>
<property name="label" translatable="yes">Loading data...</property>
</object>
<packing>
@@ -430,7 +589,6 @@ Author: Dmitriy Yefremov
<object class="GtkSpinner" id="loading_data_spinner">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">2</property>
<property name="active">True</property>
</object>
<packing>
@@ -460,14 +618,13 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkEntry" id="url_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_bottom">2</property>
<property name="primary_icon_name">network-workgroup-symbolic</property>
<property name="primary_icon_activatable">False</property>
@@ -486,20 +643,18 @@ Author: Dmitriy Yefremov
<property name="height_request">150</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_bottom">2</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkTreeView" id="providers_tree_view">
<object class="GtkTreeView" id="providers_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="model">providers_list_store</property>
<property name="search_column">1</property>
<signal name="button-press-event" handler="on_popup_menu" object="providers_popup_menu" swapped="no"/>
<signal name="select-all" handler="on_select_all" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview_selection"/>
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="provider_column">
@@ -611,8 +766,6 @@ Author: Dmitriy Yefremov
<object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="column_spacing">2</property>
@@ -686,9 +839,6 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="picons_dir_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_bottom">5</property>
<property name="secondary_icon_name">folder-open</property>
<property name="primary_icon_activatable">False</property>
<signal name="icon-press" handler="on_picons_dir_open" swapped="no"/>
@@ -745,14 +895,12 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_right">5</property>
<child>
<object class="GtkRadioButton" id="enigma2_radio_button">
<property name="label" translatable="yes">Enigma2 (default)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">neutrino_mp_radio_button</property>
</object>
@@ -768,7 +916,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">enigma2_radio_button</property>
</object>
@@ -822,7 +969,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_100_60_radio_button</property>
</object>
@@ -838,7 +984,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_100_60_radio_button</property>
</object>
@@ -854,7 +999,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_no_radio_button</property>
</object>
@@ -894,6 +1038,9 @@ Author: Dmitriy Yefremov
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel" id="downloader_label">
@@ -902,6 +1049,7 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Downloader</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -980,6 +1128,33 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="convert_to_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Enigma2 -&gt; Neutrino-MP</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkImage" id="convert_to_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-convert</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
@@ -994,7 +1169,7 @@ Author: Dmitriy Yefremov
</child>
</object>
<packing>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
<child type="tab">
@@ -1005,16 +1180,10 @@ Author: Dmitriy Yefremov
<property name="label" translatable="yes">Converter</property>
</object>
<packing>
<property name="position">1</property>
<property name="position">2</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
@@ -1067,7 +1236,7 @@ Author: Dmitriy Yefremov
<property name="show_close_button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox" id="infobar-action_area1">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
@@ -1081,7 +1250,7 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox" id="infobar-content_area1">
<object class="GtkBox">
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="info_bar_message_label">
@@ -1106,6 +1275,9 @@ Author: Dmitriy Yefremov
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -4,22 +4,24 @@ import shutil
import subprocess
import tempfile
from gi.repository import GLib, GdkPixbuf
from gi.repository import GLib, GdkPixbuf, Gio
from app.commons import run_idle, run_task
from app.commons import run_idle, run_task, run_with_delay
from app.connections import upload_data, DownloadType, download_data, remove_picons
from app.settings import SettingsType
from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to
from app.tools.satellites import SatellitesParser, SatelliteSource
from .dialogs import show_dialog, DialogType, get_message
from .main_helper import update_entry_data, append_text_to_tview, scroll_to, on_popup_menu
from .main_helper import update_entry_data, append_text_to_tview, scroll_to, on_popup_menu, update_picons_data, \
get_base_model
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, TV_ICON
class PiconsDialog:
def __init__(self, transient, settings, picon_ids, sat_positions):
def __init__(self, transient, settings, picon_ids, sat_positions, callback):
self._picon_ids = picon_ids
self._sat_positions = sat_positions
self._callback = callback
self._TMP_DIR = tempfile.gettempdir() + "/"
self._BASE_URL = "www.lyngsat.com/packages/"
self._PATTERN = re.compile(r"^https://www\.lyngsat\.com/[\w-]+\.html$")
@@ -38,27 +40,38 @@ class PiconsDialog:
"on_picons_dir_open": self.on_picons_dir_open,
"on_selected_toggled": self.on_selected_toggled,
"on_url_changed": self.on_url_changed,
"on_picons_filter_changed": self.on_picons_filter_changed,
"on_position_edited": self.on_position_edited,
"on_notebook_switch_page": self.on_notebook_switch_page,
"on_convert": self.on_convert,
"on_picons_folder_changed": self.on_picons_folder_changed,
"on_view_drag_data_get": self.on_view_drag_data_get,
"on_picons_view_realize": self.on_picons_view_realize,
"on_satellites_view_realize": self.on_satellites_view_realize,
"on_satellite_selection": self.on_satellite_selection,
"on_select_all": self.on_select_all,
"on_unselect_all": self.on_unselect_all,
"on_filter_toggled": self.on_filter_toggled,
"on_popup_menu": on_popup_menu}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_from_file(UI_RESOURCES_PATH + "picons_dialog.glade")
builder.connect_signals(handlers)
self._dialog = builder.get_object("picons_dialog")
self._dialog.set_transient_for(transient)
self._providers_tree_view = builder.get_object("providers_tree_view")
self._satellites_tree_view = builder.get_object("satellites_tree_view")
self._picons_view = builder.get_object("picons_view")
self._providers_view = builder.get_object("providers_view")
self._satellites_view = builder.get_object("satellites_view")
self._picons_filter_model = builder.get_object("picons_filter_model")
self._picons_filter_model.set_visible_func(self.picons_filter_function)
self._explorer_path_button = builder.get_object("explorer_path_button")
self._expander = builder.get_object("expander")
self._text_view = builder.get_object("text_view")
self._info_bar = builder.get_object("info_bar")
self._filter_bar = builder.get_object("filter_bar")
self._filter_button = builder.get_object("filter_button")
self._picons_filter_entry = builder.get_object("picons_filter_entry")
self._ip_entry = builder.get_object("ip_entry")
self._picons_entry = builder.get_object("picons_entry")
self._url_entry = builder.get_object("url_entry")
@@ -84,7 +97,12 @@ class PiconsDialog:
self._satellite_label.bind_property("visible", builder.get_object("loading_data_spinner"), "visible", 4)
self._cancel_button.bind_property("visible", self._header_download_box, "visible", 4)
self._convert_button.bind_property("visible", self._header_download_box, "visible", 4)
# style
self._load_providers_button.bind_property("visible", self._receive_button, "visible")
self._load_providers_button.bind_property("visible", builder.get_object("download_box_separator"), "visible")
self._filter_bar.bind_property("search-mode-enabled", self._filter_bar, "visible")
# Init drag-and-drop
self.init_drag_and_drop()
# Style
self._style_provider = Gtk.CssProvider()
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
self._url_entry.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
@@ -107,7 +125,54 @@ class PiconsDialog:
self._satellite_label.show()
def show(self):
self._dialog.run()
self._dialog.show()
def on_picons_view_realize(self, view):
self._explorer_path_button.set_current_folder(self._picons_path)
def on_picons_folder_changed(self, button):
path = button.get_filename()
if not path or not os.path.exists(path):
return
GLib.idle_add(self._explorer_path_button.set_sensitive, False)
gen = self.update_picons(path)
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def update_picons(self, path):
p_model = self._picons_view.get_model()
self._picons_view.set_model(None)
model = get_base_model(p_model)
model.clear()
self._picons_view.set_model(p_model)
for file in os.listdir(path):
if self._terminate:
return
try:
p = GdkPixbuf.Pixbuf.new_from_file(filename="{}/{}".format(path, file))
except GLib.GError as e:
pass
else:
yield model.append((p, file))
self._explorer_path_button.set_sensitive(True)
yield True
# ***************** Drag-and-drop ********************* #
def init_drag_and_drop(self):
self._picons_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [], Gdk.DragAction.COPY)
self._picons_view.drag_source_add_uri_targets()
def on_view_drag_data_get(self, view, drag_context, data, info, time):
model = view.get_model()
path = view.get_selected_items()[0]
p_path = "{}/{}".format(self._explorer_path_button.get_filename(), model.get_value(model.get_iter(path), 1))
data.set_uris([p_path])
# ******************** ####### ************************* #
def on_satellites_view_realize(self, view):
self.get_satellites(view)
@@ -153,7 +218,7 @@ class PiconsDialog:
self.show_info_message(str(e), Gtk.MessageType.ERROR)
else:
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
model = self._providers_tree_view.get_model()
model = self._providers_view.get_model()
model.clear()
self.append_providers(url, model)
@@ -198,7 +263,7 @@ class PiconsDialog:
if not self._POS_PATTERN.match(prv[2]):
self.show_info_message(
get_message("Specify the correct position value for the provider!"), Gtk.MessageType.ERROR)
scroll_to(prv.path, self._providers_tree_view)
scroll_to(prv.path, self._providers_view)
return
try:
@@ -266,8 +331,10 @@ class PiconsDialog:
if self.on_cancel():
return True
self._terminate = True
self.save_window_size(window)
self.clean_data()
self._callback()
GLib.idle_add(self._dialog.destroy)
def save_window_size(self, window):
@@ -334,7 +401,7 @@ class PiconsDialog:
@run_idle
def on_selected_toggled(self, toggle, path):
model = self._providers_tree_view.get_model()
model = self._providers_view.get_model()
model.set_value(model.get_iter(path), 7, not toggle.get_active())
self.update_receive_button_state()
@@ -348,18 +415,40 @@ class PiconsDialog:
view.get_model().foreach(lambda mod, path, itr: mod.set_value(itr, 7, select))
self.update_receive_button_state()
def on_filter_toggled(self, button):
active = button.get_active()
self._filter_bar.set_search_mode(active)
if not active:
self._picons_filter_entry.set_text("")
def on_url_changed(self, entry):
suit = self._PATTERN.search(entry.get_text())
entry.set_name("GtkEntry" if suit else "digit-entry")
self._load_providers_button.set_sensitive(suit if suit else False)
@run_with_delay(1)
def on_picons_filter_changed(self, entry):
GLib.idle_add(self._picons_filter_model.refilter, priority=GLib.PRIORITY_LOW)
def picons_filter_function(self, model, itr, data):
if self._picons_filter_model is None or self._picons_filter_model == "None":
return True
t = model.get_value(itr, 1)
return not t or self._picons_filter_entry.get_text().upper() in t.upper()
def on_position_edited(self, render, path, value):
model = self._providers_tree_view.get_model()
model = self._providers_view.get_model()
model.set_value(model.get_iter(path), 2, value)
@run_idle
def on_notebook_switch_page(self, nb, box, tab_num):
self._convert_button.set_visible(tab_num)
self._convert_button.set_visible(tab_num > 1)
self._load_providers_button.set_visible(tab_num == 1)
is_explorer = tab_num == 0
self._filter_button.set_visible(is_explorer)
if is_explorer:
self.on_picons_folder_changed(self._explorer_path_button)
@run_idle
def on_convert(self, item):
@@ -388,7 +477,7 @@ class PiconsDialog:
def get_selected_providers(self):
""" returns selected providers """
return [r for r in self._providers_tree_view.get_model() if r[7]]
return [r for r in self._providers_view.get_model() if r[7]]
@run_idle
def show_dialog(self, message, dialog_type):