From 2772908a3ce1ca7636eaeeaadaaa2a84a9f8a0ad Mon Sep 17 00:00:00 2001 From: John Peterson Date: Mon, 5 Nov 2012 02:08:31 +0000 Subject: [PATCH 1/3] Fixes for viewer etc. Fix: Remember maximized state when toggle fullscreen. New: Adding saved state: fullscreen state. New: Adding context menu item: search online, back (Backspace)/forward, toc, font size, fullscreen, exit (Esc). Fix: Hiding non-selection context menu items when showing selection context menu items. Fix: Hiding selection context menu items when showing image context menu items. Fix: Return in book list would not open viewer for selected items. Fix: The top book list row was not selected on program start, as intended. Fix: Reset quick search would unselect the book list selection even when not in a search. Fix: Reset quick search when in a search would not return selection to a book list row. Fix: Don't open empty viewer if no book is selected. Change: Removing fullscreen message because it's not useful for many users. New: Applying auto convert option for manual add too. New: Making the post import phase accessible to plugins (for metadata creation or conversion). New: Adding viewer option to not show the cover. --- src/calibre/customize/__init__.py | 11 ++ src/calibre/customize/ui.py | 22 ++++ src/calibre/ebooks/oeb/iterator/book.py | 27 +++-- src/calibre/gui2/actions/view.py | 1 - src/calibre/gui2/add.py | 6 + src/calibre/gui2/init.py | 4 +- src/calibre/gui2/library/views.py | 9 +- src/calibre/gui2/search_box.py | 6 +- src/calibre/gui2/viewer/config.py | 4 + src/calibre/gui2/viewer/config.ui | 7 ++ src/calibre/gui2/viewer/documentview.py | 143 ++++++++++++++++++++++-- src/calibre/gui2/viewer/main.py | 115 +++++++------------ src/calibre/library/database2.py | 3 +- 13 files changed, 258 insertions(+), 100 deletions(-) diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index 2570efebe1..1f57305945 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -308,6 +308,10 @@ class FileTypePlugin(Plugin): # {{{ #: to the database on_import = False + #: If True, this plugin is run after books are added + #: to the database + on_postimport = False + #: If True, this plugin is run just before a conversion on_preprocess = False @@ -336,7 +340,14 @@ class FileTypePlugin(Plugin): # {{{ ''' # Default implementation does nothing return path_to_ebook + + def postimport(self, id): + ''' + Run post import. + :param id: Library id of the added book. + ''' + # }}} class MetadataReaderPlugin(Plugin): # {{{ diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 2799ed747a..15d448161e 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -104,14 +104,17 @@ def is_disabled(plugin): # File type plugins {{{ _on_import = {} +_on_postimport = {} _on_preprocess = {} _on_postprocess = {} def reread_filetype_plugins(): global _on_import + global _on_postimport global _on_preprocess global _on_postprocess _on_import = {} + _on_postimport = {} _on_preprocess = {} _on_postprocess = {} @@ -122,6 +125,10 @@ def reread_filetype_plugins(): if not _on_import.has_key(ft): _on_import[ft] = [] _on_import[ft].append(plugin) + if plugin.on_postimport: + if not _on_postimport.has_key(ft): + _on_postimport[ft] = [] + _on_postimport[ft].append(plugin) if plugin.on_preprocess: if not _on_preprocess.has_key(ft): _on_preprocess[ft] = [] @@ -163,6 +170,21 @@ run_plugins_on_preprocess = functools.partial(_run_filetype_plugins, occasion='preprocess') run_plugins_on_postprocess = functools.partial(_run_filetype_plugins, occasion='postprocess') + +def postimport_plugins(id, format): + customization = config['plugin_customization'] + format = format.lower() + for plugin in _on_postimport.get(format, []): + if is_disabled(plugin): + continue + plugin.site_customization = customization.get(plugin.name, '') + with plugin: + try: + plugin.postimport(id) + except: + print 'Running file type plugin %s failed with traceback:'%plugin.name + traceback.print_exc() + # }}} # Plugin customization {{{ diff --git a/src/calibre/ebooks/oeb/iterator/book.py b/src/calibre/ebooks/oeb/iterator/book.py index 992d5304c6..65fc48cad7 100644 --- a/src/calibre/ebooks/oeb/iterator/book.py +++ b/src/calibre/ebooks/oeb/iterator/book.py @@ -49,8 +49,9 @@ class EbookIterator(BookmarksMixin): CHARACTERS_PER_PAGE = 1000 - def __init__(self, pathtoebook, log=None): + def __init__(self, pathtoebook, exclude_cover=False, log=None): self.log = log or default_log + self.exclude_cover = exclude_cover pathtoebook = pathtoebook.strip() self.pathtoebook = os.path.abspath(pathtoebook) self.config = DynamicConfig(name='iterator') @@ -139,16 +140,20 @@ class EbookIterator(BookmarksMixin): self.log.warn('Missing spine item:', repr(spath)) cover = self.opf.cover - if cover and self.ebook_ext in {'lit', 'mobi', 'prc', 'opf', 'fb2', - 'azw', 'azw3'}: - cfile = os.path.join(self.base, 'calibre_iterator_cover.html') - rcpath = os.path.relpath(cover, self.base).replace(os.sep, '/') - chtml = (TITLEPAGE%prepare_string_for_xml(rcpath, True)).encode('utf-8') - with open(cfile, 'wb') as f: - f.write(chtml) - self.spine[0:0] = [Spiny(cfile, - mime_type='application/xhtml+xml')] - self.delete_on_exit.append(cfile) + if cover: + if self.ebook_ext in {'lit', 'mobi', 'prc', 'opf', 'fb2', + 'azw', 'azw3'}: + if not self.exclude_cover: + cfile = os.path.join(self.base, 'calibre_iterator_cover.html') + rcpath = os.path.relpath(cover, self.base).replace(os.sep, '/') + chtml = (TITLEPAGE%prepare_string_for_xml(rcpath, True)).encode('utf-8') + with open(cfile, 'wb') as f: + f.write(chtml) + self.spine[0:0] = [Spiny(cfile, + mime_type='application/xhtml+xml')] + self.delete_on_exit.append(cfile) + elif self.exclude_cover: + self.spine.remove(self.spine[0]) if self.opf.path_to_html_toc is not None and \ self.opf.path_to_html_toc not in self.spine: diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py index 5a7a991607..8672338b6a 100644 --- a/src/calibre/gui2/actions/view.py +++ b/src/calibre/gui2/actions/view.py @@ -267,7 +267,6 @@ class ViewAction(InterfaceAction): def _view_books(self, rows): if not rows or len(rows) == 0: - self._launch_viewer() return if not self._view_check(len(rows)): diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py index 234c72abf4..4336148816 100644 --- a/src/calibre/gui2/add.py +++ b/src/calibre/gui2/add.py @@ -99,6 +99,7 @@ class DBAdder(QObject): # {{{ def __init__(self, parent, db, ids, nmap): QObject.__init__(self, parent) + self.parent = parent self.db, self.ids, self.nmap = db, dict(**ids), dict(**nmap) self.critical = {} self.number_of_books_added = 0 @@ -232,6 +233,11 @@ class DBAdder(QObject): # {{{ with open(path, 'rb') as f: self.db.add_format(id, fmt, f, index_is_id=True, notify=False, replace=replace) + if gprefs['auto_add_auto_convert']: + of = prefs['output_format'] + if not of == fmt.lower(): + gui = self.parent._parent + gui.iactions['Convert Books'].auto_convert([id], None, of) # }}} diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 338a558f29..adcd0fc6cf 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import functools from PyQt4.Qt import Qt, QStackedWidget, QMenu, \ - QSize, QSizePolicy, QStatusBar, QLabel, QFont + QSize, QSizePolicy, QStatusBar, QTimer, QLabel, QFont from calibre.utils.config import prefs from calibre.constants import (isosx, __appname__, preferred_encoding, @@ -274,7 +274,7 @@ class LayoutMixin(object): # {{{ m = self.library_view.model() if m.rowCount(None) > 0: - self.library_view.set_current_row(0) + QTimer.singleShot(1, self.library_view.set_current_row) m.current_changed(self.library_view.currentIndex(), self.library_view.currentIndex()) self.library_view.setFocus(Qt.OtherFocusReason) diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index e263e2c489..85636104cb 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -754,6 +754,13 @@ class BooksView(QTableView): # {{{ # }}} + def keyPressEvent(self, event): + if event.key() == Qt.Key_Return: + selected_rows = [r.row() for r in self.selectionModel().selectedRows()] + self.display_parent.iactions['View']._view_books(selected_rows) + else: + return super(BooksView, self).keyPressEvent(event) + @property def column_map(self): return self._model.column_map @@ -777,7 +784,7 @@ class BooksView(QTableView): # {{{ self.scrollTo(self.model().index(row, i), self.PositionAtCenter) break - def set_current_row(self, row, select=True): + def set_current_row(self, row=0, select=True): if row > -1 and row < self.model().rowCount(QModelIndex()): h = self.horizontalHeader() logical_indices = list(range(h.count())) diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index 54a80571e6..50ead17d1d 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -128,7 +128,7 @@ class SearchBox2(QComboBox): # {{{ def clear(self, emit_search=True): self.normalize_state() self.setEditText('') - if emit_search: + if self.in_a_search() and emit_search: self.search.emit('') self._in_a_search = False self.cleared.emit() @@ -159,7 +159,6 @@ class SearchBox2(QComboBox): # {{{ self.normalize_state() if self._in_a_search: self.changed.emit() - self._in_a_search = False if event.key() in (Qt.Key_Return, Qt.Key_Enter): self.do_search() self.focus_to_library.emit() @@ -424,6 +423,7 @@ class SearchBoxMixin(object): # {{{ self.tags_view.clear() self.saved_search.clear() self.set_number_of_books_shown() + self.focus_to_library() def search_box_changed(self): self.saved_search.clear() @@ -440,6 +440,8 @@ class SearchBoxMixin(object): # {{{ def focus_to_library(self): self.current_view().setFocus(Qt.OtherFocusReason) + if not self.current_view().get_selected_ids(): + self.current_view().set_current_row() # }}} diff --git a/src/calibre/gui2/viewer/config.py b/src/calibre/gui2/viewer/config.py index 8643ce63d0..e3726c1ecb 100644 --- a/src/calibre/gui2/viewer/config.py +++ b/src/calibre/gui2/viewer/config.py @@ -41,6 +41,8 @@ def config(defaults=None): help=_('Default language for hyphenation rules')) c.add_opt('remember_current_page', default=True, help=_('Save the current position in the document, when quitting')) + c.add_opt('dont_show_cover', default=False, + help=_('Don\'t show the cover.')) c.add_opt('wheel_flips_pages', default=False, help=_('Have the mouse wheel turn pages')) c.add_opt('line_scrolling_stops_on_pagebreaks', default=False, @@ -177,6 +179,7 @@ class ConfigDialog(QDialog, Ui_Dialog): def load_options(self, opts): self.opt_remember_window_size.setChecked(opts.remember_window_size) self.opt_remember_current_page.setChecked(opts.remember_current_page) + self.opt_dont_show_cover.setChecked(opts.dont_show_cover) self.opt_wheel_flips_pages.setChecked(opts.wheel_flips_pages) self.opt_page_flip_duration.setValue(opts.page_flip_duration) fms = opts.font_magnification_step @@ -267,6 +270,7 @@ class ConfigDialog(QDialog, Ui_Dialog): c.set('max_fs_width', int(self.max_fs_width.value())) c.set('hyphenate', self.hyphenate.isChecked()) c.set('remember_current_page', self.opt_remember_current_page.isChecked()) + c.set('dont_show_cover', self.opt_dont_show_cover.isChecked()) c.set('wheel_flips_pages', self.opt_wheel_flips_pages.isChecked()) c.set('page_flip_duration', self.opt_page_flip_duration.value()) c.set('font_magnification_step', diff --git a/src/calibre/gui2/viewer/config.ui b/src/calibre/gui2/viewer/config.ui index f91462e5b2..abc5391ebf 100644 --- a/src/calibre/gui2/viewer/config.ui +++ b/src/calibre/gui2/viewer/config.ui @@ -605,6 +605,13 @@ QToolBox::tab:hover { + + + + Don't show the c&over (needs restart) + + + diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 81ee82f2b6..c1927e1907 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -16,6 +16,7 @@ from PyQt4.QtWebKit import QWebPage, QWebView, QWebSettings from calibre.gui2.viewer.flip import SlideFlip from calibre.gui2.shortcuts import Shortcuts +from calibre.gui2 import open_url from calibre import prints from calibre.customize.ui import all_viewer_plugins from calibre.gui2.viewer.keys import SHORTCUTS @@ -478,7 +479,12 @@ class DocumentView(QWebView): # {{{ d = self.document self.unimplemented_actions = list(map(self.pageAction, [d.DownloadImageToDisk, d.OpenLinkInNewWindow, d.DownloadLinkToDisk, - d.OpenImageInNewWindow, d.OpenLink, d.Reload])) + d.OpenImageInNewWindow, d.OpenLink, d.Reload, d.InspectElement, d.Copy])) + + self.search_online_action = QAction(QIcon(I('search.png')), _(''), self) + self.search_online_action.setShortcut(Qt.CTRL+Qt.Key_E) + self.search_online_action.triggered.connect(self.search_online) + self.addAction(self.search_online_action) self.dictionary_action = QAction(QIcon(I('dictionary.png')), _('&Lookup in dictionary'), self) self.dictionary_action.setShortcut(Qt.CTRL+Qt.Key_L) @@ -523,6 +529,44 @@ class DocumentView(QWebView): # {{{ self.goto_location_action.setMenu(self.goto_location_menu) self.grabGesture(Qt.SwipeGesture) + self.toc_action = QAction(_('Table of contents'), self) + self.toc_action.setCheckable(True) + self.toc_action.triggered.connect(self.toggle_toc) + + self.back_action = QAction(_('&Back'), self) + self.back_action.triggered.connect(self.back) + self.back_action.setShortcut(Qt.Key_Backspace) + self.addAction(self.back_action) + self.forward_action = QAction(_('&Forward'), self) + self.forward_action.triggered.connect(self.forward) + + self.magnify_fonts_action = QAction(_('Larger font'), self) + self.magnify_fonts_action.triggered.connect(self.font_size_larger) + self.restore_fonts_action = QAction(_('Normal font size'), self) + self.restore_fonts_action.setCheckable(True) + self.restore_fonts_action.triggered.connect(self.font_size_restore) + self.shrink_fonts_action = QAction(_('Smaller font'), self) + self.shrink_fonts_action.triggered.connect(self.font_size_smaller) + + self.fullscreen_action = QAction(_('Full screen'), self) + self.fullscreen_action.triggered.connect(self.toggle_fullscreen) + self.fullscreen_action.setCheckable(True) + self.fullscreen_action.setShortcut(Qt.Key_F11) + self.addAction(self.fullscreen_action) + + self.quit_action = QAction(_('Exit'), self) + self.quit_action.triggered.connect(self.quit_toggle) + self.quit_action.setShortcut(Qt.Key_Escape) + self.addAction(self.quit_action) + + def back(self, *args): + if self.manager is not None: + self.manager.back() + + def forward(self, *args): + if self.manager is not None: + self.manager.forward() + def goto_next_section(self, *args): if self.manager is not None: self.manager.goto_next_section() @@ -539,6 +583,30 @@ class DocumentView(QWebView): # {{{ if self.manager is not None: self.manager.goto_end() + def font_size_larger(self, *args): + if self.manager is not None: + self.manager.font_size_larger() + + def font_size_smaller(self, *args): + if self.manager is not None: + self.manager.font_size_smaller() + + def font_size_restore(self, *args): + if self.manager is not None: + self.manager.font_size_restore() + + def toggle_toc(self, *args): + if self.manager is not None: + self.manager.toggle_toc() + + def toggle_fullscreen(self, *args): + if self.manager is not None: + self.manager.toggle_fullscreen() + + def quit_toggle(self, *args): + if self.manager is not None: + self.manager.quit() + @property def copy_action(self): return self.pageAction(self.document.Copy) @@ -579,6 +647,17 @@ class DocumentView(QWebView): # {{{ if self.manager is not None: self.manager.selection_changed(unicode(self.document.selectedText())) + def _selectedText(self): + t = self.selectedText().trimmed() + if not t: + return "" + if t.size() > 40: + t.truncate(40) + t = t + "..." + t = t.replace('&', '&&') + t = "S&earch Google for '" + t + "'" + return unicode(t) + def contextMenuEvent(self, ev): mf = self.document.mainFrame() r = mf.hitTestContent(ev.pos()) @@ -588,17 +667,52 @@ class DocumentView(QWebView): # {{{ menu = self.document.createStandardContextMenu() for action in self.unimplemented_actions: menu.removeAction(action) - text = unicode(self.selectedText()) - if text: - menu.insertAction(list(menu.actions())[0], self.dictionary_action) - menu.insertAction(list(menu.actions())[0], self.search_action) + if not img.isNull(): menu.addAction(self.view_image_action) - menu.addSeparator() - menu.addAction(self.goto_location_action) - if self.document.in_fullscreen_mode and self.manager is not None: + + text = self._selectedText() + if text and img.isNull(): + copyAction = self.pageAction(self.document.Copy) + copyAction.setText("&Copy") + menu.addAction(copyAction) + self.search_online_action.setText(text) + menu.addAction(self.search_online_action) + menu.addAction(self.dictionary_action) + menu.addAction(self.search_action) + + if not text and img.isNull(): menu.addSeparator() - menu.addAction(self.manager.toggle_toolbar_action) + menu.addAction(self.back_action) + menu.addAction(self.forward_action) + menu.addAction(self.goto_location_action) + + menu.addSeparator() + self.toc_action.setChecked(self.manager.toc.isVisible()) + menu.addAction(self.toc_action) + + menu.addSeparator() + menu.addAction(self.magnify_fonts_action) + self.restore_fonts_action.setChecked(self.multiplier == 1) + menu.addAction(self.restore_fonts_action) + menu.addAction(self.shrink_fonts_action) + + menu.addSeparator() + inspectAction = self.pageAction(self.document.InspectElement) + inspectAction.setText("I&nspect element") + menu.addAction(inspectAction) + + if not text and img.isNull(): + menu.addSeparator() + if self.document.in_fullscreen_mode and self.manager is not None: + self.manager.toggle_toolbar_action.setChecked(self.manager.tool_bar.isVisible()) + menu.addAction(self.manager.toggle_toolbar_action) + self.fullscreen_action.setChecked(self.manager.isFullScreen()) + menu.addAction(self.fullscreen_action) + + menu.addSeparator() + menu.addAction(self.quit_action) + menu.exec_(ev.globalPos()) def lookup(self, *args): @@ -613,6 +727,12 @@ class DocumentView(QWebView): # {{{ if t: self.manager.search.set_search_string(t) + def search_online(self): + t = unicode(self.selectedText()).strip() + if t: + url = 'https://www.google.com/search?q=' + QUrl().toPercentEncoding(t) + open_url(QUrl.fromEncoded(url)) + def set_manager(self, manager): self.manager = manager self.scrollbar = manager.horizontal_scrollbar @@ -990,6 +1110,11 @@ class DocumentView(QWebView): # {{{ self.multiplier -= amount return self.document.scroll_fraction + def restore_font_size(self): + with self.document.page_position: + self.multiplier = 1 + return self.document.scroll_fraction + def changeEvent(self, event): if event.type() == event.EnabledChange: self.update() diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index 7b624f170a..c11fda7437 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -230,7 +230,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.action_reference_mode.setCheckable(True) self.action_reference_mode.triggered[bool].connect(self.view.reference_mode) self.action_metadata.triggered[bool].connect(self.metadata.setVisible) - self.action_table_of_contents.toggled[bool].connect(self.set_toc_visible) + self.action_table_of_contents.toggled[bool].connect(self.toggle_toc) self.action_copy.triggered[bool].connect(self.copy) self.action_font_size_larger.triggered.connect(self.font_size_larger) self.action_font_size_smaller.triggered.connect(self.font_size_smaller) @@ -240,7 +240,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.action_find_next.triggered.connect(self.find_next) self.action_find_previous.triggered.connect(self.find_previous) self.action_full_screen.triggered[bool].connect(self.toggle_fullscreen) - self.action_full_screen.setShortcuts([Qt.Key_F11, Qt.CTRL+Qt.SHIFT+Qt.Key_F]) + self.action_full_screen.setShortcut(Qt.CTRL+Qt.SHIFT+Qt.Key_F) self.action_full_screen.setToolTip(_('Toggle full screen (%s)') % _(' or ').join([unicode(x.toString(x.NativeText)) for x in self.action_full_screen.shortcuts()])) @@ -274,35 +274,11 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.tool_bar2.setContextMenuPolicy(Qt.PreventContextMenu) self.tool_bar.widgetForAction(self.action_bookmark).setPopupMode(QToolButton.MenuButtonPopup) self.action_full_screen.setCheckable(True) - self.full_screen_label = QLabel(''' -
-

