mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-05-07 13:06:31 +02:00
added support for loading and importing data via dnd
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from contextlib import suppress
|
||||
from pathlib import Path
|
||||
|
||||
from app.commons import run_idle
|
||||
from app.commons import run_idle, log
|
||||
from app.eparser import get_bouquets, get_services
|
||||
from app.eparser.ecommons import BqType, BqServiceType, Bouquet
|
||||
from app.eparser.enigma.bouquets import get_bouquet
|
||||
@@ -123,6 +123,7 @@ class ImportDialog:
|
||||
self._services_model.clear()
|
||||
try:
|
||||
if not self._bouquets:
|
||||
log("Import [init data]: getting bouquets...")
|
||||
self._bouquets = get_bouquets(path, self._profile)
|
||||
for bqs in self._bouquets:
|
||||
for bq in bqs.bouquets:
|
||||
@@ -133,6 +134,7 @@ class ImportDialog:
|
||||
for srv in services:
|
||||
self._services[srv.fav_id] = srv
|
||||
except FileNotFoundError as e:
|
||||
log("Import error [init data]: {}".format(e))
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
|
||||
def on_import(self, item):
|
||||
@@ -143,9 +145,17 @@ class ImportDialog:
|
||||
if not self._bouquets or show_dialog(DialogType.QUESTION, self._dialog_window) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
self.import_data()
|
||||
|
||||
@run_idle
|
||||
def import_data(self):
|
||||
""" Importing data into models. """
|
||||
if not self._bouquets:
|
||||
return
|
||||
|
||||
log("Importing data...")
|
||||
services = set()
|
||||
to_delete = set()
|
||||
|
||||
for row in self._main_model:
|
||||
bq = (row[0], row[1])
|
||||
if row[-1]:
|
||||
@@ -155,19 +165,16 @@ class ImportDialog:
|
||||
services.add(srv)
|
||||
else:
|
||||
to_delete.add(bq)
|
||||
|
||||
bqs_to_delete = []
|
||||
for bqs in self._bouquets:
|
||||
for bq in bqs.bouquets:
|
||||
if (bq.name, bq.type) in to_delete:
|
||||
bqs_to_delete.append(bq)
|
||||
|
||||
for bqs in self._bouquets:
|
||||
bq = bqs.bouquets
|
||||
for b in bqs_to_delete:
|
||||
with suppress(ValueError):
|
||||
bq.remove(b)
|
||||
|
||||
self._append(self._bouquets, list(filter(lambda s: s.fav_id not in self._service_ids, services)))
|
||||
self._dialog_window.destroy()
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from contextlib import suppress
|
||||
from datetime import datetime
|
||||
from functools import lru_cache
|
||||
from itertools import chain
|
||||
from urllib.parse import urlparse, unquote
|
||||
|
||||
from gi.repository import GLib, Gio
|
||||
|
||||
@@ -476,7 +477,7 @@ class Application(Gtk.Application):
|
||||
self.set_profile(profile)
|
||||
|
||||
def init_drag_and_drop(self):
|
||||
""" Enable drag-and-drop """
|
||||
""" Enable drag-and-drop. """
|
||||
target = []
|
||||
bq_target = []
|
||||
|
||||
@@ -496,6 +497,7 @@ class Application(Gtk.Application):
|
||||
|
||||
self._services_view.drag_source_set_target_list(None)
|
||||
self._services_view.drag_source_add_text_targets()
|
||||
self._services_view.drag_dest_add_text_targets()
|
||||
self._services_view.drag_dest_add_uri_targets()
|
||||
|
||||
self._bouquets_view.drag_dest_set_target_list(None)
|
||||
@@ -504,6 +506,9 @@ class Application(Gtk.Application):
|
||||
self._bouquets_view.drag_source_add_text_targets()
|
||||
self._bouquets_view.drag_dest_add_uri_targets()
|
||||
|
||||
self._app_info_box.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
|
||||
self._app_info_box.drag_dest_add_text_targets()
|
||||
|
||||
def init_colors(self, update=False):
|
||||
""" Initialisation of background colors for the services.
|
||||
|
||||
@@ -1035,11 +1040,12 @@ class Application(Gtk.Application):
|
||||
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)
|
||||
if txt.startswith("file://"):
|
||||
self.on_import_data(urlparse(unquote(txt)).path.strip())
|
||||
else:
|
||||
self.receive_selection(view=view, drop_info=view.get_dest_row_at_pos(x, y), data=txt)
|
||||
|
||||
if uris:
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
src, sep, dest = uris[0].partition("::::")
|
||||
picon_path = urlparse(unquote(src)).path
|
||||
dest_path = urlparse(unquote(dest)).path + "/"
|
||||
@@ -1060,6 +1066,10 @@ class Application(Gtk.Application):
|
||||
if not data:
|
||||
return
|
||||
|
||||
if data.startswith("file://"):
|
||||
self.on_import_bouquet(None, file_path=urlparse(unquote(data)).path.strip())
|
||||
return
|
||||
|
||||
itr_str, sep, source = data.partition("::::")
|
||||
if source != self.BQ_MODEL_NAME:
|
||||
return
|
||||
@@ -1269,17 +1279,24 @@ class Application(Gtk.Application):
|
||||
|
||||
def open_compressed_data(self, data_path):
|
||||
""" Opening archived data. """
|
||||
arch_path = self.get_archive_path(data_path)
|
||||
if arch_path:
|
||||
gen = self.update_data("{}{}".format(arch_path.name, os.sep), callback=arch_path.cleanup)
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
|
||||
def get_archive_path(self, data_path):
|
||||
""" Returns the temp dir path for the extracted data, or None if the archive format is not supported. """
|
||||
import zipfile
|
||||
import tarfile
|
||||
import tempfile
|
||||
|
||||
tmp_path = tempfile.TemporaryDirectory()
|
||||
tmp_path_name = str(tmp_path.name)
|
||||
tmp_path_name = tmp_path.name
|
||||
|
||||
if zipfile.is_zipfile(data_path):
|
||||
with zipfile.ZipFile(data_path) as zip_file:
|
||||
for zip_info in zip_file.infolist():
|
||||
if not zip_info.is_dir():
|
||||
if not zip_info.filename.endswith(os.sep):
|
||||
zip_info.filename = os.path.basename(zip_info.filename)
|
||||
zip_file.extract(zip_info, path=tmp_path_name)
|
||||
elif tarfile.is_tarfile(data_path):
|
||||
@@ -1289,12 +1306,12 @@ class Application(Gtk.Application):
|
||||
mb.name = os.path.basename(mb.name)
|
||||
tar.extract(mb, path=tmp_path_name)
|
||||
else:
|
||||
self.show_error_dialog("Unsupported format!")
|
||||
tmp_path.cleanup()
|
||||
log("Error getting the path for the archive. Unsupported file format: {}".format(data_path))
|
||||
self.show_error_dialog("Unsupported format!")
|
||||
return
|
||||
|
||||
gen = self.update_data("{}{}".format(tmp_path_name, os.sep), callback=tmp_path.cleanup)
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
return tmp_path
|
||||
|
||||
def update_data(self, data_path, callback=None):
|
||||
self._profile_combo_box.set_sensitive(False)
|
||||
@@ -2034,6 +2051,16 @@ class Application(Gtk.Application):
|
||||
else:
|
||||
show_dialog(DialogType.INFO, self._main_window, "Done!")
|
||||
|
||||
def on_import_data(self, path):
|
||||
msg = "Combine with the current data?"
|
||||
if len(self._services_model) > 0 and show_dialog(DialogType.QUESTION, self._main_window,
|
||||
msg) == Gtk.ResponseType.OK:
|
||||
self.import_data(path, force=True)
|
||||
else:
|
||||
if os.path.isdir(path) and not path.endswith(os.sep):
|
||||
path += os.sep
|
||||
self.open_data(path)
|
||||
|
||||
def on_import_bouquet(self, action, value=None, file_path=None):
|
||||
model, paths = self._bouquets_view.get_selection().get_selected_rows()
|
||||
if not paths:
|
||||
@@ -2048,17 +2075,34 @@ class Application(Gtk.Application):
|
||||
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
|
||||
return
|
||||
|
||||
self.import_data(response)
|
||||
|
||||
def import_data(self, path, force=None, callback=None):
|
||||
if os.path.isdir(path) and not path.endswith(os.sep):
|
||||
path += os.sep
|
||||
elif os.path.isfile(path):
|
||||
arch_path = self.get_archive_path(path)
|
||||
if not arch_path:
|
||||
return
|
||||
|
||||
path = arch_path.name + os.sep
|
||||
callback = arch_path.cleanup
|
||||
|
||||
def append(b, s):
|
||||
gen = self.append_imported_data(b, s)
|
||||
gen = self.append_imported_data(b, s, callback)
|
||||
GLib.idle_add(lambda: next(gen, False))
|
||||
|
||||
ImportDialog(self._main_window, response, self._settings, self._services.keys(), append).show()
|
||||
dialog = ImportDialog(self._main_window, path, self._settings, self._services.keys(), append)
|
||||
dialog.import_data() if force else dialog.show()
|
||||
|
||||
def append_imported_data(self, bouquets, services):
|
||||
def append_imported_data(self, bouquets, services, callback=None):
|
||||
try:
|
||||
self._wait_dialog.show()
|
||||
yield from self.append_data(bouquets, services)
|
||||
finally:
|
||||
log("Importing data done!")
|
||||
if callback:
|
||||
callback()
|
||||
self._wait_dialog.hide()
|
||||
|
||||
# ***************** Backup ********************#
|
||||
|
||||
@@ -2778,6 +2778,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<signal name="drag-data-received" handler="on_view_drag_data_received" object="services_tree_view" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_tree_view_key_press" object="services_tree_view" swapped="no"/>
|
||||
<signal name="key-release-event" handler="on_tree_view_key_release" object="services_tree_view" swapped="no"/>
|
||||
<child>
|
||||
|
||||
Reference in New Issue
Block a user