From 82dc900a11bc9c6de9c7966deb41964ac6a01971 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 12 Aug 2010 11:09:47 -0600 Subject: [PATCH] Migrated Add Books action --- src/calibre/gui2/actions/__init__.py | 31 +++++++- src/calibre/gui2/actions/add.py | 108 ++++++++++++++++----------- src/calibre/gui2/init.py | 7 +- src/calibre/gui2/layout.py | 16 ---- src/calibre/gui2/main.py | 2 +- src/calibre/gui2/ui.py | 2 +- 6 files changed, 98 insertions(+), 68 deletions(-) diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index 5c1f2d1535..fc5f3bd9b8 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -5,8 +5,12 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' +from functools import partial + +from PyQt4.Qt import QToolButton, QAction, QIcon from calibre.customize import InterfaceActionBase +from calibre.gui2 import Dispatcher class InterfaceAction(InterfaceActionBase): @@ -17,12 +21,31 @@ class InterfaceAction(InterfaceActionBase): positions = frozenset([]) separators = frozenset([]) + popup_type = QToolButton.MenuPopup + + #: Of the form: (text, icon_path, tooltip, keyboard shortcut) + #: tooltip and keybard shortcut can be None + #: shortcut must be a translated string if not None + action_spec = ('text', 'icon', None, None) + def do_genesis(self, gui): self.gui = gui + self.Dispatcher = partial(Dispatcher, parent=gui) + self.create_action() self.genesis() - # Subclassable methods {{{ - def genesis(self): - raise NotImplementedError() - # }}} + def create_action(self): + text, icon, tooltip, shortcut = self.action_spec + action = QAction(QIcon(I(icon)), text, self) + text = tooltip if tooltip else text + action.setToolTip(text) + action.setStatusTip(text) + action.setWhatsThis(text) + action.setAutoRepeat(False) + if shortcut: + action.setShortcut(shortcut) + self.qaction = action + + def genesis(self): + pass diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index b7be89360f..8c6b627d5c 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -8,10 +8,10 @@ __docformat__ = 'restructuredtext en' import os from functools import partial -from PyQt4.Qt import QInputDialog, QPixmap +from PyQt4.Qt import QInputDialog, QPixmap, QMenu -from calibre.gui2 import error_dialog, Dispatcher, choose_files, \ +from calibre.gui2 import error_dialog, choose_files, \ choose_dir, warning_dialog, info_dialog from calibre.gui2.widgets import IMAGE_EXTENSIONS from calibre.ebooks import BOOK_EXTENSIONS @@ -21,20 +21,41 @@ from calibre.gui2.actions import InterfaceAction class AddAction(InterfaceAction): + name = 'Add Books' + action_spec = (_('Add books'), 'add_book.svg', None, _('A')) + positions = frozenset([ + ('toolbar', 'all', 0), + ]) + def genesis(self): - self._add_filesystem_book = Dispatcher(self.__add_filesystem_book, - parent=self.gui) + self._add_filesystem_book = self.Dispatcher(self.__add_filesystem_book) + self.add_menu = QMenu() + self.add_menu.addAction(_('Add books from a single directory'), + self.add_books) + self.add_menu.addAction(_('Add books from directories, including ' + 'sub-directories (One book per directory, assumes every ebook ' + 'file is the same book in a different format)'), + self.add_recursive_single) + self.add_menu.addAction(_('Add books from directories, including ' + 'sub directories (Multiple books per directory, assumes every ' + 'ebook file is a different book)'), self.add_recursive_multiple) + self.add_menu.addSeparator() + self.add_menu.addAction(_('Add Empty book. (Book entry with no ' + 'formats)'), self.add_empty) + self.add_menu.addAction(_('Add from ISBN'), self.add_from_isbn) + self.qaction.setMenu(self.add_menu) + self.qaction.triggered.connect(self.add_books) def add_recursive(self, single): - root = choose_dir(self, 'recursive book import root dir dialog', + root = choose_dir(self.gui, 'recursive book import root dir dialog', 'Select root folder') if not root: return from calibre.gui2.add import Adder - self._adder = Adder(self, - self.library_view.model().db, - Dispatcher(self._files_added), spare_server=self.spare_server) + self._adder = Adder(self.gui, + self.gui.library_view.model().db, + self.Dispatcher(self._files_added), spare_server=self.gui.spare_server) self._adder.add_recursive(root, single) def add_recursive_single(self, *args): @@ -56,13 +77,13 @@ class AddAction(InterfaceAction): Add an empty book item to the library. This does not import any formats from a book file. ''' - num, ok = QInputDialog.getInt(self, _('How many empty books?'), + num, ok = QInputDialog.getInt(self.gui, _('How many empty books?'), _('How many empty books should be added?'), 1, 1, 100) if ok: from calibre.ebooks.metadata import MetaInformation for x in xrange(num): - self.library_view.model().db.import_book(MetaInformation(None), []) - self.library_view.model().books_added(num) + self.gui.library_view.model().db.import_book(MetaInformation(None), []) + self.gui.library_view.model().books_added(num) def add_isbns(self, isbns): from calibre.ebooks.metadata import MetaInformation @@ -70,21 +91,21 @@ class AddAction(InterfaceAction): for x in isbns: mi = MetaInformation(None) mi.isbn = x - ids.add(self.library_view.model().db.import_book(mi, [])) - self.library_view.model().books_added(len(isbns)) - self.do_download_metadata(ids) + ids.add(self.gui.library_view.model().db.import_book(mi, [])) + self.gui.library_view.model().books_added(len(isbns)) + self.gui.do_download_metadata(ids) def files_dropped(self, paths): - to_device = self.stack.currentIndex() != 0 + to_device = self.gui.stack.currentIndex() != 0 self._add_books(paths, to_device) def files_dropped_on_book(self, event, paths): accept = False - if self.current_view() is not self.library_view: + if self.gui.current_view() is not self.gui.library_view: return - db = self.library_view.model().db - current_idx = self.library_view.currentIndex() + db = self.gui.library_view.model().db + current_idx = self.gui.library_view.currentIndex() if not current_idx.isValid(): return cid = db.id(current_idx.row()) for path in paths: @@ -102,7 +123,7 @@ class AddAction(InterfaceAction): accept = True if accept: event.accept() - self.library_view.model().current_changed(current_idx, current_idx) + self.gui.library_view.model().current_changed(current_idx, current_idx) def __add_filesystem_book(self, paths, allow_device=True): if isinstance(paths, basestring): @@ -111,10 +132,10 @@ class AddAction(InterfaceAction): os.R_OK)] if books: - to_device = allow_device and self.stack.currentIndex() != 0 + to_device = allow_device and self.gui.stack.currentIndex() != 0 self._add_books(books, to_device) if to_device: - self.status_bar.show_message(\ + self.gui.status_bar.show_message(\ _('Uploading books to device.'), 2000) @@ -123,7 +144,7 @@ class AddAction(InterfaceAction): def add_from_isbn(self, *args): from calibre.gui2.dialogs.add_from_isbn import AddFromISBN - d = AddFromISBN(self) + d = AddFromISBN(self.gui) if d.exec_() == d.Accepted: self.add_isbns(d.isbns) @@ -144,11 +165,11 @@ class AddAction(InterfaceAction): (_('Comics'), ['cbz', 'cbr', 'cbc']), (_('Archives'), ['zip', 'rar']), ] - to_device = self.stack.currentIndex() != 0 + to_device = self.gui.stack.currentIndex() != 0 if to_device: - filters = [(_('Supported books'), self.device_manager.device.FORMATS)] + filters = [(_('Supported books'), self.gui.device_manager.device.FORMATS)] - books = choose_files(self, 'add books dialog dir', 'Select books', + books = choose_files(self.gui, 'add books dialog dir', 'Select books', filters=filters) if not books: return @@ -156,32 +177,33 @@ class AddAction(InterfaceAction): def _add_books(self, paths, to_device, on_card=None): if on_card is None: - on_card = 'carda' if self.stack.currentIndex() == 2 else 'cardb' if self.stack.currentIndex() == 3 else None + on_card = 'carda' if self.gui.stack.currentIndex() == 2 else \ + 'cardb' if self.gui.stack.currentIndex() == 3 else None if not paths: return from calibre.gui2.add import Adder self.__adder_func = partial(self._files_added, on_card=on_card) - self._adder = Adder(self, - None if to_device else self.library_view.model().db, - Dispatcher(self.__adder_func), spare_server=self.spare_server) + self._adder = Adder(self.gui, + None if to_device else self.gui.library_view.model().db, + self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server) self._adder.add(paths) def _files_added(self, paths=[], names=[], infos=[], on_card=None): if paths: - self.upload_books(paths, + self.gui.upload_books(paths, list(map(ascii_filename, names)), infos, on_card=on_card) - self.status_bar.show_message( + self.gui.status_bar.show_message( _('Uploading books to device.'), 2000) if getattr(self._adder, 'number_of_books_added', 0) > 0: - self.library_view.model().books_added(self._adder.number_of_books_added) - if hasattr(self, 'db_images'): - self.db_images.reset() + self.gui.library_view.model().books_added(self._adder.number_of_books_added) + if hasattr(self.gui, 'db_images'): + self.gui.db_images.reset() if getattr(self._adder, 'merged_books', False): books = u'\n'.join([x if isinstance(x, unicode) else x.decode(preferred_encoding, 'replace') for x in self._adder.merged_books]) - info_dialog(self, _('Merged some books'), + info_dialog(self.gui, _('Merged some books'), _('Some duplicates were found and merged into the ' 'following existing books:'), det_msg=books, show=True) if getattr(self._adder, 'critical', None): @@ -191,7 +213,7 @@ class AddAction(InterfaceAction): name = name.decode(filesystem_encoding, 'replace') det_msg.append(name+'\n'+log) - warning_dialog(self, _('Failed to read metadata'), + warning_dialog(self.gui, _('Failed to read metadata'), _('Failed to read metadata from the following')+':', det_msg='\n\n'.join(det_msg), show=True) @@ -205,17 +227,17 @@ class AddAction(InterfaceAction): # set the in-library flags, and as a consequence send the library's # metadata for this book to the device. This sets the uuid to the # correct value. - self.set_books_in_library(booklists=[model.db], reset=True) + self.gui.set_books_in_library(booklists=[model.db], reset=True) model.reset() def add_books_from_device(self, view): rows = view.selectionModel().selectedRows() if not rows or len(rows) == 0: - d = error_dialog(self, _('Add to library'), _('No book selected')) + d = error_dialog(self.gui, _('Add to library'), _('No book selected')) d.exec_() return paths = [p for p in view._model.paths(rows) if p is not None] - ve = self.device_manager.device.VIRTUAL_BOOK_EXTENSIONS + ve = self.gui.device_manager.device.VIRTUAL_BOOK_EXTENSIONS def ext(x): ans = os.path.splitext(x)[1] ans = ans[1:] if len(ans) > 1 else ans @@ -223,21 +245,21 @@ class AddAction(InterfaceAction): remove = set([p for p in paths if ext(p) in ve]) if remove: paths = [p for p in paths if p not in remove] - info_dialog(self, _('Not Implemented'), + info_dialog(self.gui, _('Not Implemented'), _('The following books are virtual and cannot be added' ' to the calibre library:'), '\n'.join(remove), show=True) if not paths: return if not paths or len(paths) == 0: - d = error_dialog(self, _('Add to library'), _('No book files found')) + d = error_dialog(self.gui, _('Add to library'), _('No book files found')) d.exec_() return from calibre.gui2.add import Adder self.__adder_func = partial(self._add_from_device_adder, on_card=None, model=view._model) - self._adder = Adder(self, self.library_view.model().db, - Dispatcher(self.__adder_func), spare_server=self.spare_server) + self._adder = Adder(self.gui, self.gui.library_view.model().db, + self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server) self._adder.add(paths) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index a3ae5b77aa..7f8ad2d23c 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -63,7 +63,8 @@ class LibraryViewMixin(object): # {{{ add_to_library = None, edit_device_collections=None, similar_menu=similar_menu) - add_to_library = (_('Add books to library'), self.add_books_from_device) + add_to_library = (_('Add books to library'), + self.iactions['Add Books'].add_books_from_device) edit_device_collections = (_('Manage collections'), partial(self.edit_device_collections, oncard=None)) @@ -89,7 +90,7 @@ class LibraryViewMixin(object): # {{{ add_to_library=add_to_library, edit_device_collections=edit_device_collections) - self.library_view.files_dropped.connect(self.files_dropped, type=Qt.QueuedConnection) + self.library_view.files_dropped.connect(self.iactions['Add Books'].files_dropped, type=Qt.QueuedConnection) for func, args in [ ('connect_to_search_box', (self.search, self.search_done)), @@ -305,7 +306,7 @@ class LayoutMixin(object): # {{{ def finalize_layout(self): self.status_bar.initialize(self.system_tray_icon) self.book_details.show_book_info.connect(self.show_book_info) - self.book_details.files_dropped.connect(self.files_dropped_on_book) + self.book_details.files_dropped.connect(self.iactions['Add Books'].files_dropped_on_book) self.book_details.open_containing_folder.connect(self.view_folder_for_id) self.book_details.view_specific_format.connect(self.view_format_by_id) diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index 8a919c59f5..05763db658 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -528,22 +528,6 @@ class MainWindowMixin(object): md.addSeparator() md.addAction(self.action_merge) - self.add_menu = QMenu() - self.add_menu.addAction(_('Add books from a single directory'), - self.add_books) - self.add_menu.addAction(_('Add books from directories, including ' - 'sub-directories (One book per directory, assumes every ebook ' - 'file is the same book in a different format)'), - self.add_recursive_single) - self.add_menu.addAction(_('Add books from directories, including ' - 'sub directories (Multiple books per directory, assumes every ' - 'ebook file is a different book)'), self.add_recursive_multiple) - self.add_menu.addSeparator() - self.add_menu.addAction(_('Add Empty book. (Book entry with no ' - 'formats)'), self.add_empty) - self.add_menu.addAction(_('Add from ISBN'), self.add_from_isbn) - self.action_add.setMenu(self.add_menu) - self.action_add.triggered.connect(self.add_books) self.action_del.triggered.connect(self.delete_books) self.action_edit.triggered.connect(self.edit_metadata) self.action_merge.triggered.connect(self.merge_books) diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index ca896fc014..f9d7d80b24 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -155,7 +155,7 @@ class GuiRunner(QObject): main.initialize(self.library_path, self.db, self.listener, self.actions) if DEBUG: prints('Started up in', time.time() - self.startup_time) - add_filesystem_book = partial(main.add_filesystem_book, allow_device=False) + add_filesystem_book = partial(main.iactions['Add Books'].add_filesystem_book, allow_device=False) sys.excepthook = main.unhandled_exception if len(self.args) > 1: p = os.path.abspath(self.args[1]) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 0b1091f848..cca6a378d1 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -329,7 +329,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ if len(argv) > 1: path = os.path.abspath(argv[1]) if os.access(path, os.R_OK): - self.add_filesystem_book(path) + self.iactions['Add Books'].add_filesystem_book(path) self.setWindowState(self.windowState() & \ ~Qt.WindowMinimized|Qt.WindowActive) self.show_windows()