Greatly improved file handling flow and added popup guards.
This commit is contained in:
parent
cbf5706845
commit
bed8af256c
@ -13,7 +13,6 @@ sudo apt-get install python3 wget ffmpegthumbnailer steamcmd
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>Fix the wonky file handler situation and add prompt guards for actions.</b></li>
|
|
||||||
<li>Add path bar search dropdown.</li>
|
<li>Add path bar search dropdown.</li>
|
||||||
<li>Add "clear trash", "restore from trash" options.</li>
|
<li>Add "clear trash", "restore from trash" options.</li>
|
||||||
<li>Add drive size free and consumed info to bottom bar.</li>
|
<li>Add drive size free and consumed info to bottom bar.</li>
|
||||||
|
@ -44,7 +44,7 @@ class Launcher:
|
|||||||
os.system(command)
|
os.system(command)
|
||||||
else:
|
else:
|
||||||
DEVNULL = open(os.devnull, 'w')
|
DEVNULL = open(os.devnull, 'w')
|
||||||
subprocess.Popen(command, cwd=start_dir, shell=False, start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True)
|
subprocess.Popen(command, cwd=start_dir, shell=True, start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True)
|
||||||
|
|
||||||
|
|
||||||
def remux_video(self, hash, file):
|
def remux_video(self, hash, file):
|
||||||
|
@ -127,7 +127,6 @@ class Controller(Controller_Data, ShowHideMixin, KeyboardSignalsMixin, \
|
|||||||
if action == "execute_in_terminal":
|
if action == "execute_in_terminal":
|
||||||
self.execute_files(in_terminal=True)
|
self.execute_files(in_terminal=True)
|
||||||
if action == "rename":
|
if action == "rename":
|
||||||
self.to_rename_files = self.selected_files
|
|
||||||
self.rename_files()
|
self.rename_files()
|
||||||
if action == "cut":
|
if action == "cut":
|
||||||
self.to_copy_files.clear()
|
self.to_copy_files.clear()
|
||||||
|
@ -31,10 +31,11 @@ class Controller_Data:
|
|||||||
self.arc_command_buffer = self.builder.get_object("arc_command_buffer")
|
self.arc_command_buffer = self.builder.get_object("arc_command_buffer")
|
||||||
|
|
||||||
self.warning_alert = self.builder.get_object("warning_alert")
|
self.warning_alert = self.builder.get_object("warning_alert")
|
||||||
self.exists_alert = self.builder.get_object("exists_alert")
|
self.edit_file_menu = self.builder.get_object("edit_file_menu")
|
||||||
self.exists_from_label = self.builder.get_object("exists_from_label")
|
self.file_exists_dialog = self.builder.get_object("file_exists_dialog")
|
||||||
self.exists_to_label = self.builder.get_object("exists_to_label")
|
self.exists_file_label = self.builder.get_object("exists_file_label")
|
||||||
self.exists_file_field = self.builder.get_object("exists_file_field")
|
self.exists_file_field = self.builder.get_object("exists_file_field")
|
||||||
|
self.exists_file_rename_bttn = self.builder.get_object("exists_file_rename_bttn")
|
||||||
|
|
||||||
self.bottom_size_label = self.builder.get_object("bottom_size_label")
|
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_file_count_label = self.builder.get_object("bottom_file_count_label")
|
||||||
@ -72,7 +73,6 @@ class Controller_Data:
|
|||||||
|
|
||||||
self.notebooks = [self.window1, self.window2, self.window3, self.window4]
|
self.notebooks = [self.window1, self.window2, self.window3, self.window4]
|
||||||
self.selected_files = []
|
self.selected_files = []
|
||||||
self.to_rename_files = []
|
|
||||||
self.to_copy_files = []
|
self.to_copy_files = []
|
||||||
self.to_cut_files = []
|
self.to_cut_files = []
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ class KeyboardSignalsMixin:
|
|||||||
if keyname == "delete":
|
if keyname == "delete":
|
||||||
self.delete_files()
|
self.delete_files()
|
||||||
if keyname == "f2":
|
if keyname == "f2":
|
||||||
self.do_edit_files()
|
self.rename_files()
|
||||||
if keyname == "f4":
|
if keyname == "f4":
|
||||||
wid, tid = self.window_controller.get_active_data()
|
wid, tid = self.window_controller.get_active_data()
|
||||||
view = self.get_fm_window(wid).get_view_by_id(tid)
|
view = self.get_fm_window(wid).get_view_by_id(tid)
|
||||||
|
@ -15,29 +15,32 @@ class ShowHideMixin:
|
|||||||
|
|
||||||
|
|
||||||
def show_exists_page(self, widget=None, eve=None):
|
def show_exists_page(self, widget=None, eve=None):
|
||||||
# self.exists_alert = self.builder.get_object("exists_alert")
|
response = self.file_exists_dialog.run()
|
||||||
# self.exists_from_label = self.builder.get_object("exists_from_label")
|
self.file_exists_dialog.hide()
|
||||||
# self.exists_to_label = self.builder.get_object("exists_to_label")
|
|
||||||
# self.exists_file_field = self.builder.get_object("exists_file_field")
|
|
||||||
|
|
||||||
|
if response == Gtk.ResponseType.OK:
|
||||||
|
return "rename"
|
||||||
|
if response == Gtk.ResponseType.ACCEPT:
|
||||||
|
return "rename_auto"
|
||||||
|
if response == Gtk.ResponseType.CLOSE:
|
||||||
|
return "rename_auto_all"
|
||||||
|
if response == Gtk.ResponseType.YES:
|
||||||
|
return "overwrite"
|
||||||
|
if response == Gtk.ResponseType.APPLY:
|
||||||
|
return "overwrite_all"
|
||||||
|
if response == Gtk.ResponseType.NO:
|
||||||
|
return "skip"
|
||||||
|
if response == Gtk.ResponseType.REJECT:
|
||||||
|
return "skip_all"
|
||||||
|
|
||||||
response = self.exists_alert.run()
|
def hide_exists_page_rename(self, widget=None, eve=None):
|
||||||
if response == Gtk.ResponseType.OK: # Rename
|
self.file_exists_dialog.response(Gtk.ResponseType.OK)
|
||||||
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 hide_exists_page_auto_rename(self, widget=None, eve=None):
|
||||||
|
self.file_exists_dialog.response(Gtk.ResponseType.ACCEPT)
|
||||||
|
|
||||||
|
def hide_exists_page_auto_rename_all(self, widget=None, eve=None):
|
||||||
|
self.file_exists_dialog.response(Gtk.ResponseType.CLOSE)
|
||||||
|
|
||||||
|
|
||||||
def show_about_page(self, widget=None, eve=None):
|
def show_about_page(self, widget=None, eve=None):
|
||||||
@ -49,6 +52,7 @@ class ShowHideMixin:
|
|||||||
def hide_about_page(self, widget=None, eve=None):
|
def hide_about_page(self, widget=None, eve=None):
|
||||||
self.builder.get_object("about_page").hide()
|
self.builder.get_object("about_page").hide()
|
||||||
|
|
||||||
|
|
||||||
def show_archiver_dialogue(self, widget=None, eve=None):
|
def show_archiver_dialogue(self, widget=None, eve=None):
|
||||||
wid, tid = self.window_controller.get_active_data()
|
wid, tid = self.window_controller.get_active_data()
|
||||||
view = self.get_fm_window(wid).get_view_by_id(tid)
|
view = self.get_fm_window(wid).get_view_by_id(tid)
|
||||||
@ -68,6 +72,7 @@ class ShowHideMixin:
|
|||||||
def hide_archiver_dialogue(self, widget=None, eve=None):
|
def hide_archiver_dialogue(self, widget=None, eve=None):
|
||||||
self.builder.get_object("archiver_dialogue").hide()
|
self.builder.get_object("archiver_dialogue").hide()
|
||||||
|
|
||||||
|
|
||||||
def show_appchooser_menu(self, widget=None, eve=None):
|
def show_appchooser_menu(self, widget=None, eve=None):
|
||||||
appchooser_menu = self.builder.get_object("appchooser_menu")
|
appchooser_menu = self.builder.get_object("appchooser_menu")
|
||||||
appchooser_widget = self.builder.get_object("appchooser_widget")
|
appchooser_widget = self.builder.get_object("appchooser_widget")
|
||||||
@ -86,36 +91,38 @@ class ShowHideMixin:
|
|||||||
dialog = widget.get_parent().get_parent()
|
dialog = widget.get_parent().get_parent()
|
||||||
dialog.response(Gtk.ResponseType.OK)
|
dialog.response(Gtk.ResponseType.OK)
|
||||||
|
|
||||||
|
|
||||||
def show_context_menu(self, widget=None, eve=None):
|
def show_context_menu(self, widget=None, eve=None):
|
||||||
self.builder.get_object("context_menu").run()
|
self.builder.get_object("context_menu").run()
|
||||||
|
|
||||||
def hide_context_menu(self, widget=None, eve=None):
|
def hide_context_menu(self, widget=None, eve=None):
|
||||||
self.builder.get_object("context_menu").hide()
|
self.builder.get_object("context_menu").hide()
|
||||||
|
|
||||||
|
|
||||||
def show_new_file_menu(self, widget=None, eve=None):
|
def show_new_file_menu(self, widget=None, eve=None):
|
||||||
self.builder.get_object("new_file_menu").run()
|
self.builder.get_object("new_file_menu").run()
|
||||||
|
|
||||||
def hide_new_file_menu(self, widget=None, eve=None):
|
def hide_new_file_menu(self, widget=None, eve=None):
|
||||||
self.builder.get_object("new_file_menu").hide()
|
self.builder.get_object("new_file_menu").hide()
|
||||||
|
|
||||||
|
|
||||||
def show_edit_file_menu(self, widget=None, eve=None):
|
def show_edit_file_menu(self, widget=None, eve=None):
|
||||||
self.builder.get_object("edit_file_menu").run()
|
response = self.edit_file_menu.run()
|
||||||
|
if response == Gtk.ResponseType.CLOSE:
|
||||||
|
self.skip_edit = True
|
||||||
|
if response == Gtk.ResponseType.CANCEL:
|
||||||
|
self.cancel_edit = True
|
||||||
|
|
||||||
def hide_edit_file_menu(self, widget=None, eve=None):
|
def hide_edit_file_menu(self, widget=None, eve=None):
|
||||||
if widget:
|
self.builder.get_object("edit_file_menu").hide()
|
||||||
name = widget.get_name()
|
|
||||||
if name == "rename":
|
|
||||||
self.builder.get_object("edit_file_menu").hide()
|
|
||||||
else:
|
|
||||||
keyname = Gdk.keyval_name(eve.keyval).lower()
|
|
||||||
if "return" in keyname or "enter" in keyname:
|
|
||||||
self.builder.get_object("edit_file_menu").hide()
|
|
||||||
|
|
||||||
|
def hide_edit_file_menu_enter_key(self, widget=None, eve=None):
|
||||||
|
keyname = Gdk.keyval_name(eve.keyval).lower()
|
||||||
|
if "return" in keyname or "enter" in keyname:
|
||||||
|
self.builder.get_object("edit_file_menu").hide()
|
||||||
|
|
||||||
def hide_edit_file_menu_skip(self, widget=None, eve=None):
|
def hide_edit_file_menu_skip(self, widget=None, eve=None):
|
||||||
self.skip_edit = True
|
self.edit_file_menu.response(Gtk.ResponseType.CLOSE)
|
||||||
self.builder.get_object("edit_file_menu").hide()
|
|
||||||
|
|
||||||
def hide_edit_file_menu_cancel(self, widget=None, eve=None):
|
def hide_edit_file_menu_cancel(self, widget=None, eve=None):
|
||||||
self.cancel_edit = True
|
self.edit_file_menu.response(Gtk.ResponseType.CANCEL)
|
||||||
self.builder.get_object("edit_file_menu").hide()
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
import os
|
import threading, os
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
import gi
|
import gi
|
||||||
@ -10,6 +10,12 @@ from gi.repository import Gtk, GObject, Gio
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def threaded(fn):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class WidgetFileActionMixin:
|
class WidgetFileActionMixin:
|
||||||
def set_file_watcher(self, view):
|
def set_file_watcher(self, view):
|
||||||
if view.get_dir_watcher():
|
if view.get_dir_watcher():
|
||||||
@ -69,13 +75,18 @@ class WidgetFileActionMixin:
|
|||||||
for file in uris:
|
for file in uris:
|
||||||
view.open_file_locally(file)
|
view.open_file_locally(file)
|
||||||
|
|
||||||
|
@threaded
|
||||||
def open_with_files(self, appchooser_widget):
|
def open_with_files(self, appchooser_widget):
|
||||||
wid, tid, view, iconview, store = self.get_current_state()
|
wid, tid, view, iconview, store = self.get_current_state()
|
||||||
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
|
||||||
file = Gio.File.new_for_uri(uris[0])
|
|
||||||
app_info = appchooser_widget.get_app_info()
|
app_info = appchooser_widget.get_app_info()
|
||||||
|
uris = self.format_to_uris(store, wid, tid, self.selected_files, True)
|
||||||
|
files = []
|
||||||
|
|
||||||
app_info.launch([file], None)
|
for uri in uris:
|
||||||
|
gio_file = Gio.File.new_for_path(uri)
|
||||||
|
files.append(gio_file)
|
||||||
|
|
||||||
|
app_info.launch(files, None)
|
||||||
|
|
||||||
def execute_files(self, in_terminal=False):
|
def execute_files(self, in_terminal=False):
|
||||||
wid, tid, view, iconview, store = self.get_current_state()
|
wid, tid, view, iconview, store = self.get_current_state()
|
||||||
@ -85,64 +96,58 @@ class WidgetFileActionMixin:
|
|||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
command = f"sh -c '{path}'" if not in_terminal else f"{view.terminal_app} -e '{path}'"
|
command = f"sh -c '{path}'" if not in_terminal else f"{view.terminal_app} -e '{path}'"
|
||||||
view.execute(command.split(), current_dir)
|
view.execute(command, start_dir=view.get_current_directory(), use_os_system=False)
|
||||||
|
|
||||||
|
def archive_files(self, archiver_dialogue):
|
||||||
|
wid, tid, view, iconview, store = self.get_current_state()
|
||||||
|
paths = self.format_to_uris(store, wid, tid, self.selected_files, True)
|
||||||
|
|
||||||
|
save_target = archiver_dialogue.get_filename();
|
||||||
|
sItr, eItr = self.arc_command_buffer.get_bounds()
|
||||||
|
pre_command = self.arc_command_buffer.get_text(sItr, eItr, False)
|
||||||
|
pre_command = pre_command.replace("%o", save_target)
|
||||||
|
pre_command = pre_command.replace("%N", ' '.join(paths))
|
||||||
|
command = f"{view.terminal_app} -e '{command}'"
|
||||||
|
|
||||||
|
view.execute(command, start_dir=None, use_os_system=True)
|
||||||
|
|
||||||
##################################################################################################
|
|
||||||
|
|
||||||
# NOTE: Everything below is trash and needs yet another rewrite because it doesn't work properly.
|
|
||||||
|
|
||||||
##################################################################################################
|
|
||||||
|
|
||||||
def rename_files(self):
|
def rename_files(self):
|
||||||
rename_label = self.builder.get_object("file_to_rename_label")
|
rename_label = self.builder.get_object("file_to_rename_label")
|
||||||
rename_input = self.builder.get_object("new_rename_fname")
|
rename_input = self.builder.get_object("new_rename_fname")
|
||||||
wid, tid, view, iconview, store = self.get_current_state()
|
wid, tid, view, iconview, store = self.get_current_state()
|
||||||
uris = self.format_to_uris(store, wid, tid, self.to_rename_files)
|
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
||||||
|
|
||||||
# The rename button hides the rename dialog box which lets the loop continue.
|
|
||||||
# Weirdly, the show at the end is needed to flow through all the list properly
|
|
||||||
# than auto chosing the first rename entry you do.
|
|
||||||
for uri in uris:
|
for uri in uris:
|
||||||
entry = uri.split("/")[-1]
|
entry = uri.split("/")[-1]
|
||||||
rename_label.set_label(entry)
|
rename_label.set_label(entry)
|
||||||
rename_input.set_text(entry)
|
rename_input.set_text(entry)
|
||||||
if self.skip_edit:
|
|
||||||
self.skip_edit = False
|
|
||||||
self.show_edit_file_menu()
|
|
||||||
|
|
||||||
# Yes...this step is required even with the above... =/
|
|
||||||
self.show_edit_file_menu()
|
self.show_edit_file_menu()
|
||||||
|
|
||||||
if self.skip_edit:
|
if self.skip_edit:
|
||||||
|
self.skip_edit = False
|
||||||
continue
|
continue
|
||||||
if self.cancel_edit:
|
if self.cancel_edit:
|
||||||
|
self.cancel_edit = False
|
||||||
break
|
break
|
||||||
|
|
||||||
rname_to = rename_input.get_text().strip()
|
rname_to = rename_input.get_text().strip()
|
||||||
target = f"file://{view.get_current_directory()}/{rname_to}"
|
target = f"file://{view.get_current_directory()}/{rname_to}"
|
||||||
self.handle_file([uri], "edit", target)
|
self.handle_file([uri], "rename", target)
|
||||||
|
|
||||||
self.show_edit_file_menu()
|
|
||||||
|
|
||||||
self.skip_edit = False
|
self.skip_edit = False
|
||||||
self.cancel_edit = False
|
self.cancel_edit = False
|
||||||
self.hide_new_file_menu()
|
self.hide_edit_file_menu()
|
||||||
self.to_rename_files.clear()
|
self.selected_files.clear()
|
||||||
|
|
||||||
def cut_files(self):
|
def cut_files(self):
|
||||||
wid, tid, view, iconview, store = self.get_current_state()
|
wid, tid, view, iconview, store = self.get_current_state()
|
||||||
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
||||||
self.to_cut_files = uris
|
self.to_cut_files = uris
|
||||||
|
|
||||||
def copy_files(self):
|
def copy_files(self):
|
||||||
wid, tid, view, iconview, store = self.get_current_state()
|
wid, tid, view, iconview, store = self.get_current_state()
|
||||||
print(self.selected_files)
|
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
||||||
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
|
||||||
print(uris)
|
|
||||||
self.to_copy_files = uris
|
self.to_copy_files = uris
|
||||||
|
|
||||||
def paste_files(self):
|
def paste_files(self):
|
||||||
@ -155,28 +160,35 @@ class WidgetFileActionMixin:
|
|||||||
elif len(self.to_cut_files) > 0:
|
elif len(self.to_cut_files) > 0:
|
||||||
self.handle_file(self.to_cut_files, "move", target)
|
self.handle_file(self.to_cut_files, "move", target)
|
||||||
|
|
||||||
def archive_files(self, archiver_dialogue):
|
|
||||||
wid, tid, view, iconview, store = self.get_current_state()
|
|
||||||
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()
|
|
||||||
command = self.arc_command_buffer.get_text(start_itr, end_itr, False)
|
|
||||||
|
|
||||||
command = command.replace("%o", save_target)
|
|
||||||
command = command.replace("%N", ' '.join(paths))
|
|
||||||
final_command = f"terminator -e '{command}'"
|
|
||||||
self.execute(final_command, start_dir=None, use_os_system=True)
|
|
||||||
|
|
||||||
def delete_files(self):
|
def delete_files(self):
|
||||||
wid, tid, view, iconview, store = self.get_current_state()
|
wid, tid, view, iconview, store = self.get_current_state()
|
||||||
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
||||||
self.handle_file(uris, "delete")
|
response = None
|
||||||
|
|
||||||
|
self.warning_alert.format_secondary_text(f"Do you really want to delete the {len(uris)} file(s)?")
|
||||||
|
for uri in uris:
|
||||||
|
file = Gio.File.new_for_uri(uri)
|
||||||
|
|
||||||
|
if not response:
|
||||||
|
response = self.warning_alert.run()
|
||||||
|
self.warning_alert.hide()
|
||||||
|
if response == Gtk.ResponseType.YES:
|
||||||
|
type = file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE)
|
||||||
|
|
||||||
|
if type == Gio.FileType.DIRECTORY:
|
||||||
|
view.delete_file( file.get_path() )
|
||||||
|
else:
|
||||||
|
file.delete(cancellable=None)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def trash_files(self):
|
def trash_files(self):
|
||||||
wid, tid, view, iconview, store = self.get_current_state()
|
wid, tid, view, iconview, store = self.get_current_state()
|
||||||
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
uris = self.format_to_uris(store, wid, tid, self.selected_files)
|
||||||
self.handle_file(uris, "trash")
|
for uri in uris:
|
||||||
|
file = Gio.File.new_for_uri(uri)
|
||||||
|
file.trash(cancellable=None)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -191,104 +203,146 @@ class WidgetFileActionMixin:
|
|||||||
target = f"{view.get_current_directory()}"
|
target = f"{view.get_current_directory()}"
|
||||||
|
|
||||||
if file_name:
|
if file_name:
|
||||||
file_name = "file://" + target + "/" + file_name
|
path = "file://{target}/{file_name}"
|
||||||
|
|
||||||
if type == True: # Create File
|
if type == True: # Create File
|
||||||
self.handle_file([file_name], "create_file")
|
self.handle_file([path], "create_file")
|
||||||
else: # Create Folder
|
else: # Create Folder
|
||||||
self.handle_file([file_name], "create_dir")
|
self.handle_file([path], "create_dir")
|
||||||
|
|
||||||
fname_field.set_text("")
|
fname_field.set_text("")
|
||||||
|
|
||||||
def move_files(self, files, target):
|
def move_files(self, files, target):
|
||||||
self.handle_file(files, "move", target)
|
self.handle_file(files, "move", target)
|
||||||
|
|
||||||
# NOTE: While not fully race condition proof, we happy path it first
|
# NOTE: Gtk recommends using fail flow than pre check existence which is more
|
||||||
# and then handle anything after as a conflict for renaming before
|
# race condition proof. They're right; but, they can't even delete
|
||||||
# copy, move, or edit. This is literally the oppopsite of what Gtk says to do.
|
# directories properly. So... f**k them. I'll do it my way.
|
||||||
# But, they can't even delete directories properly. So... f**k them.
|
|
||||||
def handle_file(self, paths, action, _target_path=None):
|
def handle_file(self, paths, action, _target_path=None):
|
||||||
paths = self.preprocess_paths(paths)
|
target = None
|
||||||
target = None
|
_file = None
|
||||||
response = None
|
response = None
|
||||||
self.warning_alert.format_secondary_text(f"Do you really want to {action} the {len(paths)} file(s)?")
|
overwrite_all = False
|
||||||
|
rename_auto_all = False
|
||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
try:
|
try:
|
||||||
file = Gio.File.new_for_uri(path)
|
file = Gio.File.new_for_uri(path)
|
||||||
|
|
||||||
if action == "trash":
|
|
||||||
file.trash(cancellable=None)
|
|
||||||
|
|
||||||
if (action == "create_file" or action == "create_dir") and not file.query_exists():
|
|
||||||
if action == "create_file":
|
|
||||||
file.create(flags=Gio.FileCreateFlags.NONE, cancellable=None)
|
|
||||||
continue
|
|
||||||
if action == "create_dir":
|
|
||||||
file.make_directory(cancellable=None)
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
|
||||||
if _target_path:
|
if _target_path:
|
||||||
if os.path.isdir(_target_path.split("file://")[1]):
|
if os.path.isdir(_target_path.split("file://")[1]):
|
||||||
info = file.query_info("standard::display-name", 0, cancellable=None)
|
info = file.query_info("standard::display-name", 0, cancellable=None)
|
||||||
_target = f"{_target_path}/{info.get_display_name()}"
|
_target = f"{_target_path}/{info.get_display_name()}"
|
||||||
target = Gio.File.new_for_uri(_target)
|
_file = Gio.File.new_for_uri(_target)
|
||||||
else:
|
else:
|
||||||
target = Gio.File.new_for_uri(_target_path)
|
_file = Gio.File.new_for_uri(_target_path)
|
||||||
|
else:
|
||||||
if target and not target.query_exists():
|
_file = Gio.File.new_for_uri(path)
|
||||||
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)
|
|
||||||
fPath = file.get_path()
|
|
||||||
tPath = None
|
|
||||||
state = True
|
|
||||||
|
|
||||||
if action == "copy":
|
|
||||||
tPath = target.get_path()
|
|
||||||
view.copy_file(fPath, tPath)
|
|
||||||
if action == "move" or action == "edit":
|
|
||||||
tPath = target.get_parent().get_path()
|
|
||||||
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 _file.query_exists():
|
||||||
|
if not overwrite_all and not rename_auto_all:
|
||||||
|
self.exists_file_label.set_label(_file.get_basename())
|
||||||
|
self.exists_file_field.set_text(_file.get_basename())
|
||||||
|
response = self.show_exists_page()
|
||||||
|
|
||||||
|
if response == "overwrite_all":
|
||||||
|
overwrite_all = True
|
||||||
|
if response == "rename_auto_all":
|
||||||
|
rename_auto_all = True
|
||||||
|
|
||||||
# NOTE: Past here, we need to handle detected conflicts.
|
if response == "rename":
|
||||||
# Maybe create a collection of file and target pares
|
base_path = _file.get_parent().get_path()
|
||||||
# that then get passed to a handler who calls show_exists_page?
|
new_name = self.exists_file_field.get_text().strip()
|
||||||
|
rfPath = f"{base_path}/{new_name}"
|
||||||
|
_file = Gio.File.new_for_path(rfPath)
|
||||||
|
|
||||||
if action == "delete":
|
if response == "rename_auto" or rename_auto_all:
|
||||||
if not response:
|
_file = self.rename_proc(_file)
|
||||||
response = self.warning_alert.run()
|
|
||||||
self.warning_alert.hide()
|
if response == "overwrite" or overwrite_all:
|
||||||
if response == Gtk.ResponseType.YES:
|
type = _file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE)
|
||||||
type = file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE)
|
|
||||||
|
|
||||||
if type == Gio.FileType.DIRECTORY:
|
if type == Gio.FileType.DIRECTORY:
|
||||||
wid, tid = self.window_controller.get_active_data()
|
view.delete_file( _file.get_path() )
|
||||||
view = self.get_fm_window(wid).get_view_by_id(tid)
|
|
||||||
view.delete_file( file.get_path() )
|
|
||||||
else:
|
else:
|
||||||
file.delete(cancellable=None)
|
_file.delete(cancellable=None)
|
||||||
else:
|
|
||||||
|
if response == "skip":
|
||||||
|
continue
|
||||||
|
if response == "skip_all":
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if _target_path:
|
||||||
|
target = _file
|
||||||
|
else:
|
||||||
|
file = _file
|
||||||
|
|
||||||
|
|
||||||
|
if action == "create_file":
|
||||||
|
file.create(flags=Gio.FileCreateFlags.NONE, cancellable=None)
|
||||||
|
continue
|
||||||
|
if action == "create_dir":
|
||||||
|
file.make_directory(cancellable=None)
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
fPath = file.get_path()
|
||||||
|
tPath = None
|
||||||
|
state = True
|
||||||
|
|
||||||
|
if action == "copy":
|
||||||
|
tPath = target.get_path()
|
||||||
|
view.copy_file(fPath, tPath)
|
||||||
|
if action == "move" or action == "rename":
|
||||||
|
tPath = target.get_parent().get_path()
|
||||||
|
view.move_file(fPath, tPath)
|
||||||
|
else:
|
||||||
|
if action == "copy":
|
||||||
|
file.copy(target, flags=Gio.FileCopyFlags.BACKUP, cancellable=None)
|
||||||
|
if action == "move" or action == "rename":
|
||||||
|
file.move(target, flags=Gio.FileCopyFlags.BACKUP, cancellable=None)
|
||||||
|
|
||||||
except GObject.GError as e:
|
except GObject.GError as e:
|
||||||
raise OSError(e)
|
raise OSError(e)
|
||||||
|
|
||||||
|
self.exists_file_rename_bttn.set_sensitive(False)
|
||||||
|
|
||||||
def preprocess_paths(self, paths):
|
|
||||||
if not isinstance(paths, list):
|
|
||||||
paths = [paths]
|
def rename_proc(self, gio_file):
|
||||||
# Convert items such as pathlib paths to strings
|
full_path = gio_file.get_path()
|
||||||
paths = [path.__fspath__() if hasattr(path, "__fspath__") else path for path in paths]
|
base_path = gio_file.get_parent().get_path()
|
||||||
return paths
|
file_name = os.path.splitext(gio_file.get_basename())[0]
|
||||||
|
extension = os.path.splitext(full_path)[-1]
|
||||||
|
target = Gio.File.new_for_path(full_path)
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print(f"Path: {full_path}")
|
||||||
|
print(f"Base Path: {base_path}")
|
||||||
|
print(f'Name: {file_name}')
|
||||||
|
print(f"Extension: {extension}")
|
||||||
|
|
||||||
|
i = 2
|
||||||
|
while target.query_exists():
|
||||||
|
target = Gio.File.new_for_path(f"{base_path}/{file_name}-copy{i}{extension}")
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
def exists_rename_field_changed(self, widget):
|
||||||
|
nfile_name = widget.get_text().strip()
|
||||||
|
ofile_name = self.exists_file_label.get_label()
|
||||||
|
|
||||||
|
if nfile_name:
|
||||||
|
if nfile_name == ofile_name:
|
||||||
|
self.exists_file_rename_bttn.set_sensitive(False)
|
||||||
|
else:
|
||||||
|
self.exists_file_rename_bttn.set_sensitive(True)
|
||||||
|
else:
|
||||||
|
self.exists_file_rename_bttn.set_sensitive(False)
|
||||||
|
@ -729,7 +729,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
@ -773,6 +773,242 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="stock">gtk-execute</property>
|
<property name="stock">gtk-execute</property>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkDialog" id="file_exists_dialog">
|
||||||
|
<property name="height-request">120</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="resizable">False</property>
|
||||||
|
<property name="modal">True</property>
|
||||||
|
<property name="window-position">center</property>
|
||||||
|
<property name="type-hint">splashscreen</property>
|
||||||
|
<property name="skip-taskbar-hint">True</property>
|
||||||
|
<property name="skip-pager-hint">True</property>
|
||||||
|
<property name="urgency-hint">True</property>
|
||||||
|
<property name="deletable">False</property>
|
||||||
|
<property name="gravity">center</property>
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<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">2</property>
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<object class="GtkButtonBox">
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="layout-style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button5">
|
||||||
|
<property name="label" translatable="yes">Overwrite</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button6">
|
||||||
|
<property name="label" translatable="yes">Overwrite (All)</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button7">
|
||||||
|
<property name="label" translatable="yes">Skip</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button8">
|
||||||
|
<property name="label" translatable="yes">Skip (All)</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Filename already exists. Please rename or select an action.</property>
|
||||||
|
<property name="xalign">0.10000000149011612</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="scale" value="1.5"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Filename:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="exists_file_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="exists_file_field">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<signal name="changed" handler="exists_rename_field_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="GtkButtonBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="spacing">20</property>
|
||||||
|
<property name="baseline-position">top</property>
|
||||||
|
<property name="layout-style">start</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="exists_file_rename_bttn">
|
||||||
|
<property name="label" translatable="yes">Rename</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
<signal name="button-release-event" handler="hide_exists_page_rename" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
<property name="secondary">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton">
|
||||||
|
<property name="label" translatable="yes">Auto Rename</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
<signal name="button-release-event" handler="hide_exists_page_auto_rename" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
<property name="secondary">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton">
|
||||||
|
<property name="label" translatable="yes">Auto Rename All</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
<signal name="button-release-event" handler="hide_exists_page_auto_rename_all" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
<property name="secondary">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<action-widgets>
|
||||||
|
<action-widget response="-8">button5</action-widget>
|
||||||
|
<action-widget response="-10">button6</action-widget>
|
||||||
|
<action-widget response="-9">button7</action-widget>
|
||||||
|
<action-widget response="-2">button8</action-widget>
|
||||||
|
</action-widgets>
|
||||||
|
<style>
|
||||||
|
<class name="alert-border"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
<object class="GtkImage" id="image1">
|
<object class="GtkImage" id="image1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
@ -856,12 +1092,15 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
</object>
|
</object>
|
||||||
<object class="GtkDialog" id="edit_file_menu">
|
<object class="GtkDialog" id="edit_file_menu">
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
|
<property name="resizable">False</property>
|
||||||
<property name="modal">True</property>
|
<property name="modal">True</property>
|
||||||
<property name="window-position">center</property>
|
<property name="window-position">center</property>
|
||||||
|
<property name="destroy-with-parent">True</property>
|
||||||
<property name="type-hint">splashscreen</property>
|
<property name="type-hint">splashscreen</property>
|
||||||
|
<property name="skip-taskbar-hint">True</property>
|
||||||
<property name="skip-pager-hint">True</property>
|
<property name="skip-pager-hint">True</property>
|
||||||
|
<property name="deletable">False</property>
|
||||||
<property name="gravity">center</property>
|
<property name="gravity">center</property>
|
||||||
<signal name="focus-out-event" handler="hide_edit_file_menu_cancel" swapped="no"/>
|
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
@ -872,14 +1111,14 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="layout-style">end</property>
|
<property name="layout-style">end</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton">
|
<object class="GtkButton" id="button1">
|
||||||
<property name="label" translatable="yes">Skip</property>
|
<property name="label" translatable="yes">Skip</property>
|
||||||
|
<property name="name">skip_renames</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">True</property>
|
<property name="receives-default">True</property>
|
||||||
<property name="image">skip_img</property>
|
<property name="image">skip_img</property>
|
||||||
<property name="always-show-image">True</property>
|
<property name="always-show-image">True</property>
|
||||||
<signal name="button-release-event" handler="hide_edit_file_menu_skip" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
@ -888,13 +1127,13 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton">
|
<object class="GtkButton" id="button2">
|
||||||
<property name="label">gtk-cancel</property>
|
<property name="label">gtk-cancel</property>
|
||||||
|
<property name="name">cancel_renames</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">True</property>
|
<property name="receives-default">True</property>
|
||||||
<property name="use-stock">True</property>
|
<property name="use-stock">True</property>
|
||||||
<signal name="button-release-event" handler="hide_edit_file_menu_cancel" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
@ -957,7 +1196,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
<property name="has-focus">True</property>
|
<property name="has-focus">True</property>
|
||||||
<property name="primary-icon-stock">gtk-edit</property>
|
<property name="primary-icon-stock">gtk-edit</property>
|
||||||
<property name="placeholder-text" translatable="yes">To:</property>
|
<property name="placeholder-text" translatable="yes">To:</property>
|
||||||
<signal name="key-release-event" handler="hide_edit_file_menu" swapped="no"/>
|
<signal name="key-release-event" handler="hide_edit_file_menu_enter_key" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
@ -991,6 +1230,10 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<action-widgets>
|
||||||
|
<action-widget response="-7">button1</action-widget>
|
||||||
|
<action-widget response="-6">button2</action-widget>
|
||||||
|
</action-widgets>
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkImage" id="tggl_notebook_1_img">
|
<object class="GtkImage" id="tggl_notebook_1_img">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -1730,12 +1973,13 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
<child>
|
<child>
|
||||||
<object class="GtkButton">
|
<object class="GtkButton">
|
||||||
<property name="label" translatable="yes">Open With</property>
|
<property name="label" translatable="yes">Open With</property>
|
||||||
|
<property name="name">open_with</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">True</property>
|
<property name="receives-default">True</property>
|
||||||
<property name="image">open_with_img</property>
|
<property name="image">open_with_img</property>
|
||||||
<property name="always-show-image">True</property>
|
<property name="always-show-image">True</property>
|
||||||
<signal name="button-release-event" handler="show_appchooser_menu" swapped="no"/>
|
<signal name="button-release-event" handler="do_action_from_menu_controls" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
@ -1786,7 +2030,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
<property name="margin-top">20</property>
|
<property name="margin-top">20</property>
|
||||||
<property name="image">rename_img2</property>
|
<property name="image">rename_img2</property>
|
||||||
<property name="always-show-image">True</property>
|
<property name="always-show-image">True</property>
|
||||||
<signal name="button-release-event" handler="do_edit_files" swapped="no"/>
|
<signal name="button-release-event" handler="do_action_from_menu_controls" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
@ -1923,16 +2167,26 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
</object>
|
</object>
|
||||||
<object class="GtkMessageDialog" id="warning_alert">
|
<object class="GtkMessageDialog" id="warning_alert">
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
|
<property name="resizable">False</property>
|
||||||
<property name="modal">True</property>
|
<property name="modal">True</property>
|
||||||
<property name="window-position">center</property>
|
<property name="window-position">center</property>
|
||||||
|
<property name="destroy-with-parent">True</property>
|
||||||
<property name="type-hint">dialog</property>
|
<property name="type-hint">dialog</property>
|
||||||
|
<property name="skip-taskbar-hint">True</property>
|
||||||
|
<property name="skip-pager-hint">True</property>
|
||||||
|
<property name="urgency-hint">True</property>
|
||||||
<property name="decorated">False</property>
|
<property name="decorated">False</property>
|
||||||
|
<property name="deletable">False</property>
|
||||||
<property name="gravity">center</property>
|
<property name="gravity">center</property>
|
||||||
<property name="message-type">warning</property>
|
<property name="message-type">warning</property>
|
||||||
<property name="text" translatable="yes">Warning!</property>
|
<property name="text" translatable="yes">Warning!</property>
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="can-focus">False</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="orientation">vertical</property>
|
||||||
<property name="spacing">2</property>
|
<property name="spacing">2</property>
|
||||||
<child internal-child="action_area">
|
<child internal-child="action_area">
|
||||||
@ -1982,5 +2236,8 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
|
|||||||
<action-widget response="-9">button4</action-widget>
|
<action-widget response="-9">button4</action-widget>
|
||||||
<action-widget response="-8">button3</action-widget>
|
<action-widget response="-8">button3</action-widget>
|
||||||
</action-widgets>
|
</action-widgets>
|
||||||
|
<style>
|
||||||
|
<class name="alert-border"/>
|
||||||
|
</style>
|
||||||
</object>
|
</object>
|
||||||
</interface>
|
</interface>
|
||||||
|
@ -39,6 +39,10 @@ notebook > header > tabs > tab:checked {
|
|||||||
color: rgba(255, 255, 255, 0.5);
|
color: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert-border {
|
||||||
|
border: 2px solid rgba(116, 0, 0, 0.64);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* * {
|
/* * {
|
||||||
background: rgba(0, 0, 0, 0.14);
|
background: rgba(0, 0, 0, 0.14);
|
||||||
|
Loading…
Reference in New Issue
Block a user