restructuring file handler logic for conflict control

This commit is contained in:
itdominator 2021-11-29 16:49:56 -06:00
parent a418df2ce7
commit c4342c9099
4 changed files with 102 additions and 67 deletions

View File

@ -30,6 +30,11 @@ class Controller_Data:
self.message_buffer = self.builder.get_object("message_buffer")
self.arc_command_buffer = self.builder.get_object("arc_command_buffer")
self.exists_alert = self.builder.get_object("exists_alert")
self.exists_from_label = self.builder.get_object("exists_from_label")
self.exists_to_label = self.builder.get_object("exists_to_label")
self.exists_file_field = self.builder.get_object("exists_file_field")
self.bottom_size_label = self.builder.get_object("bottom_size_label")
self.bottom_file_count_label = self.builder.get_object("bottom_file_count_label")
self.bottom_path_label = self.builder.get_object("bottom_path_label")

View File

@ -4,6 +4,7 @@
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gio
# Application imports
@ -12,6 +13,33 @@ class ShowHideMixin:
def show_messages_popup(self, type, text, seconds=None):
self.message_widget.popup()
def show_exists_page(self, widget=None, eve=None):
# self.exists_alert = self.builder.get_object("exists_alert")
# self.exists_from_label = self.builder.get_object("exists_from_label")
# self.exists_to_label = self.builder.get_object("exists_to_label")
# self.exists_file_field = self.builder.get_object("exists_file_field")
response = self.exists_alert.run()
if response == Gtk.ResponseType.OK: # Rename
print(response)
return "rename", Gio.FileCreateFlags.NONE
if response == Gtk.ResponseType.ACCEPT: # Auto rename
return "rename_auto", Gio.FileCreateFlags.NONE
if response == Gtk.ResponseType.CLOSE: # Auto rename all
return "rename_auto_all", Gio.FileCreateFlags.NONE
if response == Gtk.ResponseType.YES: # Overwrite
return "overwrite", Gio.FileCreateFlags.OVERWRITE
if response == Gtk.ResponseType.APPLY: # Overwrite all
return "overwrite_all", Gio.FileCreateFlags.OVERWRITE
if response == Gtk.ResponseType.NO: # Skip
return "skip", Gio.FileCreateFlags.NONE
if response == Gtk.ResponseType.CANCEL: # Skip all
return "skip_all", Gio.FileCreateFlags.NONE
def show_about_page(self, widget=None, eve=None):
about_page = self.builder.get_object("about_page")
response = about_page.run()

View File

