mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Migrate delete action and location_selected code
This commit is contained in:
parent
673dee204d
commit
020286b746
@ -593,5 +593,9 @@ class ActionConvert(InterfaceActionBase):
|
|||||||
name = 'Convert Books'
|
name = 'Convert Books'
|
||||||
actual_plugin = 'calibre.gui2.actions.convert:ConvertAction'
|
actual_plugin = 'calibre.gui2.actions.convert:ConvertAction'
|
||||||
|
|
||||||
|
class ActionDelete(InterfaceActionBase):
|
||||||
|
name = 'Remove Books'
|
||||||
|
actual_plugin = 'calibre.gui2.actions.delete:DeleteAction'
|
||||||
|
|
||||||
plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
|
plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
|
||||||
ActionConvert]
|
ActionConvert, ActionDelete]
|
||||||
|
@ -52,3 +52,6 @@ class InterfaceAction(QObject):
|
|||||||
def genesis(self):
|
def genesis(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def location_selected(self, loc):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@ -35,6 +35,9 @@ class ConvertAction(InterfaceAction):
|
|||||||
self.convert_menu = cm
|
self.convert_menu = cm
|
||||||
self.conversion_jobs = {}
|
self.conversion_jobs = {}
|
||||||
|
|
||||||
|
def location_selected(self, loc):
|
||||||
|
enabled = loc == 'library'
|
||||||
|
self.qaction.setEnabled(enabled)
|
||||||
|
|
||||||
def auto_convert(self, book_ids, on_card, format):
|
def auto_convert(self, book_ids, on_card, format):
|
||||||
previous = self.gui.library_view.currentIndex()
|
previous = self.gui.library_view.currentIndex()
|
||||||
|
@ -5,16 +5,46 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from PyQt4.Qt import QMenu
|
||||||
|
|
||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog
|
||||||
from calibre.gui2.dialogs.delete_matching_from_device import DeleteMatchingFromDeviceDialog
|
from calibre.gui2.dialogs.delete_matching_from_device import DeleteMatchingFromDeviceDialog
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
|
from calibre.gui2.actions import InterfaceAction
|
||||||
|
|
||||||
class DeleteAction(object):
|
class DeleteAction(InterfaceAction):
|
||||||
|
|
||||||
|
name = 'Remove Books'
|
||||||
|
action_spec = (_('Remove books'), 'trash.svg', None, _('Del'))
|
||||||
|
|
||||||
|
def genesis(self):
|
||||||
|
self.qaction.triggered.connect(self.delete_books)
|
||||||
|
self.delete_menu = QMenu()
|
||||||
|
self.delete_menu.addAction(_('Remove selected books'), self.delete_books)
|
||||||
|
self.delete_menu.addAction(
|
||||||
|
_('Remove files of a specific format from selected books..'),
|
||||||
|
self.delete_selected_formats)
|
||||||
|
self.delete_menu.addAction(
|
||||||
|
_('Remove all formats from selected books, except...'),
|
||||||
|
self.delete_all_but_selected_formats)
|
||||||
|
self.delete_menu.addAction(
|
||||||
|
_('Remove covers from selected books'), self.delete_covers)
|
||||||
|
self.delete_menu.addSeparator()
|
||||||
|
self.delete_menu.addAction(
|
||||||
|
_('Remove matching books from device'),
|
||||||
|
self.remove_matching_books_from_device)
|
||||||
|
self.qaction.setMenu(self.delete_menu)
|
||||||
|
self.delete_memory = {}
|
||||||
|
|
||||||
|
def location_selected(self, loc):
|
||||||
|
enabled = loc == 'library'
|
||||||
|
for action in list(self.delete_menu.actions())[1:]:
|
||||||
|
action.setEnabled(enabled)
|
||||||
|
|
||||||
def _get_selected_formats(self, msg):
|
def _get_selected_formats(self, msg):
|
||||||
from calibre.gui2.dialogs.select_formats import SelectFormats
|
from calibre.gui2.dialogs.select_formats import SelectFormats
|
||||||
fmts = self.gui.library_view.model().db.all_formats()
|
fmts = self.gui.library_view.model().db.all_formats()
|
||||||
d = SelectFormats([x.lower() for x in fmts], msg, parent=self)
|
d = SelectFormats([x.lower() for x in fmts], msg, parent=self.gui)
|
||||||
if d.exec_() != d.Accepted:
|
if d.exec_() != d.Accepted:
|
||||||
return None
|
return None
|
||||||
return d.selected_formats
|
return d.selected_formats
|
||||||
@ -22,7 +52,7 @@ class DeleteAction(object):
|
|||||||
def _get_selected_ids(self, err_title=_('Cannot delete')):
|
def _get_selected_ids(self, err_title=_('Cannot delete')):
|
||||||
rows = self.gui.library_view.selectionModel().selectedRows()
|
rows = self.gui.library_view.selectionModel().selectedRows()
|
||||||
if not rows or len(rows) == 0:
|
if not rows or len(rows) == 0:
|
||||||
d = error_dialog(self, err_title, _('No book selected'))
|
d = error_dialog(self.gui, err_title, _('No book selected'))
|
||||||
d.exec_()
|
d.exec_()
|
||||||
return set([])
|
return set([])
|
||||||
return set(map(self.gui.library_view.model().id, rows))
|
return set(map(self.gui.library_view.model().id, rows))
|
||||||
@ -43,7 +73,7 @@ class DeleteAction(object):
|
|||||||
self.gui.library_view.model().current_changed(self.gui.library_view.currentIndex(),
|
self.gui.library_view.model().current_changed(self.gui.library_view.currentIndex(),
|
||||||
self.gui.library_view.currentIndex())
|
self.gui.library_view.currentIndex())
|
||||||
if ids:
|
if ids:
|
||||||
self.tags_view.recount()
|
self.gui.tags_view.recount()
|
||||||
|
|
||||||
def delete_all_but_selected_formats(self, *args):
|
def delete_all_but_selected_formats(self, *args):
|
||||||
ids = self._get_selected_ids()
|
ids = self._get_selected_ids()
|
||||||
@ -66,11 +96,11 @@ class DeleteAction(object):
|
|||||||
self.gui.library_view.model().current_changed(self.gui.library_view.currentIndex(),
|
self.gui.library_view.model().current_changed(self.gui.library_view.currentIndex(),
|
||||||
self.gui.library_view.currentIndex())
|
self.gui.library_view.currentIndex())
|
||||||
if ids:
|
if ids:
|
||||||
self.tags_view.recount()
|
self.gui.tags_view.recount()
|
||||||
|
|
||||||
def remove_matching_books_from_device(self, *args):
|
def remove_matching_books_from_device(self, *args):
|
||||||
if not self.device_manager.is_device_connected:
|
if not self.gui.device_manager.is_device_connected:
|
||||||
d = error_dialog(self, _('Cannot delete books'),
|
d = error_dialog(self.gui, _('Cannot delete books'),
|
||||||
_('No device is connected'))
|
_('No device is connected'))
|
||||||
d.exec_()
|
d.exec_()
|
||||||
return
|
return
|
||||||
@ -81,18 +111,18 @@ class DeleteAction(object):
|
|||||||
return
|
return
|
||||||
to_delete = {}
|
to_delete = {}
|
||||||
some_to_delete = False
|
some_to_delete = False
|
||||||
for model,name in ((self.memory_view.model(), _('Main memory')),
|
for model,name in ((self.gui.memory_view.model(), _('Main memory')),
|
||||||
(self.card_a_view.model(), _('Storage Card A')),
|
(self.gui.card_a_view.model(), _('Storage Card A')),
|
||||||
(self.card_b_view.model(), _('Storage Card B'))):
|
(self.gui.card_b_view.model(), _('Storage Card B'))):
|
||||||
to_delete[name] = (model, model.paths_for_db_ids(ids))
|
to_delete[name] = (model, model.paths_for_db_ids(ids))
|
||||||
if len(to_delete[name][1]) > 0:
|
if len(to_delete[name][1]) > 0:
|
||||||
some_to_delete = True
|
some_to_delete = True
|
||||||
if not some_to_delete:
|
if not some_to_delete:
|
||||||
d = error_dialog(self, _('No books to delete'),
|
d = error_dialog(self.gui, _('No books to delete'),
|
||||||
_('None of the selected books are on the device'))
|
_('None of the selected books are on the device'))
|
||||||
d.exec_()
|
d.exec_()
|
||||||
return
|
return
|
||||||
d = DeleteMatchingFromDeviceDialog(self, to_delete)
|
d = DeleteMatchingFromDeviceDialog(self.gui, to_delete)
|
||||||
if d.exec_():
|
if d.exec_():
|
||||||
paths = {}
|
paths = {}
|
||||||
ids = {}
|
ids = {}
|
||||||
@ -103,10 +133,10 @@ class DeleteAction(object):
|
|||||||
paths[model].append(path)
|
paths[model].append(path)
|
||||||
ids[model].append(id)
|
ids[model].append(id)
|
||||||
for model in paths:
|
for model in paths:
|
||||||
job = self.remove_paths(paths[model])
|
job = self.gui.remove_paths(paths[model])
|
||||||
self.delete_memory[job] = (paths[model], model)
|
self.delete_memory[job] = (paths[model], model)
|
||||||
model.mark_for_deletion(job, ids[model], rows_are_ids=True)
|
model.mark_for_deletion(job, ids[model], rows_are_ids=True)
|
||||||
self.status_bar.show_message(_('Deleting books from device.'), 1000)
|
self.gui.status_bar.show_message(_('Deleting books from device.'), 1000)
|
||||||
|
|
||||||
def delete_covers(self, *args):
|
def delete_covers(self, *args):
|
||||||
ids = self._get_selected_ids()
|
ids = self._get_selected_ids()
|
||||||
@ -126,18 +156,18 @@ class DeleteAction(object):
|
|||||||
rows = view.selectionModel().selectedRows()
|
rows = view.selectionModel().selectedRows()
|
||||||
if not rows or len(rows) == 0:
|
if not rows or len(rows) == 0:
|
||||||
return
|
return
|
||||||
if self.stack.currentIndex() == 0:
|
if self.gui.stack.currentIndex() == 0:
|
||||||
if not confirm('<p>'+_('The selected books will be '
|
if not confirm('<p>'+_('The selected books will be '
|
||||||
'<b>permanently deleted</b> and the files '
|
'<b>permanently deleted</b> and the files '
|
||||||
'removed from your computer. Are you sure?')
|
'removed from your computer. Are you sure?')
|
||||||
+'</p>', 'library_delete_books', self):
|
+'</p>', 'library_delete_books', self.gui):
|
||||||
return
|
return
|
||||||
ci = view.currentIndex()
|
ci = view.currentIndex()
|
||||||
row = None
|
row = None
|
||||||
if ci.isValid():
|
if ci.isValid():
|
||||||
row = ci.row()
|
row = ci.row()
|
||||||
ids_deleted = view.model().delete_books(rows)
|
ids_deleted = view.model().delete_books(rows)
|
||||||
for v in (self.memory_view, self.card_a_view, self.card_b_view):
|
for v in (self.gui.memory_view, self.gui.card_a_view, self.gui.card_b_view):
|
||||||
if v is None:
|
if v is None:
|
||||||
continue
|
continue
|
||||||
v.model().clear_ondevice(ids_deleted)
|
v.model().clear_ondevice(ids_deleted)
|
||||||
@ -149,17 +179,17 @@ class DeleteAction(object):
|
|||||||
if not confirm('<p>'+_('The selected books will be '
|
if not confirm('<p>'+_('The selected books will be '
|
||||||
'<b>permanently deleted</b> '
|
'<b>permanently deleted</b> '
|
||||||
'from your device. Are you sure?')
|
'from your device. Are you sure?')
|
||||||
+'</p>', 'device_delete_books', self):
|
+'</p>', 'device_delete_books', self.gui):
|
||||||
return
|
return
|
||||||
if self.stack.currentIndex() == 1:
|
if self.gui.stack.currentIndex() == 1:
|
||||||
view = self.memory_view
|
view = self.gui.memory_view
|
||||||
elif self.stack.currentIndex() == 2:
|
elif self.gui.stack.currentIndex() == 2:
|
||||||
view = self.card_a_view
|
view = self.gui.card_a_view
|
||||||
else:
|
else:
|
||||||
view = self.card_b_view
|
view = self.gui.card_b_view
|
||||||
paths = view.model().paths(rows)
|
paths = view.model().paths(rows)
|
||||||
job = self.remove_paths(paths)
|
job = self.gui.remove_paths(paths)
|
||||||
self.delete_memory[job] = (paths, view.model())
|
self.delete_memory[job] = (paths, view.model())
|
||||||
view.model().mark_for_deletion(job, rows)
|
view.model().mark_for_deletion(job, rows)
|
||||||
self.status_bar.show_message(_('Deleting books from device.'), 1000)
|
self.gui.status_bar.show_message(_('Deleting books from device.'), 1000)
|
||||||
|
|
||||||
|
@ -17,6 +17,10 @@ from calibre.gui2.dialogs.tag_list_editor import TagListEditor
|
|||||||
|
|
||||||
class EditMetadataAction(object):
|
class EditMetadataAction(object):
|
||||||
|
|
||||||
|
def location_selected(self, loc):
|
||||||
|
enabled = loc == 'library'
|
||||||
|
self.qaction.setEnabled(enabled)
|
||||||
|
|
||||||
def download_metadata(self, checked, covers=True, set_metadata=True,
|
def download_metadata(self, checked, covers=True, set_metadata=True,
|
||||||
set_social_metadata=None):
|
set_social_metadata=None):
|
||||||
rows = self.gui.library_view.selectionModel().selectedRows()
|
rows = self.gui.library_view.selectionModel().selectedRows()
|
||||||
|
@ -11,6 +11,10 @@ from calibre.utils.config import dynamic
|
|||||||
|
|
||||||
class FetchNewsAction(object):
|
class FetchNewsAction(object):
|
||||||
|
|
||||||
|
def location_selected(self, loc):
|
||||||
|
enabled = loc == 'library'
|
||||||
|
self.qaction.setEnabled(enabled)
|
||||||
|
|
||||||
def genesis(self):
|
def genesis(self):
|
||||||
self.conversion_jobs = {}
|
self.conversion_jobs = {}
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@ from calibre.ptempfile import PersistentTemporaryFile
|
|||||||
|
|
||||||
class ViewAction(object):
|
class ViewAction(object):
|
||||||
|
|
||||||
|
def location_selected(self, loc):
|
||||||
|
enabled = loc == 'library'
|
||||||
|
for action in list(self.view_menu.actions())[1:]:
|
||||||
|
action.setEnabled(enabled)
|
||||||
|
|
||||||
def view_format(self, row, format):
|
def view_format(self, row, format):
|
||||||
fmt_path = self.gui.library_view.model().db.format_abspath(row, format)
|
fmt_path = self.gui.library_view.model().db.format_abspath(row, format)
|
||||||
if fmt_path:
|
if fmt_path:
|
||||||
|
@ -792,8 +792,9 @@ class DeviceMixin(object): # {{{
|
|||||||
self.device_job_exception(job)
|
self.device_job_exception(job)
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.delete_memory.has_key(job):
|
dm = self.iactions['Remove Books'].delete_memory
|
||||||
paths, model = self.delete_memory.pop(job)
|
if dm.has_key(job):
|
||||||
|
paths, model = dm.pop(job)
|
||||||
self.device_manager.remove_books_from_metadata(paths,
|
self.device_manager.remove_books_from_metadata(paths,
|
||||||
self.booklists())
|
self.booklists())
|
||||||
model.paths_deleted(paths)
|
model.paths_deleted(paths)
|
||||||
|
@ -528,7 +528,6 @@ class MainWindowMixin(object):
|
|||||||
md.addSeparator()
|
md.addSeparator()
|
||||||
md.addAction(self.action_merge)
|
md.addAction(self.action_merge)
|
||||||
|
|
||||||
self.action_del.triggered.connect(self.delete_books)
|
|
||||||
self.action_edit.triggered.connect(self.edit_metadata)
|
self.action_edit.triggered.connect(self.edit_metadata)
|
||||||
self.action_merge.triggered.connect(self.merge_books)
|
self.action_merge.triggered.connect(self.merge_books)
|
||||||
|
|
||||||
@ -557,21 +556,6 @@ class MainWindowMixin(object):
|
|||||||
self.action_view.setMenu(self.view_menu)
|
self.action_view.setMenu(self.view_menu)
|
||||||
ac.triggered.connect(self.view_specific_format, type=Qt.QueuedConnection)
|
ac.triggered.connect(self.view_specific_format, type=Qt.QueuedConnection)
|
||||||
|
|
||||||
self.delete_menu = QMenu()
|
|
||||||
self.delete_menu.addAction(_('Remove selected books'), self.delete_books)
|
|
||||||
self.delete_menu.addAction(
|
|
||||||
_('Remove files of a specific format from selected books..'),
|
|
||||||
self.delete_selected_formats)
|
|
||||||
self.delete_menu.addAction(
|
|
||||||
_('Remove all formats from selected books, except...'),
|
|
||||||
self.delete_all_but_selected_formats)
|
|
||||||
self.delete_menu.addAction(
|
|
||||||
_('Remove covers from selected books'), self.delete_covers)
|
|
||||||
self.delete_menu.addSeparator()
|
|
||||||
self.delete_menu.addAction(
|
|
||||||
_('Remove matching books from device'),
|
|
||||||
self.remove_matching_books_from_device)
|
|
||||||
self.action_del.setMenu(self.delete_menu)
|
|
||||||
|
|
||||||
self.action_open_containing_folder.setShortcut(Qt.Key_O)
|
self.action_open_containing_folder.setShortcut(Qt.Key_O)
|
||||||
self.addAction(self.action_open_containing_folder)
|
self.addAction(self.action_open_containing_folder)
|
||||||
|
@ -149,7 +149,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
|||||||
self.verbose = opts.verbose
|
self.verbose = opts.verbose
|
||||||
self.get_metadata = GetMetadata()
|
self.get_metadata = GetMetadata()
|
||||||
self.upload_memory = {}
|
self.upload_memory = {}
|
||||||
self.delete_memory = {}
|
|
||||||
self.persistent_files = []
|
self.persistent_files = []
|
||||||
self.metadata_dialogs = []
|
self.metadata_dialogs = []
|
||||||
self.default_thumbnail = None
|
self.default_thumbnail = None
|
||||||
@ -437,26 +436,18 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
|||||||
for x in ('tb', 'cb'):
|
for x in ('tb', 'cb'):
|
||||||
splitter = getattr(self, x+'_splitter')
|
splitter = getattr(self, x+'_splitter')
|
||||||
splitter.button.setEnabled(location == 'library')
|
splitter.button.setEnabled(location == 'library')
|
||||||
|
for action in self.iactions.values():
|
||||||
|
action.location_selected(location)
|
||||||
if location == 'library':
|
if location == 'library':
|
||||||
self.action_edit.setEnabled(True)
|
|
||||||
self.action_merge.setEnabled(True)
|
self.action_merge.setEnabled(True)
|
||||||
self.action_convert.setEnabled(True)
|
|
||||||
self.view_menu.actions()[1].setEnabled(True)
|
|
||||||
self.action_open_containing_folder.setEnabled(True)
|
self.action_open_containing_folder.setEnabled(True)
|
||||||
self.action_sync.setEnabled(True)
|
self.action_sync.setEnabled(True)
|
||||||
self.search_restriction.setEnabled(True)
|
self.search_restriction.setEnabled(True)
|
||||||
for action in list(self.delete_menu.actions())[1:]:
|
|
||||||
action.setEnabled(True)
|
|
||||||
else:
|
else:
|
||||||
self.action_edit.setEnabled(False)
|
|
||||||
self.action_merge.setEnabled(False)
|
self.action_merge.setEnabled(False)
|
||||||
self.action_convert.setEnabled(False)
|
|
||||||
self.view_menu.actions()[1].setEnabled(False)
|
|
||||||
self.action_open_containing_folder.setEnabled(False)
|
self.action_open_containing_folder.setEnabled(False)
|
||||||
self.action_sync.setEnabled(False)
|
self.action_sync.setEnabled(False)
|
||||||
self.search_restriction.setEnabled(False)
|
self.search_restriction.setEnabled(False)
|
||||||
for action in list(self.delete_menu.actions())[1:]:
|
|
||||||
action.setEnabled(False)
|
|
||||||
# Reset the view in case something changed while it was invisible
|
# Reset the view in case something changed while it was invisible
|
||||||
self.current_view().reset()
|
self.current_view().reset()
|
||||||
self.set_number_of_books_shown()
|
self.set_number_of_books_shown()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user