%s

-

%s

-

%s

-

%s

-
- '''%(_('Full screen mode'), - _('Right click to show controls'), - _('Tap in the left or right page margin to turn pages'), - _('Press Esc to quit')), - self) - self.full_screen_label.setVisible(False) - self.full_screen_label.setStyleSheet(''' - QLabel { - text-align: center; - background-color: white; - color: black; - border-width: 1px; - border-style: solid; - border-radius: 20px; - } - ''') self.window_mode_changed = None self.toggle_toolbar_action = QAction(_('Show/hide controls'), self) + self.toggle_toolbar_action.setCheckable(True) self.toggle_toolbar_action.triggered.connect(self.toggle_toolbars) self.addAction(self.toggle_toolbar_action) - self.full_screen_label_anim = QPropertyAnimation( - self.full_screen_label, 'size') self.clock_label = QLabel('99:99', self) self.clock_label.setVisible(False) self.clock_label.setFocusPolicy(Qt.NoFocus) @@ -324,11 +300,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.pos_label.setFocusPolicy(Qt.NoFocus) self.clock_timer = QTimer(self) self.clock_timer.timeout.connect(self.update_clock) - self.esc_full_screen_action = a = QAction(self) - self.addAction(a) - a.setShortcut(Qt.Key_Escape) - a.setEnabled(False) - a.triggered.connect(self.action_full_screen.trigger) self.print_menu = QMenu() self.print_menu.addAction(QIcon(I('print-preview.png')), _('Print Preview')) @@ -374,8 +345,13 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.pending_restore = True self.load_path(self.view.last_loaded_path) - def set_toc_visible(self, yes): - self.toc.setVisible(yes) + def toggle_toc(self): + if self.toc.isVisible(): + self.toc.setVisible(False) + self.action_table_of_contents.setChecked(False) + else: + self.toc.setVisible(True) + self.action_table_of_contents.setChecked(True) def clear_recent_history(self, *args): vprefs.set('viewer_open_history', []) @@ -397,9 +373,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer): count += 1 def shutdown(self): - if self.isFullScreen(): - self.action_full_screen.trigger() - return False self.save_state() return True @@ -421,7 +394,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer): def save_state(self): state = bytearray(self.saveState(self.STATE_VERSION)) vprefs['viewer_toolbar_state'] = state - vprefs.set('viewer_window_geometry', bytearray(self.saveGeometry())) + if not self.isFullScreen(): + vprefs.set('viewer_window_geometry', bytearray(self.saveGeometry())) if self.current_book_has_toc: vprefs.set('viewer_toc_isvisible', bool(self.toc.isVisible())) if self.toc.isVisible(): @@ -429,6 +403,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): bytearray(self.splitter.saveState())) vprefs['multiplier'] = self.view.multiplier vprefs['in_paged_mode'] = not self.action_toggle_paged_mode.isChecked() + vprefs['fullscreen'] = self.isFullScreen() def restore_state(self): state = vprefs.get('viewer_toolbar_state', None) @@ -449,6 +424,9 @@ class EbookViewer(MainWindow, Ui_EbookViewer): True)) self.toggle_paged_mode(self.action_toggle_paged_mode.isChecked(), at_start=True) + fullscreen = vprefs.get('fullscreen', None) + if fullscreen: + self.showFullScreen() def lookup(self, word): self.dictionary_view.setHtml('

'+ \ @@ -468,7 +446,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer): from calibre.gui2.viewer.documentview import config c = config().parse() return c.remember_current_page - + + def get_dont_show_cover_opt(self): + from calibre.gui2.viewer.documentview import config + c = config().parse() + return c.dont_show_cover + def print_book(self): p = Printing(self.iterator, self) p.start_print() @@ -477,7 +460,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): p = Printing(self.iterator, self) p.start_preview() - def toggle_fullscreen(self, x): + def toggle_fullscreen(self): if self.isFullScreen(): self.showNormal() else: @@ -485,9 +468,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer): def showFullScreen(self): self.view.document.page_position.save() + self.view.document.switch_to_fullscreen_mode() self.window_mode_changed = 'fullscreen' + self.was_maximized = super(EbookViewer, self).isMaximized() self.tool_bar.setVisible(False) self.tool_bar2.setVisible(False) + self.action_full_screen.setChecked(True) if not self.view.document.fullscreen_scrollbar: self.vertical_scrollbar.setVisible(False) self.frame.layout().setSpacing(0) @@ -500,26 +486,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer): super(EbookViewer, self).showFullScreen() - def show_full_screen_label(self): - f = self.full_screen_label - self.esc_full_screen_action.setEnabled(True) - f.setVisible(True) - height = 200 - width = int(0.7*self.view.width()) - f.resize(width, height) - f.move((self.view.width() - width)//2, (self.view.height()-height)//2) - a = self.full_screen_label_anim - a.setDuration(500) - a.setStartValue(QSize(width, 0)) - a.setEndValue(QSize(width, height)) - a.start() - QTimer.singleShot(3500, self.full_screen_label.hide) - self.view.document.switch_to_fullscreen_mode() - if self.view.document.fullscreen_clock: - self.show_clock() - if self.view.document.fullscreen_pos: - self.show_pos_label() - def show_clock(self): self.clock_label.setVisible(True) self.clock_label.setText(QTime(22, 33, @@ -559,6 +525,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): def showNormal(self): self.view.document.page_position.save() + self.view.document.switch_to_window_mode() self.clock_label.setVisible(False) self.pos_label.setVisible(False) self.frame.setFrameStyle(self.original_frame_style) @@ -566,23 +533,23 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.clock_timer.stop() self.vertical_scrollbar.setVisible(True) self.window_mode_changed = 'normal' - self.esc_full_screen_action.setEnabled(False) + self.action_full_screen.setChecked(False) self.tool_bar.setVisible(True) self.tool_bar2.setVisible(True) - self.full_screen_label.setVisible(False) if hasattr(self, '_original_frame_margins'): om = self._original_frame_margins self.centralwidget.layout().setContentsMargins(om[0]) self.frame.layout().setContentsMargins(om[1]) - super(EbookViewer, self).showNormal() + if self.was_maximized: + super(EbookViewer, self).showMaximized() + else: + super(EbookViewer, self).showNormal() def handle_window_mode_toggle(self): if self.window_mode_changed: fs = self.window_mode_changed == 'fullscreen' self.window_mode_changed = None - if fs: - self.show_full_screen_label() - else: + if not fs: self.view.document.switch_to_window_mode() self.view.document.page_position.restore() self.scrolled(self.view.scroll_fraction) @@ -634,7 +601,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): if self.selected_text: QApplication.clipboard().setText(self.selected_text) - def back(self, x): + def back(self): pos = self.history.back(self.pos.value()) if pos is not None: self.goto_page(pos) @@ -643,7 +610,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): num = self.pos.value() self.goto_page(num) - def forward(self, x): + def forward(self): pos = self.history.forward() if pos is not None: self.goto_page(pos) @@ -657,6 +624,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): def goto_page(self, new_page, loaded_check=True): if self.current_page is not None or not loaded_check: for page in self.iterator.spine: + # print "goto_page", new_page, page.start_page, page.max_page if new_page >= page.start_page and new_page <= page.max_page: try: frac = float(new_page-page.start_page)/(page.pages-1) @@ -681,20 +649,21 @@ class EbookViewer(MainWindow, Ui_EbookViewer): def font_size_larger(self): self.view.magnify_fonts() - self.action_font_size_larger.setEnabled(self.view.multiplier < 3) - self.action_font_size_smaller.setEnabled(self.view.multiplier > 0.2) def font_size_smaller(self): self.view.shrink_fonts() - self.action_font_size_larger.setEnabled(self.view.multiplier < 3) - self.action_font_size_smaller.setEnabled(self.view.multiplier > 0.2) + def font_size_restore(self): + self.view.restore_font_size() + def magnification_changed(self, val): tt = _('Make font size %(which)s\nCurrent magnification: %(mag).1f') self.action_font_size_larger.setToolTip( tt %dict(which=_('larger'), mag=val)) self.action_font_size_smaller.setToolTip( tt %dict(which=_('smaller'), mag=val)) + self.action_font_size_larger.setEnabled(self.view.multiplier < 3) + self.action_font_size_smaller.setEnabled(self.view.multiplier > 0.2) def find(self, text, repeat=False, backwards=False): if not text: @@ -961,7 +930,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): if self.iterator is not None: self.save_current_position() self.iterator.__exit__() - self.iterator = EbookIterator(pathtoebook) + self.iterator = EbookIterator(pathtoebook, self.get_dont_show_cover_opt()) self.open_progress_indicator(_('Loading ebook...')) worker = Worker(target=partial(self.iterator.__enter__, extract_embedded_fonts_for_qt=True)) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 5952e11e57..d7dcbac75a 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -28,7 +28,7 @@ from calibre.ebooks.metadata.book.base import Metadata from calibre.constants import preferred_encoding, iswindows, filesystem_encoding from calibre.ptempfile import (PersistentTemporaryFile, base_dir, SpooledTemporaryFile) -from calibre.customize.ui import run_plugins_on_import +from calibre.customize.ui import run_plugins_on_import, postimport_plugins from calibre import isbytestring from calibre.utils.filenames import (ascii_filename, samefile, WindowsAtomicFolderMove, hardlink_file) @@ -1534,6 +1534,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.refresh_ids([id]) if notify: self.notify('metadata', [id]) + postimport_plugins(id, format) return True def save_original_format(self, book_id, fmt, notify=True): From 8a3ca41c0b94de0c2576ada555b3cac9db099d18 Mon Sep 17 00:00:00 2001 From: John Peterson Date: Mon, 5 Nov 2012 06:00:05 +0000 Subject: [PATCH 2/3] Response to merge review. 1) Fixed by making it optional. 1.5) Fixed by making it optional. 2) Fixed. 3) Not fixed. Can you provide a test file result in the unhandled exception that you describe? The option should be available because (i) the option is off by default and therefore the most novice users (that are least likely to identify the unhandled exception when it occurs) will be unaware of the option and (ii) the option has a larger net value available than not available. 4) Fixed. 5) Fixed. --- src/calibre/customize/__init__.py | 3 +- src/calibre/customize/ui.py | 4 +- src/calibre/gui2/__init__.py | 1 + src/calibre/gui2/add.py | 2 +- src/calibre/gui2/library/views.py | 3 +- src/calibre/gui2/preferences/adding.py | 1 + src/calibre/gui2/preferences/adding.ui | 26 +++++++++++- src/calibre/gui2/viewer/config.py | 8 ++++ src/calibre/gui2/viewer/config.ui | 14 +++++++ src/calibre/gui2/viewer/documentview.py | 2 + src/calibre/gui2/viewer/main.py | 54 +++++++++++++++++++++++-- 11 files changed, 109 insertions(+), 9 deletions(-) diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index 1f57305945..75ef4b0bd0 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -341,11 +341,12 @@ class FileTypePlugin(Plugin): # {{{ # Default implementation does nothing return path_to_ebook - def postimport(self, id): + def postimport(self, id, db): ''' Run post import. :param id: Library id of the added book. + :param db: Library db. ''' # }}} diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 15d448161e..987a6fbb84 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -172,6 +172,8 @@ run_plugins_on_postprocess = functools.partial(_run_filetype_plugins, occasion='postprocess') def postimport_plugins(id, format): + from calibre.gui2.ui import get_gui + db = get_gui().current_db customization = config['plugin_customization'] format = format.lower() for plugin in _on_postimport.get(format, []): @@ -180,7 +182,7 @@ def postimport_plugins(id, format): plugin.site_customization = customization.get(plugin.name, '') with plugin: try: - plugin.postimport(id) + plugin.postimport(id, db) except: print 'Running file type plugin %s failed with traceback:'%plugin.name traceback.print_exc() diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 895bb5a6b2..14776d1363 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -93,6 +93,7 @@ gprefs.defaults['tag_browser_dont_collapse'] = [] gprefs.defaults['edit_metadata_single_layout'] = 'default' gprefs.defaults['default_author_link'] = 'http://en.wikipedia.org/w/index.php?search={author}' gprefs.defaults['preserve_date_on_ctl'] = True +gprefs.defaults['manual_add_auto_convert'] = False gprefs.defaults['cb_fullscreen'] = False gprefs.defaults['worker_max_time'] = 0 gprefs.defaults['show_files_after_save'] = True diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py index 4336148816..eb4a2105d7 100644 --- a/src/calibre/gui2/add.py +++ b/src/calibre/gui2/add.py @@ -233,7 +233,7 @@ class DBAdder(QObject): # {{{ with open(path, 'rb') as f: self.db.add_format(id, fmt, f, index_is_id=True, notify=False, replace=replace) - if gprefs['auto_add_auto_convert']: + if gprefs['manual_add_auto_convert']: of = prefs['output_format'] if not of == fmt.lower(): gui = self.parent._parent diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 85636104cb..edfc0dc762 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -756,8 +756,7 @@ class BooksView(QTableView): # {{{ def keyPressEvent(self, event): if event.key() == Qt.Key_Return: - selected_rows = [r.row() for r in self.selectionModel().selectedRows()] - self.display_parent.iactions['View']._view_books(selected_rows) + self.display_parent.iactions['View'].view_book(True) else: return super(BooksView, self).keyPressEvent(event) diff --git a/src/calibre/gui2/preferences/adding.py b/src/calibre/gui2/preferences/adding.py index fafc5b5a1c..266b0ca9cc 100644 --- a/src/calibre/gui2/preferences/adding.py +++ b/src/calibre/gui2/preferences/adding.py @@ -28,6 +28,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('swap_author_names', prefs) r('add_formats_to_existing', prefs) r('preserve_date_on_ctl', gprefs) + r('manual_add_auto_convert', gprefs) choices = [ (_('Ignore duplicate incoming formats'), 'ignore'), (_('Overwrite existing duplicate formats'), 'overwrite'), diff --git a/src/calibre/gui2/preferences/adding.ui b/src/calibre/gui2/preferences/adding.ui index abf5d5f7a5..703d2de1a9 100644 --- a/src/calibre/gui2/preferences/adding.ui +++ b/src/calibre/gui2/preferences/adding.ui @@ -68,13 +68,37 @@ - + When using the "&Copy to library" action to copy books between libraries, preserve the date + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Automatically &convert added files to the current output format + + + + + diff --git a/src/calibre/gui2/viewer/config.py b/src/calibre/gui2/viewer/config.py index e3726c1ecb..10c519cad9 100644 --- a/src/calibre/gui2/viewer/config.py +++ b/src/calibre/gui2/viewer/config.py @@ -61,6 +61,10 @@ def config(defaults=None): help=_('Show reading position in fullscreen mode.')) c.add_opt('fullscreen_scrollbar', default=True, action='store_false', help=_('Show the scrollbar in fullscreen mode.')) + c.add_opt('fullscreen_message', default=True, + help=_('Show information message when enabling fullscreen.')) + c.add_opt('fullscreen_save_state', default=False, + help=_('Save the fullscreen state.')) c.add_opt('cols_per_screen', default=1) c.add_opt('use_book_margins', default=False, action='store_true') c.add_opt('top_margin', default=20) @@ -210,6 +214,8 @@ class ConfigDialog(QDialog, Ui_Dialog): self.opt_fullscreen_clock.setChecked(opts.fullscreen_clock) self.opt_fullscreen_scrollbar.setChecked(opts.fullscreen_scrollbar) self.opt_fullscreen_pos.setChecked(opts.fullscreen_pos) + self.opt_fullscreen_message.setChecked(opts.fullscreen_message) + self.opt_fullscreen_save_state.setChecked(opts.fullscreen_save_state) self.opt_cols_per_screen.setValue(opts.cols_per_screen) self.opt_override_book_margins.setChecked(not opts.use_book_margins) for x in ('top', 'bottom', 'side'): @@ -283,6 +289,8 @@ class ConfigDialog(QDialog, Ui_Dialog): c.set('fullscreen_clock', self.opt_fullscreen_clock.isChecked()) c.set('fullscreen_pos', self.opt_fullscreen_pos.isChecked()) c.set('fullscreen_scrollbar', self.opt_fullscreen_scrollbar.isChecked()) + c.set('fullscreen_message', self.opt_fullscreen_message.isChecked()) + c.set('fullscreen_save_state', self.opt_fullscreen_save_state.isChecked()) c.set('cols_per_screen', int(self.opt_cols_per_screen.value())) c.set('use_book_margins', not self.opt_override_book_margins.isChecked()) diff --git a/src/calibre/gui2/viewer/config.ui b/src/calibre/gui2/viewer/config.ui index abc5391ebf..23e31dd93f 100644 --- a/src/calibre/gui2/viewer/config.ui +++ b/src/calibre/gui2/viewer/config.ui @@ -402,6 +402,20 @@ QToolBox::tab:hover { + + + + Show fullscreen &message + + + + + + + Save fullscreen state + + + diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index c1927e1907..6bd6c7c740 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -145,6 +145,8 @@ class Document(QWebPage): # {{{ self.fullscreen_clock = opts.fullscreen_clock self.fullscreen_scrollbar = opts.fullscreen_scrollbar self.fullscreen_pos = opts.fullscreen_pos + self.fullscreen_message = opts.fullscreen_message + self.fullscreen_save_state = opts.fullscreen_save_state self.use_book_margins = opts.use_book_margins self.cols_per_screen = opts.cols_per_screen self.side_margin = opts.side_margin diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index c11fda7437..d1cb7b3d86 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -274,11 +274,36 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.tool_bar2.setContextMenuPolicy(Qt.PreventContextMenu) self.tool_bar.widgetForAction(self.action_bookmark).setPopupMode(QToolButton.MenuButtonPopup) self.action_full_screen.setCheckable(True) + self.full_screen_label = QLabel(''' +

