Merge from trunk

This commit is contained in:
Charles Haley 2010-12-02 08:37:01 +00:00
commit 0a730c46ee
9 changed files with 94 additions and 16 deletions

View File

@ -37,6 +37,8 @@ class Plugin(_Plugin):
self.fsizes.append((name, num, float(size))) self.fsizes.append((name, num, float(size)))
self.fnames = dict((name, sz) for name, _, sz in self.fsizes if name) 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.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 {{{ # Input profiles {{{
class InputProfile(Plugin): class InputProfile(Plugin):

View File

@ -10,9 +10,10 @@ import copy
import re import re
from lxml import etree from lxml import etree
from calibre.ebooks.oeb.base import namespace, barename 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.stylizer import Stylizer
from calibre.ebooks.oeb.transforms.flatcss import KeyMapper from calibre.ebooks.oeb.transforms.flatcss import KeyMapper
from calibre.utils.magick.draw import identify_data
MBP_NS = 'http://mobipocket.com/ns/mbp' MBP_NS = 'http://mobipocket.com/ns/mbp'
def MBP(name): return '{%s}%s' % (MBP_NS, name) def MBP(name): return '{%s}%s' % (MBP_NS, name)
@ -121,6 +122,7 @@ class MobiMLizer(object):
body = item.data.find(XHTML('body')) body = item.data.find(XHTML('body'))
nroot = etree.Element(XHTML('html'), nsmap=MOBI_NSMAP) nroot = etree.Element(XHTML('html'), nsmap=MOBI_NSMAP)
nbody = etree.SubElement(nroot, XHTML('body')) nbody = etree.SubElement(nroot, XHTML('body'))
self.current_spine_item = item
self.mobimlize_elem(body, stylizer, BlockState(nbody), self.mobimlize_elem(body, stylizer, BlockState(nbody),
[FormatState()]) [FormatState()])
item.data = nroot item.data = nroot
@ -357,8 +359,9 @@ class MobiMLizer(object):
if tag == 'img' and 'src' in elem.attrib: if tag == 'img' and 'src' in elem.attrib:
istate.attrib['src'] = elem.attrib['src'] istate.attrib['src'] = elem.attrib['src']
istate.attrib['align'] = 'baseline' istate.attrib['align'] = 'baseline'
cssdict = style.cssdict()
for prop in ('width', 'height'): for prop in ('width', 'height'):
if style[prop] != 'auto': if cssdict[prop] != 'auto':
value = style[prop] value = style[prop]
if value == getattr(self.profile, prop): if value == getattr(self.profile, prop):
result = '100%' result = '100%'
@ -371,8 +374,40 @@ class MobiMLizer(object):
(72./self.profile.dpi))) (72./self.profile.dpi)))
except: except:
continue continue
result = "%d"%pixs result = str(pixs)
istate.attrib[prop] = result 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: elif tag == 'hr' and asfloat(style['width']) > 0:
prop = style['width'] / self.profile.width prop = style['width'] / self.profile.width
istate.attrib['width'] = "%d%%" % int(round(prop * 100)) istate.attrib['width'] = "%d%%" % int(round(prop * 100))

View File

@ -253,7 +253,10 @@ class Stylizer(object):
upd = {} upd = {}
for prop in ('width', 'height'): for prop in ('width', 'height'):
val = elem.get(prop, '').strip() val = elem.get(prop, '').strip()
del elem.attrib[prop] try:
del elem.attrib[prop]
except:
pass
if val: if val:
if num_pat.match(val) is not None: if num_pat.match(val) is not None:
val += 'px' val += 'px'
@ -572,7 +575,7 @@ class Style(object):
if parent is not None: if parent is not None:
base = parent.width base = parent.width
else: else:
base = self._profile.width base = self._profile.width_pts
if 'width' in self._element.attrib: if 'width' in self._element.attrib:
width = self._element.attrib['width'] width = self._element.attrib['width']
elif 'width' in self._style: elif 'width' in self._style:
@ -584,6 +587,13 @@ class Style(object):
if isinstance(result, (unicode, str, bytes)): if isinstance(result, (unicode, str, bytes)):
result = self._profile.width result = self._profile.width
self._width = result 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 return self._width
@property @property
@ -595,7 +605,7 @@ class Style(object):
if parent is not None: if parent is not None:
base = parent.height base = parent.height
else: else:
base = self._profile.height base = self._profile.height_pts
if 'height' in self._element.attrib: if 'height' in self._element.attrib:
height = self._element.attrib['height'] height = self._element.attrib['height']
elif 'height' in self._style: elif 'height' in self._style:
@ -607,6 +617,13 @@ class Style(object):
if isinstance(result, (unicode, str, bytes)): if isinstance(result, (unicode, str, bytes)):
result = self._profile.height result = self._profile.height
self._height = result 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 return self._height
@property @property

