From 1a0d182067fbf02a8bf3e5f06e912c4ced52f406 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 12:19:32 -0700 Subject: [PATCH 1/9] After a search, always select the first result row --- src/calibre/gui2/init.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 223efcf95b..27a6a2352a 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -86,6 +86,10 @@ class LibraryViewMixin(object): # {{{ if view is self.current_view(): self.search.search_done(ok) self.set_number_of_books_shown() + if ok: + v = self.current_view() + if hasattr(v, 'set_current_row'): + v.set_current_row(0) # }}} From 769d4e9502e2e46641e0b32bee083703a625b690 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 12:55:15 -0700 Subject: [PATCH 2/9] Fix #7726 (Search history incorrect when closing/reopening calibre) --- src/calibre/gui2/search_box.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index 0c8eb84a37..a0faa4c0a1 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -92,7 +92,11 @@ class SearchBox2(QComboBox): # {{{ def initialize(self, opt_name, colorize=False, help_text=_('Search')): self.as_you_type = config['search_as_you_type'] self.opt_name = opt_name - self.addItems(QStringList(list(set(config[opt_name])))) + items = [] + for item in config[opt_name]: + if item not in items: + items.append(item) + self.addItems(QStringList(items)) try: self.line_edit.setPlaceholderText(help_text) except: @@ -189,8 +193,9 @@ class SearchBox2(QComboBox): # {{{ self.insertItem(0, t) self.setCurrentIndex(0) self.block_signals(False) - config[self.opt_name] = [unicode(self.itemText(i)) for i in + history = [unicode(self.itemText(i)) for i in range(self.count())] + config[self.opt_name] = history def do_search(self, *args): self._do_search() From 8460d35fa7be2637e722db79aa4d89d079380b5e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 13:01:42 -0700 Subject: [PATCH 3/9] Fix #7715 (OS X - Viewer window taller than non-standard display, can't resize) --- src/calibre/gui2/viewer/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index 7c19567804..1ea1aca733 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -17,7 +17,7 @@ from calibre.gui2.viewer.bookmarkmanager import BookmarkManager from calibre.gui2.widgets import ProgressIndicator from calibre.gui2.main_window import MainWindow from calibre.gui2 import Application, ORG_NAME, APP_UID, choose_files, \ - info_dialog, error_dialog, open_url + info_dialog, error_dialog, open_url, available_height from calibre.ebooks.oeb.iterator import EbookIterator from calibre.ebooks import DRMError from calibre.constants import islinux, isfreebsd, isosx @@ -694,6 +694,9 @@ class EbookViewer(MainWindow, Ui_EbookViewer): if ss is not None: self.splitter.restoreState(ss) self.show_toc_on_open = dynamic.get('viewer_toc_isvisible', False) + av = available_height() - 30 + if self.height() > av: + self.resize(self.width(), av) def config(defaults=None): desc = _('Options to control the ebook viewer') From 0c7df44df5bbe78dcb7740d6a2e941f23b2591ff Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 13:22:54 -0700 Subject: [PATCH 4/9] ... --- src/calibre/gui2/search_box.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index a0faa4c0a1..1cdf622537 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -51,7 +51,7 @@ class SearchBox2(QComboBox): # {{{ * Call search_done() after every search is complete * Call set_search_string() to perform a search programmatically * You can use the current_text property to get the current search text - Be aware that if you are using it in a slow connected to the + Be aware that if you are using it in a slot connected to the changed() signal, if the connection is not queued it will not be accurate. ''' From 6143392ee9c21f118a90c397fea8ce5af05833e6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 16:27:17 -0700 Subject: [PATCH 5/9] Fix #7706 (show cover Image info in tool tip) --- src/calibre/gui2/dialogs/metadata_single.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py index 2b951a7b2b..7beeb56378 100644 --- a/src/calibre/gui2/dialogs/metadata_single.py +++ b/src/calibre/gui2/dialogs/metadata_single.py @@ -98,9 +98,16 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): COVER_FETCH_TIMEOUT = 240 # seconds view_format = pyqtSignal(object) + def update_cover_tooltip(self): + p = self.cover.pixmap() + self.cover.setToolTip(_('Cover size: %dx%d pixels') % + (p.width(), p.height())) + + def do_reset_cover(self, *args): pix = QPixmap(I('default_cover.png')) self.cover.setPixmap(pix) + self.update_cover_tooltip() self.cover_changed = True self.cover_data = None @@ -136,6 +143,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): else: self.cover_path.setText(_file) self.cover.setPixmap(pix) + self.update_cover_tooltip() self.cover_changed = True self.cpixmap = pix self.cover_data = cover @@ -161,6 +169,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): pix = QPixmap() pix.loadFromData(self.cover_data) self.cover.setPixmap(pix) + self.update_cover_tooltip() self.cover_changed = True self.cpixmap = pix @@ -296,6 +305,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): _('The cover in the %s format is invalid')%ext).exec_() return self.cover.setPixmap(pix) + self.update_cover_tooltip() self.cover_changed = True self.cpixmap = pix self.cover_data = cdata @@ -312,6 +322,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): pix = QPixmap() pix.loadFromData(cdata) self.cover.setPixmap(pix) + self.update_cover_tooltip() self.cover_changed = True self.cpixmap = pix self.cover_data = cdata @@ -472,6 +483,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): else: self.cover_data = cover self.cover.setPixmap(pm) + self.update_cover_tooltip() self.original_series_name = unicode(self.series.text()).strip() if len(db.custom_column_label_map) == 0: self.central_widget.tabBar().setVisible(False) @@ -677,6 +689,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): _('The cover is not a valid picture')).exec_() else: self.cover.setPixmap(pix) + self.update_cover_tooltip() self.cover_changed = True self.cpixmap = pix self.cover_data = self.cover_fetcher.cover_data From 113ff417d66c6997aaf8428733026d8a50c61c2e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 18:05:35 -0700 Subject: [PATCH 6/9] Conversion pipeline: Respect max-width and max-height when calculating the effective size of an element --- src/calibre/ebooks/oeb/stylizer.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index 4f8ae68943..84bce3864e 100644 --- a/src/calibre/ebooks/oeb/stylizer.py +++ b/src/calibre/ebooks/oeb/stylizer.py @@ -253,7 +253,10 @@ class Stylizer(object): upd = {} for prop in ('width', 'height'): val = elem.get(prop, '').strip() - del elem.attrib[prop] + try: + del elem.attrib[prop] + except: + pass if val: if num_pat.match(val) is not None: val += 'px' @@ -584,6 +587,13 @@ class Style(object): if isinstance(result, (unicode, str, bytes)): result = self._profile.width self._width = result + if 'max-width' in self._style: + result = self._unit_convert(self._style['max-width'], base=base) + if isinstance(result, (unicode, str, bytes)): + result = self._width + if result < self._width: + self._width = result + return self._width @property @@ -607,6 +617,13 @@ class Style(object): if isinstance(result, (unicode, str, bytes)): result = self._profile.height self._height = result + if 'max-height' in self._style: + result = self._unit_convert(self._style['max-height'], base=base) + if isinstance(result, (unicode, str, bytes)): + result = self._height + if result < self._height: + self._height = result + return self._height @property From b343837f65305b2729f78383260cc3944472d78d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 20:31:01 -0700 Subject: [PATCH 7/9] Conversion pipeline: Fix bug that caused height/width specified in %/em of screen size to be incorrectly calculated by a factor of 72./DPI --- src/calibre/customize/profiles.py | 2 ++ src/calibre/ebooks/oeb/stylizer.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py index 2ca3bb0c54..0a3945304a 100644 --- a/src/calibre/customize/profiles.py +++ b/src/calibre/customize/profiles.py @@ -37,6 +37,8 @@ class Plugin(_Plugin): self.fsizes.append((name, num, float(size))) self.fnames = dict((name, sz) for name, _, sz in self.fsizes if name) self.fnums = dict((num, sz) for _, num, sz in self.fsizes if num) + self.width_pts = self.width * 72./self.dpi + self.height_pts = self.height * 72./self.dpi # Input profiles {{{ class InputProfile(Plugin): diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index 84bce3864e..6c0c384eb3 100644 --- a/src/calibre/ebooks/oeb/stylizer.py +++ b/src/calibre/ebooks/oeb/stylizer.py @@ -575,7 +575,7 @@ class Style(object): if parent is not None: base = parent.width else: - base = self._profile.width + base = self._profile.width_pts if 'width' in self._element.attrib: width = self._element.attrib['width'] elif 'width' in self._style: @@ -605,7 +605,7 @@ class Style(object): if parent is not None: base = parent.height else: - base = self._profile.height + base = self._profile.height_pts if 'height' in self._element.attrib: height = self._element.attrib['height'] elif 'height' in self._style: From 63ef5a542510cc4556560cc2ace0b2395b5e7dc2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 20:35:08 -0700 Subject: [PATCH 8/9] MOBI Output: When the input document does not explicitly specify a size for images, set the size to be the natural size of the image. This works around Amazon's *truly wonderful* MOBI renderer's tendency to expand images that do not have a width and height specified. --- src/calibre/ebooks/mobi/mobiml.py | 41 ++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/mobi/mobiml.py b/src/calibre/ebooks/mobi/mobiml.py index 98e7b6023c..8d20179250 100644 --- a/src/calibre/ebooks/mobi/mobiml.py +++ b/src/calibre/ebooks/mobi/mobiml.py @@ -10,9 +10,10 @@ import copy import re from lxml import etree from calibre.ebooks.oeb.base import namespace, barename -from calibre.ebooks.oeb.base import XHTML, XHTML_NS, OEB_DOCS +from calibre.ebooks.oeb.base import XHTML, XHTML_NS, OEB_DOCS, urlnormalize from calibre.ebooks.oeb.stylizer import Stylizer from calibre.ebooks.oeb.transforms.flatcss import KeyMapper +from calibre.utils.magick.draw import identify_data MBP_NS = 'http://mobipocket.com/ns/mbp' def MBP(name): return '{%s}%s' % (MBP_NS, name) @@ -121,6 +122,7 @@ class MobiMLizer(object): body = item.data.find(XHTML('body')) nroot = etree.Element(XHTML('html'), nsmap=MOBI_NSMAP) nbody = etree.SubElement(nroot, XHTML('body')) + self.current_spine_item = item self.mobimlize_elem(body, stylizer, BlockState(nbody), [FormatState()]) item.data = nroot @@ -357,8 +359,9 @@ class MobiMLizer(object): if tag == 'img' and 'src' in elem.attrib: istate.attrib['src'] = elem.attrib['src'] istate.attrib['align'] = 'baseline' + cssdict = style.cssdict() for prop in ('width', 'height'): - if style[prop] != 'auto': + if cssdict[prop] != 'auto': value = style[prop] if value == getattr(self.profile, prop): result = '100%' @@ -371,8 +374,40 @@ class MobiMLizer(object): (72./self.profile.dpi))) except: continue - result = "%d"%pixs + result = str(pixs) istate.attrib[prop] = result + if 'width' not in istate.attrib or 'height' not in istate.attrib: + href = self.current_spine_item.abshref(elem.attrib['src']) + try: + item = self.oeb.manifest.hrefs[urlnormalize(href)] + except: + self.oeb.logger.warn('Failed to find image:', + href) + else: + try: + width, height = identify_data(item.data)[:2] + except: + self.oeb.logger.warn('Invalid image:', href) + else: + if 'width' not in istate.attrib and 'height' not in \ + istate.attrib: + istate.attrib['width'] = str(width) + istate.attrib['height'] = str(height) + else: + ar = float(width)/float(height) + if 'width' not in istate.attrib: + try: + width = int(istate.attrib['height'])*ar + except: + pass + istate.attrib['width'] = str(int(width)) + else: + try: + height = int(istate.attrib['width'])/ar + except: + pass + istate.attrib['height'] = str(int(height)) + item.unload_data_from_memory() elif tag == 'hr' and asfloat(style['width']) > 0: prop = style['width'] / self.profile.width istate.attrib['width'] = "%d%%" % int(round(prop * 100)) From 28732ccbdbd17e7946a0cfea67bdcc9f9d50893b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Dec 2010 21:55:02 -0700 Subject: [PATCH 9/9] Fix #7424 (Formats hyperlinks are inconsistently launched) --- src/calibre/gui2/actions/show_book_details.py | 3 ++- src/calibre/gui2/dialogs/book_info.py | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/calibre/gui2/actions/show_book_details.py b/src/calibre/gui2/actions/show_book_details.py index 18b0a694bf..67903a7d58 100644 --- a/src/calibre/gui2/actions/show_book_details.py +++ b/src/calibre/gui2/actions/show_book_details.py @@ -29,5 +29,6 @@ class ShowBookDetailsAction(InterfaceAction): return index = self.gui.library_view.currentIndex() if index.isValid(): - BookInfo(self.gui, self.gui.library_view, index).show() + BookInfo(self.gui, self.gui.library_view, index, + self.gui.iactions['View'].view_format_by_id).show() diff --git a/src/calibre/gui2/dialogs/book_info.py b/src/calibre/gui2/dialogs/book_info.py index 4cbe0ace7f..df21314712 100644 --- a/src/calibre/gui2/dialogs/book_info.py +++ b/src/calibre/gui2/dialogs/book_info.py @@ -15,12 +15,13 @@ from calibre.library.comments import comments_to_html class BookInfo(QDialog, Ui_BookInfo): - def __init__(self, parent, view, row): + def __init__(self, parent, view, row, view_func): QDialog.__init__(self, parent) Ui_BookInfo.__init__(self) self.setupUi(self) self.cover_pixmap = None self.comments.sizeHint = self.comments_size_hint + self.view_func = view_func desktop = QCoreApplication.instance().desktop() screen_height = desktop.availableGeometry().height() - 100 @@ -58,10 +59,7 @@ class BookInfo(QDialog, Ui_BookInfo): if os.sep in path: open_local_file(path) else: - path = self.view.model().db.format_abspath(self.current_row, path) - if path is not None: - open_local_file(path) - + self.view_func(self.view.model().id(self.current_row), path) def next(self): row = self.view.currentIndex().row()