1 2from gi.repository import Gio 3from gi.repository import GLib 4from gi.repository import Gtk 5 6from meld.conf import _ 7from meld.misc import get_modal_parent, modal_dialog 8from meld.ui.filechooser import MeldFileChooserDialog 9 10 11def trash_or_confirm(gfile: Gio.File): 12 """Trash or delete the given Gio.File 13 14 Files and folders will be moved to the system Trash location 15 without confirmation. If they can't be trashed, then the user is 16 prompted for an irreversible deletion. 17 18 :rtype: bool 19 :returns: whether the file was deleted 20 """ 21 22 try: 23 gfile.trash(None) 24 return True 25 except GLib.GError as e: 26 # Handle not-supported, as that's due to the trashing target 27 # being a (probably network) mount-point, not an underlying 28 # problem. We also have to handle the generic FAILED code 29 # because that's what we get with NFS mounts. 30 expected_error = ( 31 e.code == Gio.IOErrorEnum.NOT_SUPPORTED or 32 e.code == Gio.IOErrorEnum.FAILED 33 ) 34 if not expected_error: 35 raise RuntimeError(str(e)) 36 37 file_type = gfile.query_file_type( 38 Gio.FileQueryInfoFlags.NONE, None) 39 40 if file_type == Gio.FileType.DIRECTORY: 41 raise RuntimeError(_("Deleting remote folders is not supported")) 42 elif file_type != Gio.FileType.REGULAR: 43 raise RuntimeError(_("Not a file or directory")) 44 45 delete_permanently = modal_dialog( 46 primary=_( 47 "“{}” can’t be put in the trash. Do you want to " 48 "delete it immediately?".format( 49 GLib.markup_escape_text(gfile.get_parse_name())) 50 ), 51 secondary=_( 52 "This remote location does not support sending items " 53 "to the trash." 54 ), 55 buttons=[ 56 (_("_Cancel"), Gtk.ResponseType.CANCEL), 57 (_("_Delete Permanently"), Gtk.ResponseType.OK), 58 ], 59 ) 60 61 if delete_permanently != Gtk.ResponseType.OK: 62 return False 63 64 try: 65 gfile.delete(None) 66 # TODO: Deleting remote folders involves reimplementing 67 # shutil.rmtree for gio, and then calling 68 # self.recursively_update(). 69 except Exception as e: 70 raise RuntimeError(str(e)) 71 72 73def prompt_save_filename(title: str, parent: Gtk.Widget = None) -> Gio.File: 74 dialog = MeldFileChooserDialog( 75 title, 76 transient_for=get_modal_parent(parent), 77 action=Gtk.FileChooserAction.SAVE, 78 ) 79 dialog.set_default_response(Gtk.ResponseType.ACCEPT) 80 response = dialog.run() 81 gfile = dialog.get_file() 82 dialog.destroy() 83 84 if response != Gtk.ResponseType.ACCEPT or not gfile: 85 return 86 87 try: 88 file_info = gfile.query_info( 89 'standard::name,standard::display-name', 0, None) 90 except GLib.Error as err: 91 if err.code == Gio.IOErrorEnum.NOT_FOUND: 92 return gfile 93 raise 94 95 # The selected file exists, so we need to prompt for overwrite. 96 parent_name = gfile.get_parent().get_parse_name() 97 file_name = file_info.get_display_name() 98 99 replace = modal_dialog( 100 primary=_("Replace file “%s”?") % file_name, 101 secondary=_( 102 "A file with this name already exists in “%s”.\n" 103 "If you replace the existing file, its contents " 104 "will be lost.") % parent_name, 105 buttons=[ 106 (_("_Cancel"), Gtk.ResponseType.CANCEL), 107 (_("_Replace"), Gtk.ResponseType.OK), 108 ], 109 messagetype=Gtk.MessageType.WARNING, 110 ) 111 if replace != Gtk.ResponseType.OK: 112 return 113 114 return gfile 115