diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 8462ae5d38..8232a163e7 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -593,5 +593,9 @@ class ActionConvert(InterfaceActionBase): name = 'Convert Books' actual_plugin = 'calibre.gui2.actions.convert:ConvertAction' +class ActionDelete(InterfaceActionBase): + name = 'Remove Books' + actual_plugin = 'calibre.gui2.actions.delete:DeleteAction' + plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog, - ActionConvert] + ActionConvert, ActionDelete] diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index 65d0078c50..b198a69214 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -52,3 +52,6 @@ class InterfaceAction(QObject): def genesis(self): pass + def location_selected(self, loc): + pass + diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py index ace877b315..0641cc6a97 100644 --- a/src/calibre/gui2/actions/convert.py +++ b/src/calibre/gui2/actions/convert.py @@ -35,6 +35,9 @@ class ConvertAction(InterfaceAction): self.convert_menu = cm self.conversion_jobs = {} + def location_selected(self, loc): + enabled = loc == 'library' + self.qaction.setEnabled(enabled) def auto_convert(self, book_ids, on_card, format): previous = self.gui.library_view.currentIndex() diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py index de3c4d8868..e0f3ae4d65 100644 --- a/src/calibre/gui2/actions/delete.py +++ b/src/calibre/gui2/actions/delete.py @@ -5,16 +5,46 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' +from PyQt4.Qt import QMenu + from calibre.gui2 import error_dialog from calibre.gui2.dialogs.delete_matching_from_device import DeleteMatchingFromDeviceDialog 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): from calibre.gui2.dialogs.select_formats import SelectFormats 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: return None return d.selected_formats @@ -22,7 +52,7 @@ class DeleteAction(object): def _get_selected_ids(self, err_title=_('Cannot delete')): rows = self.gui.library_view.selectionModel().selectedRows() 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_() return set([]) 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.currentIndex()) if ids: - self.tags_view.recount() + self.gui.tags_view.recount() def delete_all_but_selected_formats(self, *args): 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.currentIndex()) if ids: - self.tags_view.recount() + self.gui.tags_view.recount() def remove_matching_books_from_device(self, *args): - if not self.device_manager.is_device_connected: - d = error_dialog(self, _('Cannot delete books'), + if not self.gui.device_manager.is_device_connected: + d = error_dialog(self.gui, _('Cannot delete books'), _('No device is connected')) d.exec_() return @@ -81,18 +111,18 @@ class DeleteAction(object): return to_delete = {} some_to_delete = False - for model,name in ((self.memory_view.model(), _('Main memory')), - (self.card_a_view.model(), _('Storage Card A')), - (self.card_b_view.model(), _('Storage Card B'))): + for model,name in ((self.gui.memory_view.model(), _('Main memory')), + (self.gui.card_a_view.model(), _('Storage Card A')), + (self.gui.card_b_view.model(), _('Storage Card B'))): to_delete[name] = (model, model.paths_for_db_ids(ids)) if len(to_delete[name][1]) > 0: some_to_delete = True 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')) d.exec_() return - d = DeleteMatchingFromDeviceDialog(self, to_delete) + d = DeleteMatchingFromDeviceDialog(self.gui, to_delete) if d.exec_(): paths = {} ids = {} @@ -103,10 +133,10 @@ class DeleteAction(object): paths[model].append(path) ids[model].append(id) for model in paths: - job = self.remove_paths(paths[model]) + job = self.gui.remove_paths(paths[model]) self.delete_memory[job] = (paths[model], model) 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): ids = self._get_selected_ids() @@ -126,18 +156,18 @@ class DeleteAction(object): rows = view.selectionModel().selectedRows() if not rows or len(rows) == 0: return - if self.stack.currentIndex() == 0: + if self.gui.stack.currentIndex() == 0: if not confirm('

'+_('The selected books will be ' 'permanently deleted and the files ' 'removed from your computer. Are you sure?') - +'

', 'library_delete_books', self): + +'

', 'library_delete_books', self.gui): return ci = view.currentIndex() row = None if ci.isValid(): row = ci.row() 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: continue v.model().clear_ondevice(ids_deleted) @@ -149,17 +179,17 @@ class DeleteAction(object): if not confirm('

'+_('The selected books will be ' 'permanently deleted ' 'from your device. Are you sure?') - +'

', 'device_delete_books', self): + +'

', 'device_delete_books', self.gui): return - if self.stack.currentIndex() == 1: - view = self.memory_view - elif self.stack.currentIndex() == 2: - view = self.card_a_view + if self.gui.stack.currentIndex() == 1: + view = self.gui.memory_view + elif self.gui.stack.currentIndex() == 2: + view = self.gui.card_a_view else: - view = self.card_b_view + view = self.gui.card_b_view paths = view.model().paths(rows) - job = self.remove_paths(paths) + job = self.gui.remove_paths(paths) self.delete_memory[job] = (paths, view.model()) 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) diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 5c323e609d..e4b2145da0 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -17,6 +17,10 @@ from calibre.gui2.dialogs.tag_list_editor import TagListEditor 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, set_social_metadata=None): rows = self.gui.library_view.selectionModel().selectedRows() diff --git a/src/calibre/gui2/actions/fetch_news.py b/src/calibre/gui2/actions/fetch_news.py index 361e3d63bd..d161877cea 100644 --- a/src/calibre/gui2/actions/fetch_news.py +++ b/src/calibre/gui2/actions/fetch_news.py @@ -11,6 +11,10 @@ from calibre.utils.config import dynamic class FetchNewsAction(object): + def location_selected(self, loc): + enabled = loc == 'library' + self.qaction.setEnabled(enabled) + def genesis(self): self.conversion_jobs = {} diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py index bf445b40b2..bdad55d142 100644 --- a/src/calibre/gui2/actions/view.py +++ b/src/calibre/gui2/actions/view.py @@ -18,6 +18,11 @@ from calibre.ptempfile import PersistentTemporaryFile 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): fmt_path = self.gui.library_view.model().db.format_abspath(row, format) if fmt_path: diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 6cc8e47aa5..1e716a85fe 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -792,8 +792,9 @@ class DeviceMixin(object): # {{{ self.device_job_exception(job) return - if self.delete_memory.has_key(job): - paths, model = self.delete_memory.pop(job) + dm = self.iactions['Remove Books'].delete_memory + if dm.has_key(job): + paths, model = dm.pop(job) self.device_manager.remove_books_from_metadata(paths, self.booklists()) model.paths_deleted(paths) diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index b0851c0b25..74da5f53d3 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -528,7 +528,6 @@ class MainWindowMixin(object): md.addSeparator() md.addAction(self.action_merge) - self.action_del.triggered.connect(self.delete_books) self.action_edit.triggered.connect(self.edit_metadata) self.action_merge.triggered.connect(self.merge_books) @@ -557,21 +556,6 @@ class MainWindowMixin(object): self.action_view.setMenu(self.view_menu) 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.addAction(self.action_open_containing_folder) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 79d16eeb5a..df0c9091b5 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -149,7 +149,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.verbose = opts.verbose self.get_metadata = GetMetadata() self.upload_memory = {} - self.delete_memory = {} self.persistent_files = [] self.metadata_dialogs = [] self.default_thumbnail = None @@ -437,26 +436,18 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ for x in ('tb', 'cb'): splitter = getattr(self, x+'_splitter') splitter.button.setEnabled(location == 'library') + for action in self.iactions.values(): + action.location_selected(location) if location == 'library': - self.action_edit.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_sync.setEnabled(True) self.search_restriction.setEnabled(True) - for action in list(self.delete_menu.actions())[1:]: - action.setEnabled(True) else: - self.action_edit.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_sync.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 self.current_view().reset() self.set_number_of_books_shown()