View File

@ -29,5 +29,6 @@ class ShowBookDetailsAction(InterfaceAction):
return return
index = self.gui.library_view.currentIndex() index = self.gui.library_view.currentIndex()
if index.isValid(): 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()

View File

@ -15,12 +15,13 @@ from calibre.library.comments import comments_to_html
class BookInfo(QDialog, Ui_BookInfo): class BookInfo(QDialog, Ui_BookInfo):
def __init__(self, parent, view, row): def __init__(self, parent, view, row, view_func):
QDialog.__init__(self, parent) QDialog.__init__(self, parent)
Ui_BookInfo.__init__(self) Ui_BookInfo.__init__(self)
self.setupUi(self) self.setupUi(self)
self.cover_pixmap = None self.cover_pixmap = None
self.comments.sizeHint = self.comments_size_hint self.comments.sizeHint = self.comments_size_hint
self.view_func = view_func
desktop = QCoreApplication.instance().desktop() desktop = QCoreApplication.instance().desktop()
screen_height = desktop.availableGeometry().height() - 100 screen_height = desktop.availableGeometry().height() - 100
@ -58,10 +59,7 @@ class BookInfo(QDialog, Ui_BookInfo):
if os.sep in path: if os.sep in path:
open_local_file(path) open_local_file(path)
else: else:
path = self.view.model().db.format_abspath(self.current_row, path) self.view_func(self.view.model().id(self.current_row), path)
if path is not None:
open_local_file(path)
def next(self): def next(self):
row = self.view.currentIndex().row() row = self.view.currentIndex().row()

View File

@ -98,9 +98,16 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
COVER_FETCH_TIMEOUT = 240 # seconds COVER_FETCH_TIMEOUT = 240 # seconds
view_format = pyqtSignal(object) 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): def do_reset_cover(self, *args):
pix = QPixmap(I('default_cover.png')) pix = QPixmap(I('default_cover.png'))
self.cover.setPixmap(pix) self.cover.setPixmap(pix)
self.update_cover_tooltip()
self.cover_changed = True self.cover_changed = True
self.cover_data = None self.cover_data = None
@ -136,6 +143,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
else: else:
self.cover_path.setText(_file) self.cover_path.setText(_file)
self.cover.setPixmap(pix) self.cover.setPixmap(pix)
self.update_cover_tooltip()
self.cover_changed = True self.cover_changed = True
self.cpixmap = pix self.cpixmap = pix
self.cover_data = cover self.cover_data = cover
@ -161,6 +169,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
pix = QPixmap() pix = QPixmap()
pix.loadFromData(self.cover_data) pix.loadFromData(self.cover_data)
self.cover.setPixmap(pix) self.cover.setPixmap(pix)
self.update_cover_tooltip()
self.cover_changed = True self.cover_changed = True
self.cpixmap = pix self.cpixmap = pix
@ -296,6 +305,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
_('The cover in the %s format is invalid')%ext).exec_() _('The cover in the %s format is invalid')%ext).exec_()
return return
self.cover.setPixmap(pix) self.cover.setPixmap(pix)
self.update_cover_tooltip()
self.cover_changed = True self.cover_changed = True
self.cpixmap = pix self.cpixmap = pix
self.cover_data = cdata self.cover_data = cdata
@ -312,6 +322,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
pix = QPixmap() pix = QPixmap()
pix.loadFromData(cdata) pix.loadFromData(cdata)
self.cover.setPixmap(pix) self.cover.setPixmap(pix)
self.update_cover_tooltip()
self.cover_changed = True self.cover_changed = True
self.cpixmap = pix self.cpixmap = pix
self.cover_data = cdata self.cover_data = cdata
@ -472,6 +483,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
else: else:
self.cover_data = cover self.cover_data = cover
self.cover.setPixmap(pm) self.cover.setPixmap(pm)
self.update_cover_tooltip()
self.original_series_name = unicode(self.series.text()).strip() self.original_series_name = unicode(self.series.text()).strip()
if len(db.custom_column_label_map) == 0: if len(db.custom_column_label_map) == 0:
self.central_widget.tabBar().setVisible(False) self.central_widget.tabBar().setVisible(False)
@ -677,6 +689,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
_('The cover is not a valid picture')).exec_() _('The cover is not a valid picture')).exec_()
else: else:
self.cover.setPixmap(pix) self.cover.setPixmap(pix)
self.update_cover_tooltip()
self.cover_changed = True self.cover_changed = True
self.cpixmap = pix self.cpixmap = pix
self.cover_data = self.cover_fetcher.cover_data self.cover_data = self.cover_fetcher.cover_data

