2012-05-30 16:10:56 +00:00
|
|
|
# Created On: 2012-05-30
|
2015-01-03 21:30:57 +00:00
|
|
|
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
2020-01-01 02:16:27 +00:00
|
|
|
#
|
|
|
|
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
|
|
# which should be included with this package. The terms are also available at
|
2015-01-03 21:33:16 +00:00
|
|
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
2012-05-30 16:10:56 +00:00
|
|
|
|
2013-07-14 15:58:49 +00:00
|
|
|
import os
|
|
|
|
|
2012-05-30 16:10:56 +00:00
|
|
|
from hscommon.gui.base import GUIObject
|
|
|
|
from hscommon.trans import tr
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
class DeletionOptionsView:
|
|
|
|
"""Expected interface for :class:`DeletionOptions`'s view.
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
*Not actually used in the code. For documentation purposes only.*
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
Our view presents the user with an appropriate way (probably a mix of checkboxes and radio
|
|
|
|
buttons) to set the different flags in :class:`DeletionOptions`. Note that
|
|
|
|
:attr:`DeletionOptions.use_hardlinks` is only relevant if :attr:`DeletionOptions.link_deleted`
|
|
|
|
is true. This is why we toggle the "enabled" state of that flag.
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
We expect the view to set :attr:`DeletionOptions.link_deleted` immediately as the user changes
|
|
|
|
its value because it will toggle :meth:`set_hardlink_option_enabled`
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
Other than the flags, there's also a prompt message which has a dynamic content, defined by
|
|
|
|
:meth:`update_msg`.
|
|
|
|
"""
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
def update_msg(self, msg: str):
|
|
|
|
"""Update the dialog's prompt with ``str``.
|
|
|
|
"""
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
def show(self):
|
|
|
|
"""Show the dialog in a modal fashion.
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
Returns whether the dialog was "accepted" (the user pressed OK).
|
|
|
|
"""
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
def set_hardlink_option_enabled(self, is_enabled: bool):
|
|
|
|
"""Enable or disable the widget controlling :attr:`DeletionOptions.use_hardlinks`.
|
|
|
|
"""
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2012-05-30 16:10:56 +00:00
|
|
|
class DeletionOptions(GUIObject):
|
2013-12-06 20:48:01 +00:00
|
|
|
"""Present the user with deletion options before proceeding.
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
When the user activates "Send to trash", we present him with a couple of options that changes
|
|
|
|
the behavior of that deletion operation.
|
|
|
|
"""
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
def __init__(self):
|
|
|
|
GUIObject.__init__(self)
|
|
|
|
#: Whether symlinks or hardlinks are used when doing :attr:`link_deleted`.
|
|
|
|
#: *bool*. *get/set*
|
|
|
|
self.use_hardlinks = False
|
|
|
|
#: Delete dupes directly and don't send to trash.
|
|
|
|
#: *bool*. *get/set*
|
|
|
|
self.direct = False
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2012-05-30 16:10:56 +00:00
|
|
|
def show(self, mark_count):
|
2013-12-06 20:48:01 +00:00
|
|
|
"""Prompt the user with a modal dialog offering our deletion options.
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
:param int mark_count: Number of dupes marked for deletion.
|
|
|
|
:rtype: bool
|
|
|
|
:returns: Whether the user accepted the dialog (we cancel deletion if false).
|
|
|
|
"""
|
|
|
|
self._link_deleted = False
|
|
|
|
self.view.set_hardlink_option_enabled(False)
|
2012-08-01 16:36:23 +00:00
|
|
|
self.use_hardlinks = False
|
2012-05-30 16:10:56 +00:00
|
|
|
self.direct = False
|
|
|
|
msg = tr("You are sending {} file(s) to the Trash.").format(mark_count)
|
|
|
|
self.view.update_msg(msg)
|
|
|
|
return self.view.show()
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-07-14 15:58:49 +00:00
|
|
|
def supports_links(self):
|
2013-12-06 20:48:01 +00:00
|
|
|
"""Returns whether our platform supports symlinks.
|
|
|
|
"""
|
2013-07-14 15:58:49 +00:00
|
|
|
# When on a platform that doesn't implement it, calling os.symlink() (with the wrong number
|
|
|
|
# of arguments) raises NotImplementedError, which allows us to gracefully check for the
|
|
|
|
# feature.
|
|
|
|
try:
|
|
|
|
os.symlink()
|
|
|
|
except NotImplementedError:
|
2013-07-14 17:59:03 +00:00
|
|
|
# Windows XP, not supported
|
|
|
|
return False
|
|
|
|
except OSError:
|
|
|
|
# Vista+, symbolic link privilege not held
|
2013-07-14 15:58:49 +00:00
|
|
|
return False
|
|
|
|
except TypeError:
|
|
|
|
# wrong number of arguments
|
|
|
|
return True
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
@property
|
|
|
|
def link_deleted(self):
|
|
|
|
"""Replace deleted dupes with symlinks (or hardlinks) to the dupe group reference.
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
*bool*. *get/set*
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
Whether the link is a symlink or hardlink is decided by :attr:`use_hardlinks`.
|
|
|
|
"""
|
|
|
|
return self._link_deleted
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2013-12-06 20:48:01 +00:00
|
|
|
@link_deleted.setter
|
|
|
|
def link_deleted(self, value):
|
|
|
|
self._link_deleted = value
|
|
|
|
hardlinks_enabled = value and self.supports_links()
|
|
|
|
self.view.set_hardlink_option_enabled(hardlinks_enabled)
|