+

%s

+

%s

+

%s

+

%s

+
+ '''%(_('Full screen mode'), + _('Right click to show controls'), + _('Tap in the left or right page margin to turn pages'), + _('Press Esc to quit')), + self) + self.full_screen_label.setVisible(False) + self.full_screen_label.setStyleSheet(''' + QLabel { + text-align: center; + background-color: white; + color: black; + border-width: 1px; + border-style: solid; + border-radius: 20px; + } + ''') self.window_mode_changed = None self.toggle_toolbar_action = QAction(_('Show/hide controls'), self) self.toggle_toolbar_action.setCheckable(True) self.toggle_toolbar_action.triggered.connect(self.toggle_toolbars) self.addAction(self.toggle_toolbar_action) + self.full_screen_label_anim = QPropertyAnimation( + self.full_screen_label, 'size') self.clock_label = QLabel('99:99', self) self.clock_label.setVisible(False) self.clock_label.setFocusPolicy(Qt.NoFocus) @@ -300,7 +325,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.pos_label.setFocusPolicy(Qt.NoFocus) self.clock_timer = QTimer(self) self.clock_timer.timeout.connect(self.update_clock) - + self.print_menu = QMenu() self.print_menu.addAction(QIcon(I('print-preview.png')), _('Print Preview')) self.action_print.setMenu(self.print_menu) @@ -425,7 +450,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.toggle_paged_mode(self.action_toggle_paged_mode.isChecked(), at_start=True) fullscreen = vprefs.get('fullscreen', None) - if fullscreen: + if fullscreen and self.view.document.fullscreen_save_state: self.showFullScreen() def lookup(self, word): @@ -486,6 +511,25 @@ class EbookViewer(MainWindow, Ui_EbookViewer): super(EbookViewer, self).showFullScreen() + def show_full_screen_label(self): + f = self.full_screen_label + f.setVisible(True) + height = 200 + width = int(0.7*self.view.width()) + f.resize(width, height) + f.move((self.view.width() - width)//2, (self.view.height()-height)//2) + a = self.full_screen_label_anim + a.setDuration(500) + a.setStartValue(QSize(width, 0)) + a.setEndValue(QSize(width, height)) + a.start() + QTimer.singleShot(3500, self.full_screen_label.hide) + self.view.document.switch_to_fullscreen_mode() + if self.view.document.fullscreen_clock: + self.show_clock() + if self.view.document.fullscreen_pos: + self.show_pos_label() + def show_clock(self): self.clock_label.setVisible(True) self.clock_label.setText(QTime(22, 33, @@ -536,6 +580,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.action_full_screen.setChecked(False) self.tool_bar.setVisible(True) self.tool_bar2.setVisible(True) + self.full_screen_label.setVisible(False) if hasattr(self, '_original_frame_margins'): om = self._original_frame_margins self.centralwidget.layout().setContentsMargins(om[0]) @@ -549,7 +594,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer): if self.window_mode_changed: fs = self.window_mode_changed == 'fullscreen' self.window_mode_changed = None - if not fs: + if fs: + if self.view.document.fullscreen_message: + self.show_full_screen_label() + else: self.view.document.switch_to_window_mode() self.view.document.page_position.restore() self.scrolled(self.view.scroll_fraction) From 4f43a7fa8fceec82014bf87aabd1a6ac7418a17f Mon Sep 17 00:00:00 2001 From: John Peterson Date: Sun, 18 Nov 2012 17:01:20 +0000 Subject: [PATCH 3/3] Response to merge review. 3) Fixed. --- src/calibre/ebooks/oeb/iterator/book.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/oeb/iterator/book.py b/src/calibre/ebooks/oeb/iterator/book.py index 65fc48cad7..37ef43f5f1 100644 --- a/src/calibre/ebooks/oeb/iterator/book.py +++ b/src/calibre/ebooks/oeb/iterator/book.py @@ -153,7 +153,7 @@ class EbookIterator(BookmarksMixin): mime_type='application/xhtml+xml')] self.delete_on_exit.append(cfile) elif self.exclude_cover: - self.spine.remove(self.spine[0]) + self.spine.remove(cover) if self.opf.path_to_html_toc is not None and \ self.opf.path_to_html_toc not in self.spine: