diff --git a/src/calibre/gui2/actions/show_book_details.py b/src/calibre/gui2/actions/show_book_details.py index 164feb7958..7469bc5572 100644 --- a/src/calibre/gui2/actions/show_book_details.py +++ b/src/calibre/gui2/actions/show_book_details.py @@ -8,69 +8,88 @@ __docformat__ = 'restructuredtext en' from qt.core import Qt, sip from calibre.gui2.actions import InterfaceAction -from calibre.gui2.dialogs.book_info import BookInfo +from calibre.gui2.dialogs.book_info import BookInfo, DialogNumbers from calibre.gui2 import error_dialog class ShowBookDetailsAction(InterfaceAction): name = 'Show Book Details' - action_spec = (_('Show Book details'), 'dialog_information.png', + action_spec = (_('Book details'), 'dialog_information.png', _('Show the detailed metadata for the current book in a separate window'), _('I')) + action_shortcut_name = _('Show Book details in a separate window') dont_add_to = frozenset(('context-menu-device',)) action_type = 'current' + action_add_menu = True + action_menu_clone_qaction = _('Show Book details in a separate window') def genesis(self): + self.dialogs = [None, None, None] + m = self.qaction.menu() + self.show_info_locked = l = self.create_menu_action(m, + 'show_locked_details', _('Show Book details in a separate locked window'), + icon='drm-locked.png', shortcut=None) + l.triggered.connect(self.open_locked_window) + l = self.create_menu_action(m, + 'close_all_details', _('Close all book details windows'), icon='close.png', shortcut=None) + l.triggered.connect(self.close_all_windows) self.qaction.triggered.connect(self.show_book_info) - self.dialogs = [None, ] def show_book_info(self, *args, **kwargs): library_path = kwargs.get('library_path', None) book_id = kwargs.get('book_id', None) library_id = kwargs.get('library_id', None) - query = kwargs.get('query', None) + locked = kwargs.get('locked', False) index = self.gui.library_view.currentIndex() if self.gui.current_view() is not self.gui.library_view and not library_path: error_dialog(self.gui, _('No detailed info available'), _('No detailed information is available for books ' 'on the device.')).exec() return - if library_path or index.isValid(): - # Window #0 is slaved to changes in the book list. As such - # it must not be used for details from other libraries. - for dn,v in enumerate(self.dialogs): - if dn == 0 and library_path: - continue - if v is None: - break - else: - self.dialogs.append(None) - dn += 1 - - try: - d = BookInfo(self.gui, self.gui.library_view, index, - self.gui.book_details.handle_click, dialog_number=dn, - library_id=library_id, library_path=library_path, book_id=book_id, query=query) - except ValueError as e: - error_dialog(self.gui, _('Book not found'), str(e)).exec() + if library_path: + dn = DialogNumbers.DetailsLink + else: + if not index.isValid(): return + dn = DialogNumbers.Locked if locked else DialogNumbers.Slaved + if self.dialogs[dn] is not None: + if dn == DialogNumbers.Slaved: + # This is the slaved window. It will update automatically + return + else: + # Replace the other windows. There is a signals race condition + # between closing the existing window and opening the new one, + # so do all the work here + d = self.dialogs[dn] + d.closed.disconnect(self.closed) + d.done(0) + self.dialogs[dn] = None + try: + d = BookInfo(self.gui, self.gui.library_view, index, + self.gui.book_details.handle_click, dialog_number=dn, + library_id=library_id, library_path=library_path, book_id=book_id) + except ValueError as e: + error_dialog(self.gui, _('Book not found'), str(e)).exec() + return - d.open_cover_with.connect(self.gui.bd_open_cover_with, type=Qt.ConnectionType.QueuedConnection) - self.dialogs[dn] = d - d.closed.connect(self.closed, type=Qt.ConnectionType.QueuedConnection) - d.show() + d.open_cover_with.connect(self.gui.bd_open_cover_with, type=Qt.ConnectionType.QueuedConnection) + self.dialogs[dn] = d + d.closed.connect(self.closed, type=Qt.ConnectionType.QueuedConnection) + d.show() + + def open_locked_window(self): + self.show_book_info(locked=True) def shutting_down(self): - for d in self.dialogs: - if d: - d.done(0) + self.close_all_windows() + + def close_all_windows(self): + for dialog in [d for d in self.dialogs if d is not None]: + dialog.done(0) def library_about_to_change(self, *args): - for i,d in enumerate(self.dialogs): - if i == 0: - continue - if d: - d.done(0) + for dialog in [d for d in self.dialogs[1:] if d is not None]: + dialog.done(0) def closed(self, d): try: diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index 33aac40dd7..0f3443e702 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -541,8 +541,7 @@ def details_context_menu_event(view, ev, book_info, add_popup_action=False, edit menu.addSeparator() from calibre.gui2.ui import get_gui if add_popup_action: - ema = get_gui().iactions['Show Book Details'].menuless_qaction - menu.addAction(_('Open the Book details window') + '\t' + ema.shortcut().toString(QKeySequence.SequenceFormat.NativeText), book_info.show_book_info) + menu.addMenu(get_gui().iactions['Show Book Details'].qaction.menu()) else: ema = get_gui().iactions['Edit Metadata'].menuless_qaction menu.addAction(_('Open the Edit metadata window') + '\t' + ema.shortcut().toString(QKeySequence.SequenceFormat.NativeText), edit_metadata) diff --git a/src/calibre/gui2/dialogs/book_info.py b/src/calibre/gui2/dialogs/book_info.py index bf34003549..e9cebb86fd 100644 --- a/src/calibre/gui2/dialogs/book_info.py +++ b/src/calibre/gui2/dialogs/book_info.py @@ -2,6 +2,7 @@ # License: GPLv3 Copyright: 2008, Kovid Goyal +from enum import IntEnum import textwrap from qt.core import ( @@ -130,14 +131,20 @@ class Details(HTMLDisplay): details_context_menu_event(self, ev, self.book_info, edit_metadata=self.edit_metadata) +class DialogNumbers(IntEnum): + Slaved = 0 + Locked = 1 + DetailsLink = 2 + + class BookInfo(QDialog): closed = pyqtSignal(object) open_cover_with = pyqtSignal(object, object) def __init__(self, parent, view, row, link_delegate, dialog_number=None, - library_id=None, library_path=None, book_id=None, query=None): - QDialog.__init__(self, None, flags=Qt.WindowType.Window) + library_id=None, library_path=None, book_id=None): + QDialog.__init__(self, parent) self.dialog_number = dialog_number self.library_id = library_id self.marked = None @@ -179,7 +186,7 @@ class BookInfo(QDialog): hl.setContentsMargins(0, 0, 0, 0) l2.addLayout(hl, l2.rowCount(), 0, 1, -1) hl.addWidget(self.fit_cover), hl.addStretch() - if self.dialog_number == 0: + if self.dialog_number == DialogNumbers.Slaved: self.previous_button = QPushButton(QIcon.ic('previous.png'), _('&Previous'), self) self.previous_button.clicked.connect(self.previous) l2.addWidget(self.previous_button, l2.rowCount(), 0) @@ -201,11 +208,6 @@ class BookInfo(QDialog): if library_path is not None: self.view = None db = get_gui().library_broker.get_library(library_path) - if book_id is None: - ids = db.new_api.search(query) - if len(ids) == 0: - raise ValueError(_('Query "{}" found no books').format(query)) - book_id = sorted(ids)[0] if not db.new_api.has_id(book_id): raise ValueError(_("Book {} doesn't exist").format(book_id)) mi = db.new_api.get_metadata(book_id, get_cover=False) @@ -219,7 +221,7 @@ class BookInfo(QDialog): self.refresh(row, mi) else: self.view = view - if dialog_number == 0: + if dialog_number == DialogNumbers.Slaved: self.slave_connected = True self.view.model().new_bookdisplay_data.connect(self.slave) self.refresh(row) @@ -246,9 +248,9 @@ class BookInfo(QDialog): pass def geometry_string(self, txt): - if self.dialog_number is None or self.dialog_number == 0: + if self.dialog_number is None or self.dialog_number == DialogNumbers.Slaved: return txt - return txt + '_' + str(self.dialog_number) + return txt + '_' + str(int(self.dialog_number)) def sizeHint(self): try: @@ -379,7 +381,7 @@ class BookInfo(QDialog): # Indicates books was deleted from library, or row numbers have # changed return - if self.dialog_number == 0: + if self.dialog_number == DialogNumbers.Slaved: self.previous_button.setEnabled(False if row == 0 else True) self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True) self.setWindowTitle(mi.title + ' ' + _('(the current book)'))