Moved trash logic to plugin structure
This commit is contained in:
@@ -47,6 +47,8 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
|
||||
event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
|
||||
event_system.subscribe("get_current_state", self.get_current_state)
|
||||
event_system.subscribe("display_message", self.display_message)
|
||||
event_system.subscribe("go_to_path", self.go_to_path)
|
||||
event_system.subscribe("do_hide_context_menu", self.do_hide_context_menu)
|
||||
|
||||
def tear_down(self, widget=None, eve=None):
|
||||
self.fm_controller.save_state()
|
||||
@@ -100,7 +102,7 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
|
||||
gc.collect()
|
||||
|
||||
|
||||
def do_action_from_menu_controls(self, widget, event_button):
|
||||
def do_action_from_menu_controls(self, widget, eve = None):
|
||||
action = widget.get_name()
|
||||
self.hide_context_menu()
|
||||
self.hide_new_file_menu()
|
||||
@@ -124,16 +126,6 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
|
||||
self.paste_files()
|
||||
if action == "archive":
|
||||
self.show_archiver_dialogue()
|
||||
if action == "delete":
|
||||
self.delete_files()
|
||||
if action == "trash":
|
||||
self.trash_files()
|
||||
if action == "go_to_trash":
|
||||
self.path_entry.set_text(self.trash_files_path)
|
||||
if action == "restore_from_trash":
|
||||
self.restore_trash_files()
|
||||
if action == "empty_trash":
|
||||
self.empty_trash()
|
||||
if action == "create":
|
||||
self.create_files()
|
||||
if action in ["save_session", "save_session_as", "load_session"]:
|
||||
@@ -169,3 +161,9 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
|
||||
wid, tid = self.fm_controller.get_active_wid_and_tid()
|
||||
tab = self.get_fm_window(wid).get_tab_by_id(tid)
|
||||
tab.execute([f"{tab.terminal_app}"], start_dir=tab.get_current_directory())
|
||||
|
||||
def go_to_path(self, path):
|
||||
self.path_entry.set_text(path)
|
||||
|
||||
def do_hide_context_menu(self):
|
||||
self.hide_context_menu()
|
||||
|
@@ -7,7 +7,6 @@ import gi
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from trasher.xdgtrash import XDGTrash
|
||||
from shellfm.windows.controller import WindowController
|
||||
from plugins.plugins_controller import PluginsController
|
||||
|
||||
@@ -22,6 +21,7 @@ class State:
|
||||
selected_files: [] = None
|
||||
to_copy_files: [] = None
|
||||
to_cut_files: [] = None
|
||||
warning_alert: type = None
|
||||
|
||||
|
||||
class Controller_Data:
|
||||
@@ -34,11 +34,9 @@ class Controller_Data:
|
||||
self.logger = self.settings.get_logger()
|
||||
self.keybindings = self.settings.get_keybindings()
|
||||
|
||||
self.trashman = XDGTrash()
|
||||
self.fm_controller = WindowController()
|
||||
self.plugins = PluginsController(_settings)
|
||||
self.fm_controller_data = self.fm_controller.get_state_from_file()
|
||||
self.trashman.regenerate()
|
||||
|
||||
self.window = self.settings.get_main_window()
|
||||
self.window1 = self.builder.get_object("window_1")
|
||||
@@ -142,6 +140,7 @@ class Controller_Data:
|
||||
state.tab = self.get_fm_window(state.wid).get_tab_by_id(state.tid)
|
||||
state.icon_grid = self.builder.get_object(f"{state.wid}|{state.tid}|icon_grid")
|
||||
state.store = state.icon_grid.get_model()
|
||||
state.warning_alert = self.warning_alert
|
||||
|
||||
|
||||
selected_files = state.icon_grid.get_selected_items()
|
||||
@@ -155,7 +154,6 @@ class Controller_Data:
|
||||
# state.to_cut_files = self.format_to_uris(state.store, state.wid, state.tid, self.to_cut_files, True)
|
||||
|
||||
event_system.emit("update_state_info_plugins", state)
|
||||
|
||||
return state
|
||||
|
||||
|
||||
|
@@ -208,45 +208,6 @@ class WidgetFileActionMixin:
|
||||
elif self.to_cut_files:
|
||||
self.handle_files(self.to_cut_files, "move", target)
|
||||
|
||||
def delete_files(self):
|
||||
state = self.get_current_state()
|
||||
uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True)
|
||||
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_path(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:
|
||||
state.tab.delete_file( file.get_path() )
|
||||
else:
|
||||
file.delete(cancellable=None)
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
def trash_files(self):
|
||||
state = self.get_current_state()
|
||||
uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True)
|
||||
for uri in uris:
|
||||
self.trashman.trash(uri, False)
|
||||
|
||||
def restore_trash_files(self):
|
||||
state = self.get_current_state()
|
||||
uris = self.format_to_uris(state.store, state.wid, state.tid, self.selected_files, True)
|
||||
for uri in uris:
|
||||
self.trashman.restore(filename=uri.split("/")[-1], verbose=False)
|
||||
|
||||
def empty_trash(self):
|
||||
self.trashman.empty(verbose=False)
|
||||
|
||||
|
||||
def create_files(self):
|
||||
fname_field = self.builder.get_object("new_fname_field")
|
||||
self.show_new_file_menu(fname_field)
|
||||
|
@@ -88,12 +88,11 @@ class WindowMixin(TabMixin):
|
||||
formatted_mount_free = self.sizeof_fmt( int(mount_file.get_attribute_as_string("filesystem::free")) )
|
||||
formatted_mount_size = self.sizeof_fmt( int(mount_file.get_attribute_as_string("filesystem::size")) )
|
||||
|
||||
# NOTE: Hides empty trash and other desired buttons based on context.
|
||||
if self.trash_files_path == current_directory:
|
||||
self.builder.get_object("restore_from_trash").show()
|
||||
self.builder.get_object("empty_trash").show()
|
||||
event_system.emit("show_trash_buttons")
|
||||
else:
|
||||
self.builder.get_object("restore_from_trash").hide()
|
||||
self.builder.get_object("empty_trash").hide()
|
||||
event_system.emit("hide_trash_buttons")
|
||||
|
||||
# If something selected
|
||||
self.bottom_size_label.set_label(f"{formatted_mount_free} free / {formatted_mount_size}")
|
||||
|
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Trasher module
|
||||
"""
|
@@ -1,46 +0,0 @@
|
||||
# Python imports
|
||||
import os
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
|
||||
class Trash(object):
|
||||
"""Base Trash class."""
|
||||
|
||||
def size_dir(self, sdir):
|
||||
"""Get the size of a directory. Based on code found online."""
|
||||
size = os.path.getsize(sdir)
|
||||
|
||||
for item in os.listdir(sdir):
|
||||
item = os.path.join(sdir, item)
|
||||
|
||||
if os.path.isfile(item):
|
||||
size = size + os.path.getsize(item)
|
||||
elif os.path.isdir(item):
|
||||
size = size + self.size_dir(item)
|
||||
|
||||
return size
|
||||
|
||||
def regenerate(self):
|
||||
"""Regenerate the trash and recreate metadata."""
|
||||
pass # Some backends don’t need regeneration.
|
||||
|
||||
def empty(self, verbose):
|
||||
"""Empty the trash."""
|
||||
raise NotImplementedError(_('Backend didn’t implement this functionality'))
|
||||
|
||||
def list(self, human=True):
|
||||
"""List the trash contents."""
|
||||
raise NotImplementedError(_('Backend didn’t implement this functionality'))
|
||||
|
||||
def trash(self, filepath, verbose):
|
||||
"""Move specified file to trash."""
|
||||
raise NotImplementedError(_('Backend didn’t implement this functionality'))
|
||||
|
||||
def restore(self, filename, verbose):
|
||||
"""Restore a file from trash."""
|
||||
raise NotImplementedError(_('Backend didn’t \ implement this functionality'))
|
@@ -1,161 +0,0 @@
|
||||
from .trash import Trash
|
||||
import shutil
|
||||
import os
|
||||
import os.path
|
||||
import datetime
|
||||
import sys
|
||||
import logging
|
||||
|
||||
try:
|
||||
import configparser
|
||||
except ImportError:
|
||||
import ConfigParser as configparser
|
||||
|
||||
|
||||
|
||||
|
||||
class XDGTrash(Trash):
|
||||
"""XDG trash backend."""
|
||||
def __init__(self):
|
||||
self.trashdir = None
|
||||
self.filedir = None
|
||||
self.infodir = None
|
||||
|
||||
if os.getenv('XDG_DATA_HOME') is None:
|
||||
self.trashdir = os.path.expanduser('~/.local/share/Trash')
|
||||
else:
|
||||
self.trashdir = os.getenv('XDG_DATA_HOME') + '/Trash'
|
||||
|
||||
try:
|
||||
if not os.path.exists(self.trashdir):
|
||||
os.mkdir(self.trashdir)
|
||||
except OSError:
|
||||
self.trashdir = os.path.join('tmp' 'TRASH')
|
||||
raise('Couldn’t access the proper directory, temporary trash is in in /tmp/TRASH')
|
||||
|
||||
self.filedir = self.trashdir + '/files/'
|
||||
self.infodir = self.trashdir + '/info/'
|
||||
|
||||
def regenerate(self):
|
||||
"""Regenerate the trash and recreate metadata."""
|
||||
print('Regenerating the trash and recreating metadata...')
|
||||
zerosize = False
|
||||
|
||||
if not os.path.exists(self.trashdir):
|
||||
os.mkdir(self.trashdir)
|
||||
zerosize = True
|
||||
|
||||
if ((not os.path.exists(self.filedir)) or
|
||||
(not os.path.exists(self.infodir))):
|
||||
os.mkdir(self.filedir)
|
||||
os.mkdir(self.infodir)
|
||||
zerosize = True
|
||||
if not zerosize:
|
||||
trashsize = (self.size_dir(self.filedir) + self.size_dir(self.infodir))
|
||||
else:
|
||||
trashsize = 0
|
||||
|
||||
infofile = '[Cached]\nSize=' + str(trashsize) + '\n'
|
||||
fh = open(os.path.join(self.trashdir, 'metadata'), 'w')
|
||||
fh.write(infofile)
|
||||
fh.close()
|
||||
|
||||
def empty(self, verbose):
|
||||
"""Empty the trash."""
|
||||
print('emptying (verbose={})'.format(verbose))
|
||||
shutil.rmtree(self.filedir)
|
||||
shutil.rmtree(self.infodir)
|
||||
self.regenerate()
|
||||
if verbose:
|
||||
sys.stderr.write(_('emptied the trash\n'))
|
||||
|
||||
def list(self, human=True):
|
||||
"""List the trash contents."""
|
||||
if human:
|
||||
print('listing contents (on stdout; human=True)')
|
||||
else:
|
||||
print('listing contents (return; human=False)')
|
||||
dirs = []
|
||||
files = []
|
||||
for f in os.listdir(self.filedir):
|
||||
if os.path.isdir(self.filedir + f):
|
||||
dirs.append(f)
|
||||
else:
|
||||
files.append(f)
|
||||
|
||||
dirs.sort()
|
||||
files.sort()
|
||||
|
||||
allfiles = []
|
||||
for i in dirs:
|
||||
allfiles.append(i + '/')
|
||||
for i in files:
|
||||
allfiles.append(i)
|
||||
if human:
|
||||
if allfiles != []:
|
||||
print('\n'.join(allfiles))
|
||||
else:
|
||||
return allfiles
|
||||
|
||||
def trash(self, filepath, verbose):
|
||||
"""Move specified file to trash."""
|
||||
print('trashing file {} (verbose={})'.format(filepath, verbose))
|
||||
# Filename alteration, a big mess.
|
||||
filename = os.path.basename(filepath)
|
||||
fileext = os.path.splitext(filename)
|
||||
|
||||
tomove = filename
|
||||
collision = True
|
||||
i = 1
|
||||
|
||||
while collision:
|
||||
if os.path.lexists(self.filedir + tomove):
|
||||
tomove = fileext[0] + ' ' + str(i) + fileext[1]
|
||||
i = i + 1
|
||||
else:
|
||||
collision = False
|
||||
|
||||
infofile = """[Trash Info]
|
||||
Path={}
|
||||
DeletionDate={}
|
||||
""".format(os.path.realpath(filepath),
|
||||
datetime.datetime.now().strftime('%Y-%m-%dT%H:%m:%S'))
|
||||
|
||||
os.rename(filepath, self.filedir + tomove)
|
||||
|
||||
f = open(os.path.join(self.infodir, tomove + '.trashinfo'), 'w')
|
||||
f.write(infofile)
|
||||
f.close()
|
||||
|
||||
self.regenerate()
|
||||
|
||||
if verbose:
|
||||
sys.stderr.write(_('trashed \'{}\'\n').format(filename))
|
||||
|
||||
def restore(self, filename, verbose, tocwd=False):
|
||||
"""Restore a file from trash."""
|
||||
print('restoring file {} (verbose={}, tocwd={})'.format(filename, verbose, tocwd))
|
||||
info = configparser.ConfigParser()
|
||||
if os.path.exists(os.path.join(self.filedir, filename)):
|
||||
info.read(os.path.join(self.infodir, filename + '.trashinfo'))
|
||||
restname = os.path.basename(info.get('Trash Info', 'Path'))
|
||||
|
||||
if tocwd:
|
||||
restdir = os.path.abspath('.')
|
||||
else:
|
||||
restdir = os.path.dirname(info.get('Trash Info', 'Path'))
|
||||
|
||||
restfile = os.path.join(restdir, restname)
|
||||
if not os.path.exists(restdir):
|
||||
raise TMError('restore', 'nodir', _('no such directory: {}'
|
||||
' -- cannot restore').format(restdir))
|
||||
os.rename(os.path.join(self.filedir, filename), restfile)
|
||||
os.remove(os.path.join(self.infodir, filename + '.trashinfo'))
|
||||
self.regenerate()
|
||||
print('restored {} to {}'.format(filename, restfile))
|
||||
if verbose:
|
||||
sys.stderr.write(_('restored {} to {}\n').format(filename, restfile))
|
||||
|
||||
else:
|
||||
print('couldn\'t find {} in trash'.format(filename))
|
||||
raise TMError('restore', 'nofile', _('no such file in trash'))
|
Reference in New Issue
Block a user