mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Merge from trunk
This commit is contained in:
commit
0a730c46ee
@ -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):
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
# }}}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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')
|
||||
|
Loading…
x
Reference in New Issue
Block a user