View File

@ -86,6 +86,10 @@ class LibraryViewMixin(object): # {{{
if view is self.current_view(): if view is self.current_view():
self.search.search_done(ok) self.search.search_done(ok)
self.set_number_of_books_shown() self.set_number_of_books_shown()
if ok:
v = self.current_view()
if hasattr(v, 'set_current_row'):
v.set_current_row(0)
# }}} # }}}

View File

@ -51,7 +51,7 @@ class SearchBox2(QComboBox): # {{{
* Call search_done() after every search is complete * Call search_done() after every search is complete
* Call set_search_string() to perform a search programmatically * Call set_search_string() to perform a search programmatically
* You can use the current_text property to get the current search text * 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 changed() signal, if the connection is not queued it will not be
accurate. accurate.
''' '''
@ -92,7 +92,11 @@ class SearchBox2(QComboBox): # {{{
def initialize(self, opt_name, colorize=False, help_text=_('Search')): def initialize(self, opt_name, colorize=False, help_text=_('Search')):
self.as_you_type = config['search_as_you_type'] self.as_you_type = config['search_as_you_type']
self.opt_name = opt_name 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: try:
self.line_edit.setPlaceholderText(help_text) self.line_edit.setPlaceholderText(help_text)
except: except:
@ -189,8 +193,9 @@ class SearchBox2(QComboBox): # {{{
self.insertItem(0, t) self.insertItem(0, t)
self.setCurrentIndex(0) self.setCurrentIndex(0)
self.block_signals(False) 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())] range(self.count())]
config[self.opt_name] = history
def do_search(self, *args): def do_search(self, *args):
self._do_search() self._do_search()

View File

@ -17,7 +17,7 @@ from calibre.gui2.viewer.bookmarkmanager import BookmarkManager
from calibre.gui2.widgets import ProgressIndicator from calibre.gui2.widgets import ProgressIndicator
from calibre.gui2.main_window import MainWindow from calibre.gui2.main_window import MainWindow
from calibre.gui2 import Application, ORG_NAME, APP_UID, choose_files, \ 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.oeb.iterator import EbookIterator
from calibre.ebooks import DRMError from calibre.ebooks import DRMError
from calibre.constants import islinux, isfreebsd, isosx from calibre.constants import islinux, isfreebsd, isosx
@ -694,6 +694,9 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
if ss is not None: if ss is not None:
self.splitter.restoreState(ss) self.splitter.restoreState(ss)
self.show_toc_on_open = dynamic.get('viewer_toc_isvisible', False) 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): def config(defaults=None):
desc = _('Options to control the ebook viewer') desc = _('Options to control the ebook viewer')