diff --git a/bulky.pot b/bulky.pot index 94480cd..47d66de 100644 --- a/bulky.pot +++ b/bulky.pot @@ -8,13 +8,13 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-07-25 15:24+0200\n" +"POT-Creation-Date: 2026-08-07 22:02+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: usr/lib/bulky/bulky.py:45 @@ -25,69 +25,77 @@ msgstr "" msgid "Add" msgstr "" -#: usr/lib/bulky/bulky.py:222 usr/share/bulky/bulky.ui.h:33 +#: usr/lib/bulky/bulky.py:223 usr/share/bulky/bulky.ui.h:33 msgid "Rename..." msgstr "" -#: usr/lib/bulky/bulky.py:260 usr/lib/bulky/bulky.py:437 +#: usr/lib/bulky/bulky.py:262 usr/lib/bulky/bulky.py:454 msgid "About" msgstr "" -#: usr/lib/bulky/bulky.py:265 +#: usr/lib/bulky/bulky.py:267 msgid "Quit" msgstr "" -#: usr/lib/bulky/bulky.py:282 +#: usr/lib/bulky/bulky.py:284 msgid "Name" msgstr "" -#: usr/lib/bulky/bulky.py:293 +#: usr/lib/bulky/bulky.py:295 msgid "New name" msgstr "" -#: usr/lib/bulky/bulky.py:402 +#: usr/lib/bulky/bulky.py:404 msgid "Use %n, %0n, %00n, %000n, etc. to enumerate." msgstr "" -#: usr/lib/bulky/bulky.py:439 +#: usr/lib/bulky/bulky.py:456 msgid "Rename Files" msgstr "" -#: usr/lib/bulky/bulky.py:487 +#: usr/lib/bulky/bulky.py:510 msgid "Add files" msgstr "" -#: usr/lib/bulky/bulky.py:516 +#: usr/lib/bulky/bulky.py:542 #, python-format msgid "Unable to rename '%s': File name too long" msgstr "" -#: usr/lib/bulky/bulky.py:519 +#: usr/lib/bulky/bulky.py:545 #, python-format msgid "" "Unable to rename '%s': Remote operation failed. This may be due to " "insufficient permissions or a server error." msgstr "" -#: usr/lib/bulky/bulky.py:523 +#: usr/lib/bulky/bulky.py:549 #, python-format msgid "Unable to rename '%s': %s" msgstr "" -#: usr/lib/bulky/bulky.py:599 generate_desktop_files:25 +#: usr/lib/bulky/bulky.py:592 usr/lib/bulky/bulky.py:618 +msgid "Renaming files…" +msgstr "" + +#: usr/lib/bulky/bulky.py:666 usr/lib/bulky/bulky.py:680 +msgid "Loading files…" +msgstr "" + +#: usr/lib/bulky/bulky.py:693 generate_desktop_files:25 msgid "File Renamer" msgstr "" -#: usr/lib/bulky/bulky.py:600 generate_desktop_files:25 +#: usr/lib/bulky/bulky.py:694 generate_desktop_files:25 msgid "Rename files and directories" msgstr "" -#: usr/lib/bulky/bulky.py:700 +#: usr/lib/bulky/bulky.py:793 #, python-format msgid "Name collision on '%s'." msgstr "" -#: usr/lib/bulky/bulky.py:704 usr/lib/bulky/bulky.py:708 +#: usr/lib/bulky/bulky.py:797 usr/lib/bulky/bulky.py:801 #, python-format msgid "'%s' is not writeable." msgstr "" diff --git a/usr/lib/bulky/bulky.py b/usr/lib/bulky/bulky.py index 567cd13..a1ad6d7 100755 --- a/usr/lib/bulky/bulky.py +++ b/usr/lib/bulky/bulky.py @@ -211,6 +211,7 @@ def __init__(self, application): # used to prevent collisions self.uris = [] self.renamed_uris = [] + self.is_processing = False self.last_chooser_location = Gio.File.new_for_path(GLib.get_home_dir()) # Set the Glade file @@ -224,6 +225,7 @@ def __init__(self, application): # Create variables to quickly access dynamic widgets self.headerbar = self.builder.get_object("headerbar") + self.file_progress = self.builder.get_object("file_progress") self.add_button = self.builder.get_object("add_button") self.remove_button = self.builder.get_object("remove_button") self.clear_button = self.builder.get_object("clear_button") @@ -405,8 +407,23 @@ def __init__(self, application): self.load_files(sys.argv[1:], initial_load=True) + def show_progress(self, text): + self.file_progress.set_fraction(0) + self.file_progress.set_text(text) + self.file_progress.show() + + def update_progress(self, current, total, text): + fraction = current / total if total else 0 + self.file_progress.set_fraction(fraction) + self.file_progress.set_text("{} {} / {}".format(text, current, total)) + + def hide_progress(self): + self.file_progress.hide() + self.file_progress.set_fraction(0) + self.file_progress.set_text("") + def on_drag_data_received(self, widget, context, x, y, data, info, _time, user_data=None): - if data: + if data and not self.is_processing: dtype = data.get_data_type().name() if context.get_selected_action() == Gdk.DragAction.COPY: if dtype.startswith("text/uri-list"): @@ -462,6 +479,9 @@ def on_files_selected(self, selection): self.remove_button.set_sensitive(len(paths) > 0) def on_key_press_event(self, widget, event): + if self.is_processing: + return + ctrl = (event.state & Gdk.ModifierType.CONTROL_MASK) if ctrl: if event.keyval == Gdk.KEY_n: @@ -484,6 +504,9 @@ def on_remove_button(self, widget): self.preview_changes() def on_add_button(self, widget): + if self.is_processing: + return + dialog = FolderFileChooserDialog(_("Add files"), self.window, self.last_chooser_location) def update_last_location(dialog, response_id, data=None): @@ -494,11 +517,14 @@ def update_last_location(dialog, response_id, data=None): dialog.connect("response", update_last_location) response = dialog.run() - if response == Gtk.ResponseType.OK: - for uri in dialog.get_uris(): - self.add_file(uri) - self.preview_changes() + if response != Gtk.ResponseType.OK: + dialog.destroy() + self.preview_changes() + return + + uris = dialog.get_uris() dialog.destroy() + self.load_files(uris) def on_clear_button(self, widget): self.model.clear() @@ -527,6 +553,9 @@ def report_os_error(self, file_obj, new_path, error): self.infobar.show() def on_rename_button(self, widget): + if self.is_processing: + return + iters = [] iter = self.model.get_iter_first() while iter != None: @@ -546,26 +575,58 @@ def on_rename_button(self, widget): print(e) rename_list = self.sort_list_by_depth(rename_list) + rename_list = [tup for tup in rename_list if tup[2] != tup[3]] # for i in rename_list: # print(i[0].gfile.get_uri()) - for tup in rename_list: - iter, file_obj, name, new_name = tup - if new_name != name: - try: - old_uri = file_obj.uri - # print("Renaming %s --> %s" % (file_obj.get_path_or_uri_for_display(), new_name)) - if file_obj.rename(new_name): - self.uris.remove(old_uri) - self.uris.append(file_obj.uri) - self.model.set_value(iter, COL_NAME, new_name) - except GLib.Error as e: - self.report_os_error(file_obj, new_name, e) - break - + total = len(rename_list) + current = 0 self.rename_button.set_sensitive(False) + if total == 0: + return + + self.is_processing = True + self.builder.get_object("file_toolbox").set_sensitive(False) + self.show_progress(_("Renaming files…")) + + def rename_next_file(): + nonlocal current + + iter, file_obj, name, new_name = rename_list[current] + try: + old_uri = file_obj.uri + # print("Renaming %s --> %s" % (file_obj.get_path_or_uri_for_display(), new_name)) + if file_obj.rename(new_name): + self.uris.remove(old_uri) + self.uris.append(file_obj.uri) + self.model.set_value(iter, COL_NAME, new_name) + except GLib.Error as e: + self.report_os_error(file_obj, new_name, e) + self.hide_progress() + self.builder.get_object("file_toolbox").set_sensitive(True) + self.is_processing = False + return False + except Exception: + self.hide_progress() + self.builder.get_object("file_toolbox").set_sensitive(True) + self.is_processing = False + raise + + current += 1 + self.update_progress(current, total, _("Renaming files…")) + + if current == total: + self.hide_progress() + self.builder.get_object("file_toolbox").set_sensitive(True) + self.is_processing = False + return False + + return True + + GLib.idle_add(rename_next_file) + def sort_list_by_depth(self, rename_list): # Rename files first, followed by directories from deep to shallow. def file_cmp(tup_a, tup_b): @@ -590,16 +651,48 @@ def file_cmp(tup_a, tup_b): def load_files(self, uris, initial_load=False): # Clear treeview and selection + if self.is_processing: + return + if len(uris) > 0: if initial_load: self.builder.get_object("file_toolbox").hide() - for path in uris: - self.add_file(path) + total = len(uris) + current = 0 + uri_iterator = iter(uris) + + self.is_processing = True + self.builder.get_object("file_toolbox").set_sensitive(False) + self.show_progress(_("Loading files…")) + + def load_next_file(): + nonlocal current + + try: + self.add_file(next(uri_iterator)) + except Exception: + self.hide_progress() + self.builder.get_object("file_toolbox").set_sensitive(True) + self.is_processing = False + raise + + current += 1 + self.update_progress(current, total, _("Loading files…")) + + if current == total: + self.hide_progress() + self.builder.get_object("file_toolbox").set_sensitive(True) + self.preview_changes() + self.is_processing = False + return False + + return True + + GLib.idle_add(load_next_file) else: self.builder.get_object("headerbar").set_title(_("File Renamer")) self.builder.get_object("headerbar").set_subtitle(_("Rename files and directories")) - - self.preview_changes() + self.preview_changes() def add_file(self, uri_or_path): file_obj = FileObject(uri_or_path, self.window.get_scale_factor()) diff --git a/usr/share/bulky/bulky.ui b/usr/share/bulky/bulky.ui index cd6ae61..112d26e 100644 --- a/usr/share/bulky/bulky.ui +++ b/usr/share/bulky/bulky.ui @@ -108,10 +108,6 @@ True in - - True - False - True True @@ -123,8 +119,6 @@ - - @@ -134,7 +128,26 @@ - + + True + False + horizontal + + + False + False + horizontal + 0 + True + + + True + True + 0 + + + + True False icons @@ -224,6 +237,13 @@ + + + False + True + 1 + + False