@ -56,10 +56,10 @@ class WidgetFileActionMixin:
view = self.get_fm_window(wid).get_view_by_id(tid)
target = f"{view.get_current_directory()}"
if file_name != "":
if file_name:
file_name = "file://" + target + "/" + file_name
if type == True: # Create File
self.handle_file([file_name], "create_file", target)
self.handle_file([file_name], "create_file")
else: # Create Folder
self.handle_file([file_name], "create_dir")
@ -82,12 +82,9 @@ class WidgetFileActionMixin:
store = iconview.get_model()
uris = self.format_to_uris(store, wid, tid, self.selected_files)
f = Gio.File.new_for_uri(uris[0])
file = Gio.File.new_for_uri(uris[0])
app_info = appchooser_widget.get_app_info()
app_info.launch([f], None)
def edit_files(self):
pass
app_info.launch([file], None)
def rename_files(self):
rename_label = self.builder.get_object("file_to_rename_label")
@ -119,6 +116,7 @@ class WidgetFileActionMixin:
rname_to = rename_input.get_text().strip()
target = f"file://{view.get_current_directory()}/{rname_to}"
print(target)
self.handle_file([uri], "edit", target)
self.show_edit_file_menu()
@ -133,7 +131,7 @@ class WidgetFileActionMixin:
wid, tid = self.window_controller.get_active_data()
iconview = self.builder.get_object(f"{wid}|{tid}|iconview")
store = iconview.get_model()
paths = self.format_to_uris(store, wid, tid, self.selected_files, True)
paths = self.format_to_uris(store, wid, tid, self.selected_files)
save_target = archiver_dialogue.get_filename();
start_itr, end_itr = self.arc_command_buffer.get_bounds()
@ -163,7 +161,7 @@ class WidgetFileActionMixin:
def paste_files(self):
wid, tid = self.window_controller.get_active_data()
view = self.get_fm_window(wid).get_view_by_id(tid)
target = f"{view.get_current_directory()}"
target = f"file://{view.get_current_directory()}"
if len(self.to_copy_files) > 0:
self.handle_file(self.to_copy_files, "copy", target)
@ -173,8 +171,8 @@ class WidgetFileActionMixin:
def move_file(self, view, files, target):
self.handle_file([files], "move", target)
def move_files(self, files, target):
self.handle_file(files, "move", target)
def delete_files(self):
wid, tid = self.window_controller.get_active_data()
@ -195,75 +193,84 @@ class WidgetFileActionMixin:
# NOTE: Gio moves files by generating the target file path with name in it
# We can't just give a base target directory and run with it.
# Also, the display name is UTF-8 safe and meant for displaying in GUIs
# NOTE: While not fully race condition proof, we happy path it first
# and then handle anything after as a conflict for renaming before
# copy, move, or edit.
def handle_file(self, paths, action, _target_path=None):
paths = self.preprocess_paths(paths)
target = None
for path in paths:
try:
f = Gio.File.new_for_uri(path)
file = Gio.File.new_for_uri(path)
if action == "trash":
file.trash(cancellable=None)
if action == "delete":
# TODO: Add proper confirmation prompt befor doing either
type = file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE)
if type == Gio.FileType.DIRECTORY:
wid, tid = self.window_controller.get_active_data()
view = self.get_fm_window(wid).get_view_by_id(tid)
view.delete_file( file.get_path() )
else:
file.delete(cancellable=None)
if (action == "create_file" or action == "create_dir") and not file.query_exists():
if action == "create_file":
f.create(Gio.FileCreateFlags.NONE, cancellable=None)
break
file.create(flags=Gio.FileCreateFlags.NONE, cancellable=None)
continue
if action == "create_dir":
f.make_directory(cancellable=None)
break
file.make_directory(cancellable=None)
continue
if _target_path:
if os.path.isdir(_target_path):
info = f.query_info("standard::display-name", 0, cancellable=None)
_target = f"file://{_target_path}/{info.get_display_name()}"
if os.path.isdir(_target_path.split("file://")[1]):
info = file.query_info("standard::display-name", 0, cancellable=None)
_target = f"{_target_path}/{info.get_display_name()}"
target = Gio.File.new_for_uri(_target)
else:
target = Gio.File.new_for_uri(_target_path)
# See if dragging to same directory then break
if action not in ["trash", "delete", "edit"] and \
(f.get_parent().get_path() == target.get_parent().get_path()):
break
if target and not target.query_exists():
type = file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE)
type = f.query_file_type(flags=Gio.FileQueryInfoFlags.NONE, cancellable=None)
if not type == Gio.FileType.DIRECTORY:
if action == "delete":
f.delete(cancellable=None)
if action == "trash":
f.trash(cancellable=None)
if action == "copy":
f.copy(target, flags=Gio.FileCopyFlags.BACKUP, cancellable=None)
if action == "move" or action == "edit":
f.move(target, flags=Gio.FileCopyFlags.BACKUP, cancellable=None)
else:
# Yes, life is hopeless and there is no God. Blame Gio for this sinful shitshow. =/
if type == Gio.FileType.DIRECTORY:
wid, tid = self.window_controller.get_active_data()
view = self.get_fm_window(wid).get_view_by_id(tid)
fPath = f.get_path()
fPath = file.get_path()
tPath = None
state = True
if target:
tPath = target.get_path()
if action == "delete":
state = view.delete_file(fPath)
if action == "trash":
f.trash(cancellable=None)
if action == "copy":
state = view.copy_file(fPath, tPath)
tPath = target.get_path()
view.copy_file(fPath, tPath)
if action == "move" or action == "edit":
tPath = target.get_parent().get_path()
state = view.move_file(fPath, tPath)
view.move_file(fPath, tPath)
else:
if action == "copy":
file.copy(target, flags=Gio.FileCopyFlags.BACKUP, cancellable=None)
if action == "move" or action == "edit":
file.move(target, flags=Gio.FileCopyFlags.BACKUP, cancellable=None)
if not state:
raise GObject.GError("Failed to perform requested dir/file action!")
# NOTE: Past here, we need to handle detected conflicts.
# Maybe create a collection of file and target pares
# that then get passed to a handler who calls show_exists_page?
# type = None
# gio_flag = None
# self.exists_alert.hide()
# if not state:
# raise GObject.GError("Failed to perform requested dir/file action!")
except GObject.GError as e:
raise OSError(e)
def preprocess_paths(self, paths):
if not isinstance(paths, list):
paths = [paths]

View File

@ -144,16 +144,11 @@ class WindowMixin(TabMixin):
view = self.get_fm_window(wid).get_view_by_id(tid)
uris = data.get_uris()
dest = view.get_current_directory()
dest = f"file://{view.get_current_directory()}"
if len(uris) > 0:
if debug:
print(f"Target Move Path: {dest}")
self.move_files(uris, dest)
for uri in uris:
if debug:
print(f"URI: {uri}")
self.move_file(view, uri, dest)
def create_new_view_notebook(self, widget=None, wid=None, path=None):
self.create_tab(wid, path)