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/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)) diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index 4f8ae68943..6c0c384eb3 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' @@ -572,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: @@ -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 @@ -595,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: @@ -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 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() 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 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) # }}} diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index 0c8eb84a37..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. ''' @@ -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() 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')