mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Pull from trunk
This commit is contained in:
commit
9ab8caf6f5
@ -1,5 +1,5 @@
|
||||
" Project wide builtins
|
||||
let g:pyflakes_builtins += ["dynamic_property", '__']
|
||||
let g:pyflakes_builtins += ["dynamic_property", "__"]
|
||||
|
||||
python << EOFPY
|
||||
import os
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.5.3'
|
||||
__version__ = '0.5.4'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
'''
|
||||
Various run time constants.
|
||||
|
@ -510,8 +510,6 @@ class OPF(object):
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def get_text(self, elem):
|
||||
return u''.join(self.CONTENT(elem) or self.TEXT(elem))
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
import os, glob
|
||||
import os, glob, re
|
||||
from urlparse import urlparse
|
||||
from urllib import unquote
|
||||
|
||||
@ -10,17 +10,17 @@ from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup, BeautifulSoup
|
||||
from calibre.ebooks.chardet import xml_to_unicode
|
||||
|
||||
class NCXSoup(BeautifulStoneSoup):
|
||||
|
||||
|
||||
NESTABLE_TAGS = {'navpoint':[]}
|
||||
|
||||
|
||||
def __init__(self, raw):
|
||||
BeautifulStoneSoup.__init__(self, raw,
|
||||
BeautifulStoneSoup.__init__(self, raw,
|
||||
convertEntities=BeautifulSoup.HTML_ENTITIES,
|
||||
selfClosingTags=['meta', 'content'])
|
||||
|
||||
class TOC(list):
|
||||
|
||||
def __init__(self, href=None, fragment=None, text=None, parent=None, play_order=0,
|
||||
|
||||
def __init__(self, href=None, fragment=None, text=None, parent=None, play_order=0,
|
||||
base_path=os.getcwd(), type='unknown'):
|
||||
self.href = href
|
||||
self.fragment = fragment
|
||||
@ -31,7 +31,7 @@ class TOC(list):
|
||||
self.base_path = base_path
|
||||
self.play_order = play_order
|
||||
self.type = type
|
||||
|
||||
|
||||
def __str__(self):
|
||||
lines = ['TOC: %s#%s'%(self.href, self.fragment)]
|
||||
for child in self:
|
||||
@ -39,10 +39,10 @@ class TOC(list):
|
||||
for l in c:
|
||||
lines.append('\t'+l)
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def count(self, type):
|
||||
return len([i for i in self.flat() if i.type == type])
|
||||
|
||||
|
||||
def purge(self, types, max=0):
|
||||
remove = []
|
||||
for entry in self.flat():
|
||||
@ -54,23 +54,23 @@ class TOC(list):
|
||||
continue
|
||||
entry.parent.remove(entry)
|
||||
return remove
|
||||
|
||||
|
||||
def remove(self, entry):
|
||||
list.remove(self, entry)
|
||||
entry.parent = None
|
||||
|
||||
|
||||
def add_item(self, href, fragment, text, play_order=None, type='unknown'):
|
||||
if play_order is None:
|
||||
play_order = (self[-1].play_order if len(self) else self.play_order) + 1
|
||||
self.append(TOC(href=href, fragment=fragment, text=text, parent=self,
|
||||
base_path=self.base_path, play_order=play_order, type=type))
|
||||
return self[-1]
|
||||
|
||||
|
||||
def top_level_items(self):
|
||||
for item in self:
|
||||
if item.text is not None:
|
||||
yield item
|
||||
|
||||
|
||||
def depth(self):
|
||||
depth = 1
|
||||
for obj in self:
|
||||
@ -78,14 +78,14 @@ class TOC(list):
|
||||
if c > depth - 1:
|
||||
depth = c + 1
|
||||
return depth
|
||||
|
||||
|
||||
def flat(self):
|
||||
'Depth first iteration over the tree rooted at self'
|
||||
yield self
|
||||
for obj in self:
|
||||
for i in obj.flat():
|
||||
yield i
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def abspath(self):
|
||||
doc='Return the file this toc entry points to as a absolute path to a file on the system.'
|
||||
@ -96,9 +96,9 @@ class TOC(list):
|
||||
if not os.path.isabs(path):
|
||||
path = os.path.join(self.base_path, path)
|
||||
return path
|
||||
|
||||
return property(fget=fget, doc=doc)
|
||||
|
||||
|
||||
return property(fget=fget, doc=doc)
|
||||
|
||||
def read_from_opf(self, opfreader):
|
||||
toc = opfreader.soup.find('spine', toc=True)
|
||||
if toc is not None:
|
||||
@ -111,7 +111,7 @@ class TOC(list):
|
||||
if 'toc' in item.href().lower():
|
||||
toc = item.href()
|
||||
break
|
||||
|
||||
|
||||
if toc is not None:
|
||||
if toc.lower() not in ('ncx', 'ncxtoc'):
|
||||
toc = urlparse(unquote(toc))[2]
|
||||
@ -123,7 +123,7 @@ class TOC(list):
|
||||
bn = os.path.basename(toc)
|
||||
bn = bn.replace('_top.htm', '_toc.htm') # Bug in BAEN OPF files
|
||||
toc = os.path.join(os.path.dirname(toc), bn)
|
||||
|
||||
|
||||
self.read_html_toc(toc)
|
||||
except:
|
||||
print 'WARNING: Could not read Table of Contents. Continuing anyway.'
|
||||
@ -141,43 +141,43 @@ class TOC(list):
|
||||
if m:
|
||||
toc = m[0]
|
||||
self.read_ncx_toc(toc)
|
||||
|
||||
|
||||
def read_ncx_toc(self, toc):
|
||||
self.base_path = os.path.dirname(toc)
|
||||
soup = NCXSoup(xml_to_unicode(open(toc, 'rb').read())[0])
|
||||
|
||||
|
||||
def process_navpoint(np, dest):
|
||||
play_order = np.get('playOrder', None)
|
||||
if play_order is None:
|
||||
play_order = int(np.get('playorder', 1))
|
||||
href = fragment = text = None
|
||||
nl = np.find('navlabel')
|
||||
nl = np.find(re.compile('navlabel'))
|
||||
if nl is not None:
|
||||
text = u''
|
||||
for txt in nl.findAll('text'):
|
||||
for txt in nl.findAll(re.compile('text')):
|
||||
text += ''.join([unicode(s) for s in txt.findAll(text=True)])
|
||||
content = np.find('content')
|
||||
content = np.find(re.compile('content'))
|
||||
if content is None or not content.has_key('src') or not txt:
|
||||
return
|
||||
|
||||
|
||||
purl = urlparse(unquote(content['src']))
|
||||
href, fragment = purl[2], purl[5]
|
||||
nd = dest.add_item(href, fragment, text)
|
||||
nd.play_order = play_order
|
||||
|
||||
|
||||
for c in np:
|
||||
if getattr(c, 'name', None) == 'navpoint':
|
||||
if 'navpoint' in getattr(c, 'name', ''):
|
||||
process_navpoint(c, nd)
|
||||
|
||||
nm = soup.find('navmap')
|
||||
|
||||
nm = soup.find(re.compile('navmap'))
|
||||
if nm is None:
|
||||
raise ValueError('NCX files must have a <navmap> element.')
|
||||
|
||||
|
||||
for elem in nm:
|
||||
if getattr(elem, 'name', None) == 'navpoint':
|
||||
if 'navpoint' in getattr(elem, 'name', ''):
|
||||
process_navpoint(elem, self)
|
||||
|
||||
|
||||
|
||||
|
||||
def read_html_toc(self, toc):
|
||||
self.base_path = os.path.dirname(toc)
|
||||
soup = BeautifulSoup(open(toc, 'rb').read(), convertEntities=BeautifulSoup.HTML_ENTITIES)
|
||||
@ -191,13 +191,13 @@ class TOC(list):
|
||||
else:
|
||||
fragment = fragment.strip()
|
||||
href = href.strip()
|
||||
|
||||
|
||||
txt = ''.join([unicode(s).strip() for s in a.findAll(text=True)])
|
||||
add = True
|
||||
for i in self.flat():
|
||||
if i.href == href and i.fragment == fragment:
|
||||
add = False
|
||||
break
|
||||
break
|
||||
if add:
|
||||
self.add_item(href, fragment, txt)
|
||||
|
||||
@ -208,4 +208,4 @@ class TOC(list):
|
||||
template = MarkupTemplate(ncx_template)
|
||||
raw = template.generate(uid=uid, toc=self, __appname__=__appname__)
|
||||
raw = raw.render(doctype=doctype)
|
||||
stream.write(raw)
|
||||
stream.write(raw)
|
||||
|
@ -263,7 +263,7 @@ class EmailAccounts(QAbstractTableModel):
|
||||
|
||||
def remove(self, index):
|
||||
if index.isValid():
|
||||
row = self.index.row()
|
||||
row = index.row()
|
||||
account = self.account_order[row]
|
||||
self.accounts.pop(account)
|
||||
self.account_order = sorted(self.accounts.keys())
|
||||
@ -425,6 +425,8 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
||||
self.email_view.resizeColumnsToContents()
|
||||
self.connect(self.test_email_button, SIGNAL('clicked(bool)'),
|
||||
self.test_email)
|
||||
self.connect(self.email_remove, SIGNAL('clicked()'),
|
||||
self.remove_email_account)
|
||||
|
||||
def add_email_account(self, checked):
|
||||
index = self._email_accounts.add()
|
||||
@ -432,6 +434,10 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
||||
self.email_view.resizeColumnsToContents()
|
||||
self.email_view.edit(index)
|
||||
|
||||
def remove_email_account(self, *args):
|
||||
idx = self.email_view.currentIndex()
|
||||
self._email_accounts.remove(idx)
|
||||
|
||||
def create_gmail_relay(self, *args):
|
||||
self.relay_username.setText('@gmail.com')
|
||||
self.relay_password.setText('')
|
||||
|
@ -727,7 +727,7 @@
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>200</number>
|
||||
<number>250</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>20</number>
|
||||
@ -750,7 +750,7 @@
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>200</number>
|
||||
<number>250</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>20</number>
|
||||
@ -773,7 +773,7 @@
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>200</number>
|
||||
<number>250</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>10</number>
|
||||
@ -796,7 +796,7 @@
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>200</number>
|
||||
<number>250</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>0</number>
|
||||
|
BIN
src/calibre/gui2/images/news/laprensa_ni.png
Normal file
BIN
src/calibre/gui2/images/news/laprensa_ni.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 638 B |
@ -6,7 +6,7 @@ from PyQt4.QtCore import Qt, QByteArray, SIGNAL
|
||||
from PyQt4.QtGui import QGraphicsRectItem, QGraphicsScene, QPen, \
|
||||
QBrush, QColor, QFontDatabase, \
|
||||
QGraphicsItem, QGraphicsLineItem
|
||||
|
||||
|
||||
from calibre.gui2.lrf_renderer.text import TextBlock, FontLoader, COLOR, PixmapItem
|
||||
|
||||
|
||||
@ -25,17 +25,17 @@ class Pen(QPen):
|
||||
|
||||
|
||||
class ContentObject(object):
|
||||
|
||||
|
||||
has_content = True
|
||||
|
||||
|
||||
def reset(self):
|
||||
self.has_content = True
|
||||
|
||||
|
||||
class RuledLine(QGraphicsLineItem, ContentObject):
|
||||
|
||||
|
||||
map = {'solid': Qt.SolidLine, 'dashed': Qt.DashLine, 'dotted': Qt.DotLine, 'double': Qt.DashDotLine}
|
||||
|
||||
|
||||
def __init__(self, rl):
|
||||
QGraphicsLineItem.__init__(self, 0, 0, rl.linelength, 0)
|
||||
ContentObject.__init__(self)
|
||||
@ -43,7 +43,7 @@ class RuledLine(QGraphicsLineItem, ContentObject):
|
||||
|
||||
|
||||
class ImageBlock(PixmapItem, ContentObject):
|
||||
|
||||
|
||||
def __init__(self, obj):
|
||||
ContentObject.__init__(self)
|
||||
x0, y0, x1, y1 = obj.attrs['x0'], obj.attrs['y0'], obj.attrs['x1'], obj.attrs['y1']
|
||||
@ -51,26 +51,26 @@ class ImageBlock(PixmapItem, ContentObject):
|
||||
data, encoding = refstream.stream, refstream.encoding
|
||||
PixmapItem.__init__(self, data, encoding, x0, y0, x1, y1, xsize, ysize)
|
||||
self.block_id = obj.id
|
||||
|
||||
|
||||
|
||||
def object_factory(container, obj, respect_max_y=False):
|
||||
if hasattr(obj, 'name'):
|
||||
if obj.name.endswith('TextBlock'):
|
||||
|
||||
|
||||
return TextBlock(obj, container.font_loader, respect_max_y, container.text_width,
|
||||
container.logger, container.opts, container.ruby_tags,
|
||||
container.logger, container.opts, container.ruby_tags,
|
||||
container.link_activated)
|
||||
elif obj.name.endswith('ImageBlock'):
|
||||
return ImageBlock(obj)
|
||||
elif isinstance(obj, _RuledLine):
|
||||
return RuledLine(obj)
|
||||
elif isinstance(obj, __Canvas):
|
||||
return Canvas(container.font_loader, obj, container.logger, container.opts,
|
||||
container.ruby_tags, container.link_activated)
|
||||
return None
|
||||
return Canvas(container.font_loader, obj, container.logger, container.opts,
|
||||
container.ruby_tags, container.link_activated)
|
||||
return None
|
||||
|
||||
class _Canvas(QGraphicsRectItem):
|
||||
|
||||
|
||||
def __init__(self, font_loader, logger, opts, width=0, height=0, parent=None, x=0, y=0):
|
||||
QGraphicsRectItem.__init__(self, x, y, width, height, parent)
|
||||
self.font_loader, self.logger, self.opts = font_loader, logger, opts
|
||||
@ -79,7 +79,7 @@ class _Canvas(QGraphicsRectItem):
|
||||
pen = QPen()
|
||||
pen.setStyle(Qt.NoPen)
|
||||
self.setPen(pen)
|
||||
|
||||
|
||||
def layout_block(self, block, x, y):
|
||||
if isinstance(block, TextBlock):
|
||||
self.layout_text_block(block, x, y)
|
||||
@ -89,17 +89,17 @@ class _Canvas(QGraphicsRectItem):
|
||||
self.layout_image_block(block, x, y)
|
||||
elif isinstance(block, Canvas):
|
||||
self.layout_canvas(block, x, y)
|
||||
|
||||
|
||||
def layout_canvas(self, canvas, x, y):
|
||||
if canvas.max_y + y > self.max_y and y > 0:
|
||||
self.is_full = True
|
||||
return
|
||||
return
|
||||
canvas.setParentItem(self)
|
||||
canvas.setPos(x, y)
|
||||
canvas.has_content = False
|
||||
canvas.put_objects()
|
||||
self.current_y += canvas.max_y
|
||||
|
||||
|
||||
def layout_text_block(self, block, x, y):
|
||||
textwidth = block.bs.blockwidth - block.bs.sidemargin
|
||||
if block.max_y == 0 or not block.lines: # Empty block skipping
|
||||
@ -128,15 +128,15 @@ class _Canvas(QGraphicsRectItem):
|
||||
line = block.peek()
|
||||
self.current_y = y
|
||||
self.is_full = not block_consumed
|
||||
|
||||
|
||||
def layout_ruled_line(self, rl, x, y):
|
||||
br = rl.boundingRect()
|
||||
rl.setParentItem(self)
|
||||
rl.setPos(x, y+1)
|
||||
self.current_y = y + br.height() + 1
|
||||
self.is_full = y > self.max_y-5
|
||||
rl.has_content = False
|
||||
|
||||
rl.has_content = False
|
||||
|
||||
def layout_image_block(self, ib, x, y):
|
||||
mw, mh = self.max_x - x, self.max_y - y
|
||||
if self.current_y + ib.height > self.max_y-y and self.current_y > 5:
|
||||
@ -161,8 +161,8 @@ class _Canvas(QGraphicsRectItem):
|
||||
print
|
||||
print ib.block_id, ib.has_content, self.is_full
|
||||
print self.current_y, self.max_y, y, br.height()
|
||||
print
|
||||
|
||||
print
|
||||
|
||||
def search(self, phrase):
|
||||
matches = []
|
||||
for child in self.children():
|
||||
@ -174,11 +174,11 @@ class _Canvas(QGraphicsRectItem):
|
||||
else:
|
||||
matches.append(res)
|
||||
return matches
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Canvas(_Canvas, ContentObject):
|
||||
|
||||
|
||||
def __init__(self, font_loader, canvas, logger, opts, ruby_tags, link_activated, width=0, height=0):
|
||||
if hasattr(canvas, 'canvaswidth'):
|
||||
width, height = canvas.canvaswidth, canvas.canvasheight
|
||||
@ -198,11 +198,11 @@ class Canvas(_Canvas, ContentObject):
|
||||
item = object_factory(self, obj, respect_max_y=True)
|
||||
if item:
|
||||
self.items.append((item, po.x1, po.y1))
|
||||
|
||||
|
||||
def put_objects(self):
|
||||
for block, x, y in self.items:
|
||||
self.layout_block(block, x, y)
|
||||
|
||||
|
||||
def layout_block(self, block, x, y):
|
||||
block.reset()
|
||||
_Canvas.layout_block(self, block, x, y)
|
||||
@ -212,17 +212,17 @@ class Header(Canvas):
|
||||
Canvas.__init__(self, font_loader, header, logger, opts, ruby_tags, link_activated,
|
||||
page_style.textwidth, page_style.headheight)
|
||||
if opts.visual_debug:
|
||||
self.setPen(QPen(Qt.blue, 1, Qt.DashLine))
|
||||
self.setPen(QPen(Qt.blue, 1, Qt.DashLine))
|
||||
|
||||
class Footer(Canvas):
|
||||
def __init__(self, font_loader, footer, page_style, logger, opts, ruby_tags, link_activated):
|
||||
Canvas.__init__(self, font_loader, footer, logger, opts, ruby_tags, link_activated,
|
||||
page_style.textwidth, page_style.footheight)
|
||||
if opts.visual_debug:
|
||||
self.setPen(QPen(Qt.blue, 1, Qt.DashLine))
|
||||
self.setPen(QPen(Qt.blue, 1, Qt.DashLine))
|
||||
|
||||
class Screen(_Canvas):
|
||||
|
||||
|
||||
def __init__(self, font_loader, chapter, odd, logger, opts, ruby_tags, link_activated):
|
||||
self.logger, self.opts = logger, opts
|
||||
page_style = chapter.style
|
||||
@ -231,11 +231,11 @@ class Screen(_Canvas):
|
||||
self.content_x = 0 + sidemargin
|
||||
self.text_width = page_style.textwidth
|
||||
self.header_y = page_style.topmargin
|
||||
|
||||
|
||||
self.text_y = self.header_y + page_style.headheight + page_style.headsep
|
||||
self.text_height = page_style.textheight
|
||||
self.footer_y = self.text_y + self.text_height + (page_style.footspace - page_style.footheight)
|
||||
|
||||
|
||||
_Canvas.__init__(self, font_loader, logger, opts, width=width, height=self.footer_y+page_style.footheight)
|
||||
if opts.visual_debug:
|
||||
self.setPen(QPen(Qt.red, 1, Qt.SolidLine))
|
||||
@ -256,57 +256,57 @@ class Screen(_Canvas):
|
||||
if footer:
|
||||
footer = Footer(font_loader, footer, page_style, logger, opts, ruby_tags, link_activated)
|
||||
self.layout_canvas(footer, self.content_x, self.header_y)
|
||||
|
||||
|
||||
self.page = None
|
||||
|
||||
|
||||
def set_page(self, page):
|
||||
if self.page is not None and self.page.scene():
|
||||
self.scene().removeItem(self.page)
|
||||
self.scene().removeItem(self.page)
|
||||
self.page = page
|
||||
self.page.setPos(self.content_x, self.text_y)
|
||||
self.scene().addItem(self.page)
|
||||
|
||||
|
||||
def remove(self):
|
||||
if self.scene():
|
||||
if self.page is not None and self.page.scene():
|
||||
self.scene().removeItem(self.page)
|
||||
self.scene().removeItem(self)
|
||||
|
||||
|
||||
|
||||
|
||||
class Page(_Canvas):
|
||||
|
||||
|
||||
def __init__(self, font_loader, logger, opts, width, height):
|
||||
_Canvas.__init__(self, font_loader, logger, opts, width, height)
|
||||
if opts.visual_debug:
|
||||
self.setPen(QPen(Qt.cyan, 1, Qt.DashLine))
|
||||
|
||||
|
||||
def id(self):
|
||||
for child in self.children():
|
||||
if hasattr(child, 'block_id'):
|
||||
return child.block_id
|
||||
|
||||
|
||||
def add_block(self, block):
|
||||
self.layout_block(block, 0, self.current_y)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Chapter(object):
|
||||
|
||||
|
||||
num_of_pages = property(fget=lambda self: len(self.pages))
|
||||
|
||||
|
||||
def __init__(self, oddscreen, evenscreen, pages, object_to_page_map):
|
||||
self.oddscreen, self.evenscreen, self.pages, self.object_to_page_map = \
|
||||
oddscreen, evenscreen, pages, object_to_page_map
|
||||
|
||||
|
||||
def page_of_object(self, id):
|
||||
return self.object_to_page_map[id]
|
||||
|
||||
|
||||
def page(self, num):
|
||||
return self.pages[num-1]
|
||||
|
||||
|
||||
def screen(self, odd):
|
||||
return self.oddscreen if odd else self.evenscreen
|
||||
|
||||
|
||||
def search(self, phrase):
|
||||
pages = []
|
||||
for i in range(len(self.pages)):
|
||||
@ -314,36 +314,36 @@ class Chapter(object):
|
||||
if matches:
|
||||
pages.append([i, matches])
|
||||
return pages
|
||||
|
||||
|
||||
|
||||
class History(collections.deque):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
collections.deque.__init__(self)
|
||||
self.pos = 0
|
||||
|
||||
|
||||
def back(self):
|
||||
if self.pos - 1 < 0: return None
|
||||
self.pos -= 1
|
||||
return self[self.pos]
|
||||
|
||||
|
||||
def forward(self):
|
||||
if self.pos + 1 >= len(self): return None
|
||||
self.pos += 1
|
||||
return self[self.pos]
|
||||
|
||||
|
||||
def add(self, item):
|
||||
while len(self) > self.pos+1:
|
||||
self.pop()
|
||||
self.append(item)
|
||||
self.pos += 1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Document(QGraphicsScene):
|
||||
|
||||
|
||||
num_of_pages = property(fget=lambda self: sum(self.chapter_layout))
|
||||
|
||||
|
||||
def __init__(self, logger, opts):
|
||||
QGraphicsScene.__init__(self)
|
||||
self.logger, self.opts = logger, opts
|
||||
@ -358,23 +358,23 @@ class Document(QGraphicsScene):
|
||||
self.last_search = iter([])
|
||||
if not opts.white_background:
|
||||
self.setBackgroundBrush(QBrush(QColor(0xee, 0xee, 0xee)))
|
||||
|
||||
|
||||
def page_of(self, oid):
|
||||
for chapter in self.chapters:
|
||||
if oid in chapter.object_to_page_map:
|
||||
return chapter.object_to_page_map[oid]
|
||||
|
||||
|
||||
def get_page_num(self, chapterid, objid):
|
||||
cnum = self.chapter_map[chapterid]
|
||||
page = self.chapters[cnum].object_to_page_map[objid]
|
||||
return sum(self.chapter_layout[:cnum])+page
|
||||
|
||||
|
||||
def add_to_history(self):
|
||||
page = self.chapter_page(self.current_page)[1]
|
||||
page_id = page.id()
|
||||
if page_id is not None:
|
||||
self.history.add(page_id)
|
||||
|
||||
|
||||
def link_activated(self, objid, on_creation=None):
|
||||
if on_creation is None:
|
||||
cid, oid = self.link_map[objid]
|
||||
@ -385,30 +385,30 @@ class Document(QGraphicsScene):
|
||||
else:
|
||||
jb = self.objects[objid]
|
||||
self.link_map[objid] = (jb.refpage, jb.refobj)
|
||||
|
||||
|
||||
|
||||
|
||||
def back(self):
|
||||
oid = self.history.back()
|
||||
if oid is not None:
|
||||
page = self.page_of(oid)
|
||||
self.show_page(page)
|
||||
|
||||
|
||||
def forward(self):
|
||||
oid = self.history.forward()
|
||||
if oid is not None:
|
||||
page = self.page_of(oid)
|
||||
self.show_page(page)
|
||||
|
||||
|
||||
|
||||
|
||||
def load_fonts(self, lrf, load_substitutions=True):
|
||||
font_map = {}
|
||||
|
||||
|
||||
for font in lrf.font_map:
|
||||
fdata = QByteArray(lrf.font_map[font].data)
|
||||
id = QFontDatabase.addApplicationFontFromData(fdata)
|
||||
if id != -1:
|
||||
font_map[font] = [str(i) for i in QFontDatabase.applicationFontFamilies(id)][0]
|
||||
|
||||
|
||||
if load_substitutions:
|
||||
from calibre.ebooks.lrf.fonts.liberation import LiberationMono_BoldItalic
|
||||
QFontDatabase.addApplicationFontFromData(QByteArray(LiberationMono_BoldItalic.font_data))
|
||||
@ -434,10 +434,10 @@ class Document(QGraphicsScene):
|
||||
QFontDatabase.addApplicationFontFromData(QByteArray(LiberationSerif_BoldItalic.font_data))
|
||||
from calibre.ebooks.lrf.fonts.liberation import LiberationSans_Regular
|
||||
QFontDatabase.addApplicationFontFromData(QByteArray(LiberationSans_Regular.font_data))
|
||||
|
||||
|
||||
self.font_loader = FontLoader(font_map, self.dpi)
|
||||
|
||||
|
||||
|
||||
|
||||
def render_chapter(self, chapter, lrf):
|
||||
oddscreen, evenscreen = Screen(self.font_loader, chapter, True, self.logger, self.opts, self.ruby_tags, self.link_activated), \
|
||||
Screen(self.font_loader, chapter, False, self.logger, self.opts, self.ruby_tags, self.link_activated)
|
||||
@ -459,36 +459,36 @@ class Document(QGraphicsScene):
|
||||
if current_page:
|
||||
pages.append(current_page)
|
||||
self.chapters.append(Chapter(oddscreen, evenscreen, pages, object_to_page_map))
|
||||
self.chapter_map[chapter.id] = len(self.chapters)-1
|
||||
|
||||
|
||||
self.chapter_map[chapter.id] = len(self.chapters)-1
|
||||
|
||||
|
||||
def render(self, lrf, load_substitutions=True):
|
||||
self.dpi = lrf.device_info.dpi/10.
|
||||
self.ruby_tags = dict(**lrf.ruby_tags)
|
||||
self.load_fonts(lrf, load_substitutions)
|
||||
self.objects = lrf.objects
|
||||
|
||||
|
||||
num_chaps = 0
|
||||
for pt in lrf.page_trees:
|
||||
for chapter in pt:
|
||||
num_chaps += 1
|
||||
self.emit(SIGNAL('chapter_rendered(int)'), num_chaps)
|
||||
|
||||
|
||||
for pt in lrf.page_trees:
|
||||
for chapter in pt:
|
||||
self.render_chapter(chapter, lrf)
|
||||
|
||||
|
||||
self.emit(SIGNAL('chapter_rendered(int)'), -1)
|
||||
self.chapter_layout = [i.num_of_pages for i in self.chapters]
|
||||
self.objects = None
|
||||
|
||||
|
||||
def chapter_page(self, num):
|
||||
for chapter in self.chapters:
|
||||
if num <= chapter.num_of_pages:
|
||||
break
|
||||
num -= chapter.num_of_pages
|
||||
return chapter, chapter.page(num)
|
||||
|
||||
|
||||
def show_page(self, num):
|
||||
if num < 1 or num > self.num_of_pages or num == self.current_page:
|
||||
return
|
||||
@ -496,33 +496,33 @@ class Document(QGraphicsScene):
|
||||
self.current_page = num
|
||||
chapter, page = self.chapter_page(num)
|
||||
screen = chapter.screen(odd)
|
||||
|
||||
|
||||
if self.current_screen is not None and self.current_screen is not screen:
|
||||
self.current_screen.remove()
|
||||
self.current_screen = screen
|
||||
if self.current_screen.scene() is None:
|
||||
self.addItem(self.current_screen)
|
||||
|
||||
|
||||
self.current_screen.set_page(page)
|
||||
self.emit(SIGNAL('page_changed(PyQt_PyObject)'), self.current_page)
|
||||
|
||||
|
||||
|
||||
|
||||
def next(self):
|
||||
self.next_by(1)
|
||||
|
||||
|
||||
def previous(self):
|
||||
self.previous_by(1)
|
||||
|
||||
|
||||
def next_by(self, num):
|
||||
self.show_page(self.current_page + num)
|
||||
|
||||
|
||||
def previous_by(self, num):
|
||||
self.show_page(self.current_page - num)
|
||||
|
||||
|
||||
def show_page_at_percent(self, p):
|
||||
num = self.num_of_pages*(p/100.)
|
||||
self.show_page(num)
|
||||
|
||||
|
||||
def search(self, phrase):
|
||||
if not phrase:
|
||||
return
|
||||
@ -534,7 +534,7 @@ class Document(QGraphicsScene):
|
||||
matches += cmatches
|
||||
self.last_search = itertools.cycle(matches)
|
||||
self.next_match()
|
||||
|
||||
|
||||
def next_match(self):
|
||||
page_num = self.last_search.next()[0]
|
||||
if self.current_page == page_num:
|
||||
@ -542,4 +542,4 @@ class Document(QGraphicsScene):
|
||||
else:
|
||||
self.add_to_history()
|
||||
self.show_page(page_num)
|
||||
|
||||
|
||||
|
@ -52,29 +52,29 @@ def config(defaults=None):
|
||||
c = Config('viewer', desc)
|
||||
else:
|
||||
c = StringConfig(defaults, desc)
|
||||
|
||||
|
||||
c.add_opt('user_css', default='',
|
||||
help=_('Set the user CSS stylesheet. This can be used to customize the look of all books.'))
|
||||
|
||||
|
||||
fonts = c.add_group('FONTS', _('Font options'))
|
||||
fonts('serif_family', default='Times New Roman' if iswindows else 'Liberation Serif',
|
||||
fonts('serif_family', default='Times New Roman' if iswindows else 'Liberation Serif',
|
||||
help=_('The serif font family'))
|
||||
fonts('sans_family', default='Verdana' if iswindows else 'Liberation Sans',
|
||||
fonts('sans_family', default='Verdana' if iswindows else 'Liberation Sans',
|
||||
help=_('The sans-serif font family'))
|
||||
fonts('mono_family', default='Courier New' if iswindows else 'Liberation Mono',
|
||||
fonts('mono_family', default='Courier New' if iswindows else 'Liberation Mono',
|
||||
help=_('The monospaced font family'))
|
||||
fonts('default_font_size', default=20, help=_('The standard font size in px'))
|
||||
fonts('mono_font_size', default=16, help=_('The monospaced font size in px'))
|
||||
fonts('standard_font', default='serif', help=_('The standard font type'))
|
||||
|
||||
|
||||
return c
|
||||
|
||||
class ConfigDialog(QDialog, Ui_Dialog):
|
||||
|
||||
|
||||
def __init__(self, *args):
|
||||
QDialog.__init__(self, *args)
|
||||
self.setupUi(self)
|
||||
|
||||
|
||||
opts = config().parse()
|
||||
self.serif_family.setCurrentFont(QFont(opts.serif_family))
|
||||
self.sans_family.setCurrentFont(QFont(opts.sans_family))
|
||||
@ -84,7 +84,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
||||
self.standard_font.setCurrentIndex({'serif':0, 'sans':1, 'mono':2}[opts.standard_font])
|
||||
self.css.setPlainText(opts.user_css)
|
||||
self.css.setToolTip(_('Set the user CSS stylesheet. This can be used to customize the look of all books.'))
|
||||
|
||||
|
||||
def accept(self, *args):
|
||||
c = config()
|
||||
c.set('serif_family', unicode(self.serif_family.currentFont().family()))
|
||||
@ -95,10 +95,10 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
||||
c.set('standard_font', {0:'serif', 1:'sans', 2:'mono'}[self.standard_font.currentIndex()])
|
||||
c.set('user_css', unicode(self.css.toPlainText()))
|
||||
return QDialog.accept(self, *args)
|
||||
|
||||
|
||||
|
||||
class Document(QWebPage):
|
||||
|
||||
|
||||
def set_font_settings(self):
|
||||
opts = config().parse()
|
||||
settings = self.settings()
|
||||
@ -110,14 +110,14 @@ class Document(QWebPage):
|
||||
settings.setFontFamily(QWebSettings.SerifFont, opts.serif_family)
|
||||
settings.setFontFamily(QWebSettings.SansSerifFont, opts.sans_family)
|
||||
settings.setFontFamily(QWebSettings.FixedFont, opts.mono_family)
|
||||
|
||||
|
||||
def do_config(self, parent=None):
|
||||
d = ConfigDialog(parent)
|
||||
if d.exec_() == QDialog.Accepted:
|
||||
self.set_font_settings()
|
||||
self.set_user_stylesheet()
|
||||
self.triggerAction(QWebPage.Reload)
|
||||
|
||||
|
||||
def __init__(self, *args):
|
||||
QWebPage.__init__(self, *args)
|
||||
self.setLinkDelegationPolicy(self.DelegateAllLinks)
|
||||
@ -125,53 +125,53 @@ class Document(QWebPage):
|
||||
pal = self.palette()
|
||||
pal.setBrush(QPalette.Background, QColor(0xee, 0xee, 0xee))
|
||||
self.setPalette(pal)
|
||||
|
||||
|
||||
settings = self.settings()
|
||||
|
||||
|
||||
# Fonts
|
||||
load_builtin_fonts()
|
||||
self.set_font_settings()
|
||||
|
||||
|
||||
# Security
|
||||
settings.setAttribute(QWebSettings.JavaEnabled, False)
|
||||
settings.setAttribute(QWebSettings.PluginsEnabled, False)
|
||||
settings.setAttribute(QWebSettings.JavascriptCanOpenWindows, False)
|
||||
settings.setAttribute(QWebSettings.JavascriptCanAccessClipboard, False)
|
||||
|
||||
|
||||
# Miscellaneous
|
||||
settings.setAttribute(QWebSettings.LinksIncludedInFocusChain, True)
|
||||
self.set_user_stylesheet()
|
||||
|
||||
|
||||
# Load jQuery
|
||||
self.connect(self.mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'),
|
||||
self.connect(self.mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'),
|
||||
self.load_javascript_libraries)
|
||||
|
||||
|
||||
def set_user_stylesheet(self):
|
||||
raw = config().parse().user_css
|
||||
pt = PersistentTemporaryFile('_user_stylesheet.css')
|
||||
pt.write(raw.encode('utf-8'))
|
||||
pt.close()
|
||||
self.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(pt.name))
|
||||
|
||||
|
||||
def load_javascript_libraries(self):
|
||||
from calibre.resources import jquery, jquery_scrollTo
|
||||
self.javascript(jquery)
|
||||
self.javascript(jquery_scrollTo)
|
||||
self.javascript(bookmarks)
|
||||
self.javascript(referencing)
|
||||
|
||||
|
||||
def reference_mode(self, enable):
|
||||
self.javascript(('enter' if enable else 'leave')+'_reference_mode()')
|
||||
|
||||
|
||||
def set_reference_prefix(self, prefix):
|
||||
self.javascript('reference_prefix = "%s"'%prefix)
|
||||
|
||||
|
||||
def goto(self, ref):
|
||||
self.javascript('goto_reference("%s")'%ref)
|
||||
|
||||
|
||||
def goto_bookmark(self, bm):
|
||||
self.javascript('scroll_to_bookmark("%s")'%bm)
|
||||
|
||||
|
||||
def javascript(self, string, typ=None):
|
||||
ans = self.mainFrame().evaluateJavaScript(string)
|
||||
if typ == 'int':
|
||||
@ -182,65 +182,65 @@ class Document(QWebPage):
|
||||
if typ == 'string':
|
||||
return unicode(ans.toString())
|
||||
return ans
|
||||
|
||||
|
||||
def scroll_by(self, x=0, y=0):
|
||||
self.javascript('window.scrollBy(%d, %d)'%(x, y))
|
||||
|
||||
|
||||
def scroll_to(self, x=0, y=0):
|
||||
self.javascript('window.scrollTo(%d, %d)'%(x, y))
|
||||
|
||||
|
||||
def jump_to_anchor(self, anchor):
|
||||
self.javascript('document.location.hash = "%s"'%anchor)
|
||||
|
||||
|
||||
def quantize(self):
|
||||
if self.height > self.window_height:
|
||||
r = self.height%self.window_height
|
||||
if r > 0:
|
||||
self.javascript('document.body.style.paddingBottom = "%dpx"'%r)
|
||||
|
||||
|
||||
def bookmark(self):
|
||||
return self.javascript('calculate_bookmark(%d)'%(self.ypos+25), 'string')
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def at_bottom(self):
|
||||
def fget(self):
|
||||
return self.height - self.ypos <= self.window_height
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def at_top(self):
|
||||
def fget(self):
|
||||
return self.ypos <= 0
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
|
||||
|
||||
def test(self):
|
||||
pass
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def ypos(self):
|
||||
def fget(self):
|
||||
return self.javascript('window.pageYOffset', 'int')
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def window_height(self):
|
||||
def fget(self):
|
||||
return self.javascript('window.innerHeight', 'int')
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def window_width(self):
|
||||
def fget(self):
|
||||
return self.javascript('window.innerWidth', 'int')
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def xpos(self):
|
||||
def fget(self):
|
||||
return self.javascript('window.pageXOffset', 'int')
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def scroll_fraction(self):
|
||||
def fget(self):
|
||||
@ -249,19 +249,19 @@ class Document(QWebPage):
|
||||
except ZeroDivisionError:
|
||||
return 0.
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def hscroll_fraction(self):
|
||||
def fget(self):
|
||||
return float(self.xpos)/self.width
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def height(self):
|
||||
def fget(self):
|
||||
return self.javascript('document.body.offsetHeight', 'int') # contentsSize gives inaccurate results
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def width(self):
|
||||
def fget(self):
|
||||
@ -269,7 +269,7 @@ class Document(QWebPage):
|
||||
return property(fget=fget)
|
||||
|
||||
class EntityDeclarationProcessor(object):
|
||||
|
||||
|
||||
def __init__(self, html):
|
||||
self.declared_entities = {}
|
||||
for match in re.finditer(r'<!\s*ENTITY\s+([^>]+)>', html):
|
||||
@ -281,9 +281,9 @@ class EntityDeclarationProcessor(object):
|
||||
self.processed_html = self.processed_html.replace('&%s;'%key, val)
|
||||
|
||||
class DocumentView(QWebView):
|
||||
|
||||
DISABLED_BRUSH = QBrush(Qt.lightGray, Qt.Dense5Pattern)
|
||||
|
||||
|
||||
DISABLED_BRUSH = QBrush(Qt.lightGray, Qt.Dense5Pattern)
|
||||
|
||||
def __init__(self, *args):
|
||||
QWidget.__init__(self, *args)
|
||||
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
|
||||
@ -299,83 +299,83 @@ class DocumentView(QWebView):
|
||||
self.connect(self.document, SIGNAL('linkClicked(QUrl)'), self.link_clicked)
|
||||
self.connect(self.document, SIGNAL('linkHovered(QString,QString,QString)'), self.link_hovered)
|
||||
self.connect(self.document, SIGNAL('selectionChanged()'), self.selection_changed)
|
||||
|
||||
|
||||
def reference_mode(self, enable):
|
||||
self._reference_mode = enable
|
||||
self.document.reference_mode(enable)
|
||||
|
||||
|
||||
def goto(self, ref):
|
||||
self.document.goto(ref)
|
||||
|
||||
|
||||
def goto_bookmark(self, bm):
|
||||
self.document.goto_bookmark(bm)
|
||||
|
||||
|
||||
def config(self, parent=None):
|
||||
self.document.do_config(parent)
|
||||
|
||||
|
||||
def bookmark(self):
|
||||
return self.document.bookmark()
|
||||
|
||||
|
||||
def selection_changed(self):
|
||||
if self.manager is not None:
|
||||
self.manager.selection_changed(unicode(self.document.selectedText()))
|
||||
|
||||
|
||||
def set_manager(self, manager):
|
||||
self.manager = manager
|
||||
self.scrollbar = manager.horizontal_scrollbar
|
||||
self.connect(self.scrollbar, SIGNAL('valueChanged(int)'), self.scroll_horizontally)
|
||||
|
||||
|
||||
def scroll_horizontally(self, amount):
|
||||
self.document.scroll_to(y=self.document.ypos, x=amount)
|
||||
|
||||
|
||||
def link_hovered(self, link, text, context):
|
||||
link, text = unicode(link), unicode(text)
|
||||
if link:
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
else:
|
||||
self.unsetCursor()
|
||||
|
||||
self.unsetCursor()
|
||||
|
||||
def link_clicked(self, url):
|
||||
if self.manager is not None:
|
||||
self.manager.link_clicked(url)
|
||||
|
||||
|
||||
def sizeHint(self):
|
||||
return self._size_hint
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def scroll_fraction(self):
|
||||
def fget(self):
|
||||
return self.document.scroll_fraction
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def hscroll_fraction(self):
|
||||
def fget(self):
|
||||
return self.document.hscroll_fraction
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def content_size(self):
|
||||
def fget(self):
|
||||
return self.document.width, self.document.height
|
||||
return property(fget=fget)
|
||||
|
||||
|
||||
def search(self, text):
|
||||
return self.findText(text)
|
||||
|
||||
|
||||
def path(self):
|
||||
return os.path.abspath(unicode(self.url().toLocalFile()))
|
||||
|
||||
|
||||
def load_path(self, path, pos=0.0):
|
||||
self.initial_pos = pos
|
||||
html = open(path, 'rb').read().decode(path.encoding)
|
||||
html = open(path, 'rb').read().decode(path.encoding, 'replace')
|
||||
html = EntityDeclarationProcessor(html).processed_html
|
||||
self.setHtml(html, QUrl.fromLocalFile(path))
|
||||
|
||||
|
||||
def load_started(self):
|
||||
if self.manager is not None:
|
||||
self.manager.load_started()
|
||||
|
||||
|
||||
def initialize_scrollbar(self):
|
||||
if getattr(self, 'scrollbar', None) is not None:
|
||||
delta = self.document.width - self.size().width()
|
||||
@ -387,7 +387,7 @@ class DocumentView(QWebView):
|
||||
self.scrollbar.setPageStep(int(delta/10.))
|
||||
self.scrollbar.blockSignals(False)
|
||||
self.scrollbar.setVisible(delta > 0)
|
||||
|
||||
|
||||
def load_finished(self, ok):
|
||||
self.document.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
|
||||
self.document.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
|
||||
@ -409,8 +409,8 @@ class DocumentView(QWebView):
|
||||
self.document.set_reference_prefix('%d.'%(spine_index+1))
|
||||
if scrolled:
|
||||
self.manager.scrolled(self.document.scroll_fraction)
|
||||
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def test_line(cls, img, y):
|
||||
start = img.pixel(0, y)
|
||||
@ -418,7 +418,7 @@ class DocumentView(QWebView):
|
||||
if img.pixel(i, y) != start:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def find_next_blank_line(self, overlap):
|
||||
img = QImage(self.width(), overlap, QImage.Format_ARGB32)
|
||||
painter = QPainter(img)
|
||||
@ -428,8 +428,8 @@ class DocumentView(QWebView):
|
||||
if self.test_line(img, i):
|
||||
self.scroll_by(y=i, notify=False)
|
||||
return
|
||||
self.scroll_by(y=overlap)
|
||||
|
||||
self.scroll_by(y=overlap)
|
||||
|
||||
def previous_page(self):
|
||||
if self.document.at_top:
|
||||
if self.manager is not None:
|
||||
@ -448,12 +448,12 @@ class DocumentView(QWebView):
|
||||
break
|
||||
if self.manager is not None:
|
||||
self.manager.scrolled(self.scroll_fraction)
|
||||
|
||||
|
||||
def wheel_event(self, down=True):
|
||||
QWebView.wheelEvent(self,
|
||||
QWheelEvent(QPoint(100, 100), (-120 if down else 120),
|
||||
QWebView.wheelEvent(self,
|
||||
QWheelEvent(QPoint(100, 100), (-120 if down else 120),
|
||||
Qt.NoButton, Qt.NoModifier))
|
||||
|
||||
|
||||
def next_page(self):
|
||||
if self.document.at_bottom:
|
||||
if self.manager is not None:
|
||||
@ -472,14 +472,14 @@ class DocumentView(QWebView):
|
||||
self.find_next_blank_line( self.height() - (self.document.ypos-opos) )
|
||||
if self.manager is not None:
|
||||
self.manager.scrolled(self.scroll_fraction)
|
||||
|
||||
|
||||
|
||||
|
||||
def scroll_by(self, x=0, y=0, notify=True):
|
||||
old_pos = self.document.ypos
|
||||
self.document.scroll_by(x, y)
|
||||
if notify and self.manager is not None and self.document.ypos != old_pos:
|
||||
self.manager.scrolled(self.scroll_fraction)
|
||||
|
||||
|
||||
def scroll_to(self, pos, notify=True):
|
||||
old_pos = self.document.ypos
|
||||
if isinstance(pos, basestring):
|
||||
@ -492,30 +492,30 @@ class DocumentView(QWebView):
|
||||
pos*(self.document.height-self.document.window_height))))
|
||||
if notify and self.manager is not None and self.document.ypos != old_pos:
|
||||
self.manager.scrolled(self.scroll_fraction)
|
||||
|
||||
|
||||
def multiplier(self):
|
||||
return self.document.mainFrame().textSizeMultiplier()
|
||||
|
||||
|
||||
def magnify_fonts(self):
|
||||
self.document.mainFrame().setTextSizeMultiplier(self.multiplier()+0.2)
|
||||
return self.document.scroll_fraction
|
||||
|
||||
|
||||
def shrink_fonts(self):
|
||||
self.document.mainFrame().setTextSizeMultiplier(max(self.multiplier()-0.2, 0))
|
||||
return self.document.scroll_fraction
|
||||
|
||||
|
||||
def changeEvent(self, event):
|
||||
if event.type() == event.EnabledChange:
|
||||
self.update()
|
||||
return QWebView.changeEvent(self, event)
|
||||
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
self.document.mainFrame().render(painter, event.region())
|
||||
if not self.isEnabled():
|
||||
painter.fillRect(event.region().boundingRect(), self.DISABLED_BRUSH)
|
||||
painter.end()
|
||||
|
||||
|
||||
def wheelEvent(self, event):
|
||||
if event.delta() < -14:
|
||||
if self.document.at_bottom:
|
||||
@ -533,7 +533,7 @@ class DocumentView(QWebView):
|
||||
if self.manager is not None:
|
||||
self.manager.scrolled(self.scroll_fraction)
|
||||
return ret
|
||||
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
key = event.key()
|
||||
if key in [Qt.Key_PageDown, Qt.Key_Space, Qt.Key_Down]:
|
||||
@ -562,14 +562,14 @@ class DocumentView(QWebView):
|
||||
self.scroll_by(x=15)
|
||||
else:
|
||||
return QWebView.keyPressEvent(self, event)
|
||||
|
||||
|
||||
def resizeEvent(self, event):
|
||||
ret = QWebView.resizeEvent(self, event)
|
||||
QTimer.singleShot(10, self.initialize_scrollbar)
|
||||
if self.manager is not None:
|
||||
self.manager.viewport_resized(self.scroll_fraction)
|
||||
return ret
|
||||
|
||||
|
||||
def mouseReleaseEvent(self, ev):
|
||||
opos = self.document.ypos
|
||||
ret = QWebView.mouseReleaseEvent(self, ev)
|
||||
@ -578,4 +578,4 @@ class DocumentView(QWebView):
|
||||
self.manager.scrolled(self.scroll_fraction)
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ function find_enclosing_block(y) {
|
||||
if (min != 0 && min.height() < 200) break;
|
||||
}
|
||||
if (y <= 0) return document.body;
|
||||
if (min == 0) { return find_enclosing_block(x, y-20); }
|
||||
if (min == 0) { return find_enclosing_block(y-20); }
|
||||
return min;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ function enter_reference_mode() {
|
||||
}
|
||||
|
||||
function leave_reference_mode() {
|
||||
$("p").unbind("mouseenter mouseleave", toggle_reference);
|
||||
$("p").unbind("mouseenter mouseleave", toggle_reference);
|
||||
}
|
||||
|
||||
function goto_reference(ref) {
|
||||
@ -118,4 +118,4 @@ $(document.body).click(function(e) {
|
||||
|
||||
$(document).ready(enter_reference_mode);
|
||||
|
||||
'''
|
||||
'''
|
||||
|
@ -27,7 +27,7 @@ from calibre.gui2.library import SearchBox
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
|
||||
class TOCItem(QStandardItem):
|
||||
|
||||
|
||||
def __init__(self, toc):
|
||||
QStandardItem.__init__(self, toc.text if toc.text else '')
|
||||
self.abspath = toc.abspath
|
||||
@ -35,23 +35,23 @@ class TOCItem(QStandardItem):
|
||||
for t in toc:
|
||||
self.appendRow(TOCItem(t))
|
||||
self.setFlags(Qt.ItemIsEnabled|Qt.ItemIsSelectable)
|
||||
|
||||
|
||||
@classmethod
|
||||
def type(cls):
|
||||
return QStandardItem.UserType+10
|
||||
|
||||
class TOC(QStandardItemModel):
|
||||
|
||||
|
||||
def __init__(self, toc):
|
||||
QStandardItemModel.__init__(self)
|
||||
for t in toc:
|
||||
self.appendRow(TOCItem(t))
|
||||
self.setHorizontalHeaderItem(0, QStandardItem(_('Table of Contents')))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Worker(Thread):
|
||||
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
Thread.run(self)
|
||||
@ -61,7 +61,7 @@ class Worker(Thread):
|
||||
self.traceback = traceback.format_exc()
|
||||
|
||||
class ProgressIndicator(QWidget):
|
||||
|
||||
|
||||
def __init__(self, *args):
|
||||
QWidget.__init__(self, *args)
|
||||
self.setGeometry(0, 0, 300, 500)
|
||||
@ -76,7 +76,7 @@ class ProgressIndicator(QWidget):
|
||||
self.status.font().setBold(True)
|
||||
self.status.font().setPointSize(self.font().pointSize()+6)
|
||||
self.setVisible(False)
|
||||
|
||||
|
||||
def start(self, msg=''):
|
||||
view = self.parent()
|
||||
pwidth, pheight = view.size().width(), view.size().height()
|
||||
@ -89,25 +89,25 @@ class ProgressIndicator(QWidget):
|
||||
self.status.setText(msg)
|
||||
self.setVisible(True)
|
||||
self.movie.setPaused(False)
|
||||
|
||||
|
||||
def stop(self):
|
||||
if self.movie.state() == self.movie.Running:
|
||||
self.movie.setPaused(True)
|
||||
self.setVisible(False)
|
||||
|
||||
class History(collections.deque):
|
||||
|
||||
|
||||
def __init__(self, action_back, action_forward):
|
||||
self.action_back = action_back
|
||||
self.action_forward = action_forward
|
||||
collections.deque.__init__(self)
|
||||
self.pos = 0
|
||||
self.set_actions()
|
||||
|
||||
|
||||
def set_actions(self):
|
||||
self.action_back.setDisabled(self.pos < 1)
|
||||
self.action_forward.setDisabled(self.pos + 1 >= len(self))
|
||||
|
||||
|
||||
def back(self, from_pos):
|
||||
if self.pos - 1 < 0: return None
|
||||
if self.pos == len(self):
|
||||
@ -116,56 +116,56 @@ class History(collections.deque):
|
||||
self.pos -= 1
|
||||
self.set_actions()
|
||||
return self[self.pos]
|
||||
|
||||
|
||||
def forward(self):
|
||||
if self.pos + 1 >= len(self): return None
|
||||
self.pos += 1
|
||||
self.set_actions()
|
||||
return self[self.pos]
|
||||
|
||||
|
||||
def add(self, item):
|
||||
while len(self) > self.pos+1:
|
||||
self.pop()
|
||||
self.append(item)
|
||||
self.pos += 1
|
||||
self.set_actions()
|
||||
|
||||
|
||||
class Metadata(QLabel):
|
||||
|
||||
|
||||
def __init__(self, parent):
|
||||
QTextBrowser.__init__(self, parent.centralWidget())
|
||||
self.view = parent.splitter
|
||||
self.setGeometry(self.view.geometry())
|
||||
self.setWordWrap(True)
|
||||
self.setVisible(False)
|
||||
|
||||
|
||||
def show_opf(self, opf):
|
||||
mi = MetaInformation(opf)
|
||||
html = '<h2 align="center">%s</h2>%s'%(_('Metadata'), u''.join(mi.to_html()))
|
||||
self.setText(html)
|
||||
|
||||
|
||||
def setVisible(self, x):
|
||||
self.setGeometry(self.view.geometry())
|
||||
QLabel.setVisible(self, x)
|
||||
|
||||
|
||||
def paintEvent(self, ev):
|
||||
p = QPainter(self)
|
||||
p.fillRect(ev.region().boundingRect(), QBrush(QColor(200, 200, 200, 220), Qt.SolidPattern))
|
||||
p.end()
|
||||
QLabel.paintEvent(self, ev)
|
||||
|
||||
|
||||
|
||||
|
||||
class DoubleSpinBox(QDoubleSpinBox):
|
||||
|
||||
|
||||
def set_value(self, val):
|
||||
self.blockSignals(True)
|
||||
self.setValue(val)
|
||||
self.blockSignals(False)
|
||||
|
||||
class HelpfulLineEdit(QLineEdit):
|
||||
|
||||
|
||||
HELP_TEXT = _('Go to...')
|
||||
|
||||
|
||||
def __init__(self, *args):
|
||||
QLineEdit.__init__(self, *args)
|
||||
self.default_palette = QApplication.palette(self)
|
||||
@ -174,22 +174,22 @@ class HelpfulLineEdit(QLineEdit):
|
||||
self.connect(self, SIGNAL('editingFinished()'),
|
||||
lambda : self.emit(SIGNAL('goto(PyQt_PyObject)'), unicode(self.text())))
|
||||
self.clear_to_help_mode()
|
||||
|
||||
|
||||
def focusInEvent(self, ev):
|
||||
self.setPalette(QApplication.palette(self))
|
||||
if self.in_help_mode():
|
||||
self.setText('')
|
||||
return QLineEdit.focusInEvent(self, ev)
|
||||
|
||||
|
||||
def in_help_mode(self):
|
||||
return unicode(self.text()) == self.HELP_TEXT
|
||||
|
||||
|
||||
def clear_to_help_mode(self):
|
||||
self.setPalette(self.gray)
|
||||
self.setText(self.HELP_TEXT)
|
||||
|
||||
|
||||
class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
|
||||
|
||||
def __init__(self, pathtoebook=None):
|
||||
MainWindow.__init__(self, None)
|
||||
self.setupUi(self)
|
||||
@ -224,14 +224,14 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.action_quit = QAction(self)
|
||||
self.addAction(self.action_quit)
|
||||
self.action_quit.setShortcut(Qt.CTRL+Qt.Key_Q)
|
||||
self.connect(self.action_quit, SIGNAL('triggered(bool)'),
|
||||
self.connect(self.action_quit, SIGNAL('triggered(bool)'),
|
||||
lambda x:QApplication.instance().quit())
|
||||
self.action_copy.setDisabled(True)
|
||||
self.action_metadata.setCheckable(True)
|
||||
self.action_metadata.setShortcut(Qt.CTRL+Qt.Key_I)
|
||||
self.action_table_of_contents.setCheckable(True)
|
||||
self.action_reference_mode.setCheckable(True)
|
||||
self.connect(self.action_reference_mode, SIGNAL('triggered(bool)'),
|
||||
self.connect(self.action_reference_mode, SIGNAL('triggered(bool)'),
|
||||
lambda x: self.view.reference_mode(x))
|
||||
self.connect(self.action_metadata, SIGNAL('triggered(bool)'), lambda x:self.metadata.setVisible(x))
|
||||
self.connect(self.action_table_of_contents, SIGNAL('triggered(bool)'), lambda x:self.toc.setVisible(x))
|
||||
@ -246,7 +246,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
lambda x:self.view.next_page())
|
||||
self.connect(self.action_previous_page, SIGNAL('triggered(bool)'),
|
||||
lambda x:self.view.previous_page())
|
||||
self.connect(self.action_find_next, SIGNAL('triggered(bool)'),
|
||||
self.connect(self.action_find_next, SIGNAL('triggered(bool)'),
|
||||
lambda x:self.find(unicode(self.search.text()), True, repeat=True))
|
||||
self.connect(self.action_full_screen, SIGNAL('triggered(bool)'),
|
||||
self.toggle_fullscreen)
|
||||
@ -256,17 +256,16 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.connect(self.action_forward, SIGNAL('triggered(bool)'), self.forward)
|
||||
self.connect(self.action_preferences, SIGNAL('triggered(bool)'), lambda x: self.view.config(self))
|
||||
self.connect(self.pos, SIGNAL('valueChanged(double)'), self.goto_page)
|
||||
self.connect(self.vertical_scrollbar, SIGNAL('valueChanged(int)'),
|
||||
self.connect(self.vertical_scrollbar, SIGNAL('valueChanged(int)'),
|
||||
lambda x: self.goto_page(x/100.))
|
||||
self.connect(self.search, SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), self.find)
|
||||
self.connect(self.toc, SIGNAL('clicked(QModelIndex)'), self.toc_clicked)
|
||||
self.connect(self.reference, SIGNAL('goto(PyQt_PyObject)'), self.goto)
|
||||
|
||||
|
||||
|
||||
self.bookmarks_menu = QMenu()
|
||||
self.action_bookmark.setMenu(self.bookmarks_menu)
|
||||
self.set_bookmarks([])
|
||||
|
||||
|
||||
if pathtoebook is not None:
|
||||
f = functools.partial(self.load_ebook, pathtoebook)
|
||||
QTimer.singleShot(50, f)
|
||||
@ -277,7 +276,7 @@ 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.print_menu = QMenu()
|
||||
self.print_menu.addAction(QIcon(':/images/print-preview.svg'), _('Print Preview'))
|
||||
self.action_print.setMenu(self.print_menu)
|
||||
@ -293,18 +292,18 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.showNormal()
|
||||
else:
|
||||
self.showFullScreen()
|
||||
|
||||
|
||||
def goto(self, ref):
|
||||
if ref:
|
||||
tokens = ref.split('.')
|
||||
if len(tokens) > 1:
|
||||
spine_index = int(tokens[0]) -1
|
||||
spine_index = int(tokens[0]) -1
|
||||
if spine_index == self.current_index:
|
||||
self.view.goto(ref)
|
||||
else:
|
||||
self.pending_reference = ref
|
||||
self.load_path(self.iterator.spine[spine_index])
|
||||
|
||||
|
||||
def goto_bookmark(self, bm):
|
||||
m = bm[1].split('#')
|
||||
if len(m) > 1:
|
||||
@ -314,39 +313,39 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
else:
|
||||
self.pending_bookmark = bm
|
||||
self.load_path(self.iterator.spine[spine_index])
|
||||
|
||||
|
||||
def toc_clicked(self, index):
|
||||
item = self.toc_model.itemFromIndex(index)
|
||||
url = QUrl.fromLocalFile(item.abspath)
|
||||
if item.fragment:
|
||||
url.setFragment(item.fragment)
|
||||
self.link_clicked(url)
|
||||
|
||||
|
||||
def selection_changed(self, selected_text):
|
||||
self.selected_text = selected_text.strip()
|
||||
self.action_copy.setEnabled(bool(self.selected_text))
|
||||
|
||||
|
||||
def copy(self, x):
|
||||
if self.selected_text:
|
||||
QApplication.clipboard().setText(self.selected_text)
|
||||
|
||||
|
||||
def back(self, x):
|
||||
pos = self.history.back(self.pos.value())
|
||||
if pos is not None:
|
||||
self.goto_page(pos)
|
||||
|
||||
|
||||
|
||||
|
||||
def forward(self, x):
|
||||
pos = self.history.forward()
|
||||
if pos is not None:
|
||||
self.goto_page(pos)
|
||||
|
||||
|
||||
def goto_start(self):
|
||||
self.goto_page(1)
|
||||
|
||||
|
||||
def goto_end(self):
|
||||
self.goto_page(self.pos.maximum())
|
||||
|
||||
|
||||
def goto_page(self, new_page):
|
||||
if self.current_page is not None:
|
||||
for page in self.iterator.spine:
|
||||
@ -359,7 +358,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.view.scroll_to(frac)
|
||||
else:
|
||||
self.load_path(page, pos=frac)
|
||||
|
||||
|
||||
def open_ebook(self, checked):
|
||||
files = choose_files(self, 'ebook viewer open dialog',
|
||||
_('Choose ebook'),
|
||||
@ -367,19 +366,19 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
select_only_single_file=True)
|
||||
if files:
|
||||
self.load_ebook(files[0])
|
||||
|
||||
|
||||
def font_size_larger(self, checked):
|
||||
frac = 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)
|
||||
self.set_page_number(frac)
|
||||
|
||||
|
||||
def font_size_smaller(self, checked):
|
||||
frac = 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)
|
||||
self.set_page_number(frac)
|
||||
|
||||
|
||||
def bookmark(self, *args):
|
||||
title, ok = QInputDialog.getText(self, _('Add bookmark'), _('Enter title for bookmark:'))
|
||||
title = unicode(title).strip()
|
||||
@ -388,8 +387,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
bookmark = '%d#%s'%(self.current_index, pos)
|
||||
self.iterator.add_bookmark((title, bookmark))
|
||||
self.set_bookmarks(self.iterator.bookmarks)
|
||||
|
||||
|
||||
|
||||
|
||||
def find(self, text, refinement, repeat=False):
|
||||
if not text:
|
||||
return
|
||||
@ -401,18 +400,18 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
if self.current_index > 0:
|
||||
index = self.iterator.search(text, 0)
|
||||
if index is None:
|
||||
info_dialog(self, _('No matches found'),
|
||||
info_dialog(self, _('No matches found'),
|
||||
_('No matches found for: %s')%text).exec_()
|
||||
return
|
||||
return
|
||||
self.pending_search = text
|
||||
self.load_path(self.iterator.spine[index])
|
||||
|
||||
|
||||
def do_search(self, text):
|
||||
self.pending_search = None
|
||||
if self.view.search(text):
|
||||
self.scrolled(self.view.scroll_fraction)
|
||||
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if event.key() == Qt.Key_F3:
|
||||
text = unicode(self.search.text())
|
||||
@ -421,10 +420,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.search.setFocus(Qt.OtherFocusReason)
|
||||
else:
|
||||
return MainWindow.keyPressEvent(self, event)
|
||||
|
||||
|
||||
def internal_link_clicked(self, frac):
|
||||
self.history.add(self.pos.value())
|
||||
|
||||
|
||||
def link_clicked(self, url):
|
||||
path = os.path.abspath(unicode(url.toLocalFile()))
|
||||
frag = None
|
||||
@ -440,10 +439,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.view.scroll_to(frag)
|
||||
else:
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
|
||||
def load_started(self):
|
||||
self.open_progress_indicator(_('Loading flow...'))
|
||||
|
||||
|
||||
def load_finished(self, ok):
|
||||
self.close_progress_indicator()
|
||||
path = self.view.path()
|
||||
@ -467,11 +466,11 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.goto_bookmark(self.pending_bookmark)
|
||||
self.pending_bookmark = None
|
||||
return self.current_index
|
||||
|
||||
|
||||
def load_path(self, path, pos=0.0):
|
||||
self.open_progress_indicator(_('Laying out %s')%self.current_title)
|
||||
self.view.load_path(path, pos=pos)
|
||||
|
||||
|
||||
def viewport_resized(self, frac):
|
||||
new_page = self.pos.value()
|
||||
if self.current_page is not None:
|
||||
@ -482,20 +481,20 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.view.scroll_to(frac, notify=False)
|
||||
else:
|
||||
self.set_page_number(frac)
|
||||
|
||||
|
||||
def close_progress_indicator(self):
|
||||
self.pi.stop()
|
||||
for o in ('tool_bar', 'tool_bar2', 'view', 'horizontal_scrollbar', 'vertical_scrollbar'):
|
||||
getattr(self, o).setEnabled(True)
|
||||
self.unsetCursor()
|
||||
self.view.setFocus(Qt.PopupFocusReason)
|
||||
|
||||
|
||||
def open_progress_indicator(self, msg=''):
|
||||
self.pi.start(msg)
|
||||
for o in ('tool_bar', 'tool_bar2', 'view', 'horizontal_scrollbar', 'vertical_scrollbar'):
|
||||
getattr(self, o).setEnabled(False)
|
||||
self.setCursor(Qt.BusyCursor)
|
||||
|
||||
|
||||
def set_bookmarks(self, bookmarks):
|
||||
self.bookmarks_menu.clear()
|
||||
self.bookmarks_menu.addAction(_("Manage Bookmarks"), self.manage_bookmarks)
|
||||
@ -507,19 +506,19 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
else:
|
||||
self.bookmarks_menu.addAction(bm[0], partial(self.goto_bookmark, bm))
|
||||
return current_page
|
||||
|
||||
|
||||
def manage_bookmarks(self):
|
||||
bmm = BookmarkManager(self, self.iterator.bookmarks)
|
||||
if bmm.exec_() != BookmarkManager.Accepted:
|
||||
return
|
||||
|
||||
|
||||
bookmarks = bmm.get_bookmarks()
|
||||
|
||||
|
||||
if bookmarks != self.iterator.bookmarks:
|
||||
self.iterator.set_bookmarks(bookmarks)
|
||||
self.iterator.save_bookmarks()
|
||||
self.set_bookmarks(bookmarks)
|
||||
|
||||
|
||||
def save_current_position(self):
|
||||
try:
|
||||
pos = self.view.bookmark()
|
||||
@ -527,7 +526,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.iterator.add_bookmark(('calibre_current_page_bookmark', bookmark))
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def load_ebook(self, pathtoebook):
|
||||
if self.iterator is not None:
|
||||
self.save_current_position()
|
||||
@ -543,7 +542,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
if isinstance(worker.exception, DRMError):
|
||||
error_dialog(self, _('DRM Error'), _('<p>This book is protected by <a href="%s">DRM</a>')%'http://wiki.mobileread.com/wiki/DRM').exec_()
|
||||
else:
|
||||
ConversionErrorDialog(self, _('Could not open ebook'),
|
||||
ConversionErrorDialog(self, _('Could not open ebook'),
|
||||
_('<b>%s</b><br/><p>%s</p>')%(worker.exception, worker.traceback.replace('\n', '<br>')), show=True)
|
||||
self.close_progress_indicator()
|
||||
else:
|
||||
@ -571,37 +570,37 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.goto_bookmark(previous)
|
||||
else:
|
||||
self.next_document()
|
||||
|
||||
|
||||
def set_vscrollbar_value(self, pagenum):
|
||||
self.vertical_scrollbar.blockSignals(True)
|
||||
self.vertical_scrollbar.setValue(int(pagenum*100))
|
||||
self.vertical_scrollbar.blockSignals(False)
|
||||
|
||||
|
||||
def set_page_number(self, frac):
|
||||
if getattr(self, 'current_page', None) is not None:
|
||||
page = self.current_page.start_page + frac*float(self.current_page.pages-1)
|
||||
self.pos.set_value(page)
|
||||
self.set_vscrollbar_value(page)
|
||||
|
||||
|
||||
def scrolled(self, frac):
|
||||
self.set_page_number(frac)
|
||||
|
||||
|
||||
def next_document(self):
|
||||
if self.current_index < len(self.iterator.spine) - 1:
|
||||
self.load_path(self.iterator.spine[self.current_index+1])
|
||||
|
||||
|
||||
def previous_document(self):
|
||||
if self.current_index > 0:
|
||||
self.load_path(self.iterator.spine[self.current_index-1], pos=1.0)
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
|
||||
def __exit__(self, *args):
|
||||
if self.iterator is not None:
|
||||
self.save_current_position()
|
||||
self.iterator.__exit__(*args)
|
||||
|
||||
|
||||
|
||||
def config(defaults=None):
|
||||
desc = _('Options to control the ebook viewer')
|
||||
@ -609,8 +608,8 @@ def config(defaults=None):
|
||||
c = Config('viewer', desc)
|
||||
else:
|
||||
c = StringConfig(defaults, desc)
|
||||
|
||||
c.add_opt('raise_window', ['--raise-window'], default=False,
|
||||
|
||||
c.add_opt('raise_window', ['--raise-window'], default=False,
|
||||
help=_('If specified, viewer window will try to come to the '
|
||||
'front when started.'))
|
||||
return c
|
||||
@ -620,7 +619,7 @@ def option_parser():
|
||||
return c.option_parser(usage=_('''\
|
||||
%prog [options] file
|
||||
|
||||
View an ebook.
|
||||
View an ebook.
|
||||
'''))
|
||||
|
||||
|
||||
@ -639,7 +638,7 @@ def main(args=sys.argv):
|
||||
if opts.raise_window:
|
||||
main.raise_()
|
||||
with main:
|
||||
return app.exec_()
|
||||
return app.exec_()
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -37,7 +37,7 @@ recipe_modules = ['recipe_' + r for r in (
|
||||
'new_york_review_of_books_no_sub', 'politico', 'adventuregamers',
|
||||
'mondedurable', 'instapaper', 'dnevnik_cro', 'vecernji_list',
|
||||
'nacional_cro', '24sata', 'dnevni_avaz', 'glas_srpske', '24sata_rs',
|
||||
'krstarica', 'krstarica_en', 'tanjug',
|
||||
'krstarica', 'krstarica_en', 'tanjug', 'laprensa_ni',
|
||||
)]
|
||||
|
||||
import re, imp, inspect, time, os
|
||||
|
96
src/calibre/web/feeds/recipes/recipe_laprensa_ni.py
Normal file
96
src/calibre/web/feeds/recipes/recipe_laprensa_ni.py
Normal file
@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
laprensa.com.ni
|
||||
'''
|
||||
|
||||
import locale
|
||||
import time
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class LaPrensa_ni(BasicNewsRecipe):
|
||||
title = 'La Prensa - Nicaragua'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'LA PRENSA - EL Diario de los Nicaraguenses'
|
||||
publisher = 'La Prensa'
|
||||
category = 'Nicaragua, nicaragua, la prensa, La Prensa, prensa, Prensa, diario, Diario, periodico, noticias, internacional, economia, dinero, opinion, ultimas noticias, deportes, politica, managua, Managua, ultima hora, daily, newspaper, news, breaking news, urgente, tecnologia, tiempo, weather, buscador, magazine, Magazine, nosotras, Nosotras, journalism, clasificados, avisos, classified, ads, media, publicidad, arroba, arroba de oro'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'cp1252'
|
||||
remove_javascript = True
|
||||
language = _('Spanish')
|
||||
|
||||
#Locale setting to get appropriate date/month values in Spanish
|
||||
try:
|
||||
#Windows seting for locale
|
||||
locale.setlocale(locale.LC_TIME,'Spanish_Nicaragua')
|
||||
except locale.Error:
|
||||
#Linux setting for locale -- choose one appropriate for your distribution
|
||||
try:
|
||||
locale.setlocale(locale.LC_TIME,'es_NI')
|
||||
except locale.Error:
|
||||
try:
|
||||
locale.setlocale(locale.LC_TIME,'es_ES')
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
current_index = time.strftime("http://www.laprensa.com.ni/archivo/%Y/%B/%d/noticias/")
|
||||
|
||||
html2lrf_options = [
|
||||
'--comment', description
|
||||
, '--category', category
|
||||
, '--publisher', publisher
|
||||
, '--ignore-tables'
|
||||
]
|
||||
|
||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||
|
||||
feeds = [(u'Portada', current_index + 'portada/')]
|
||||
|
||||
def print_version(self, url):
|
||||
return url.replace('.shtml','_print.shtml')
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
del soup.body['onload']
|
||||
mtag = '<meta http-equiv="Content-Language" content="es-NI"/>'
|
||||
soup.head.insert(0,mtag)
|
||||
atag = soup.find('span',attrs={'class':'mas_noticias'})
|
||||
if atag:
|
||||
atag.extract()
|
||||
btag = soup.find('a',attrs={'href':'/archivo'})
|
||||
if btag:
|
||||
btag.extract()
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
||||
|
||||
def parse_index(self):
|
||||
totalfeeds = []
|
||||
lfeeds = self.get_feeds()
|
||||
for feedobj in lfeeds:
|
||||
feedtitle, feedurl = feedobj
|
||||
self.report_progress(0, _('Fetching feed')+' %s...'%(feedtitle if feedtitle else feedurl))
|
||||
articles = []
|
||||
soup = self.index_to_soup(feedurl)
|
||||
for item in soup.findAll('a', attrs={'class':['titular','titulonotamed']}):
|
||||
description = ''
|
||||
url = feedurl + item['href']
|
||||
title = self.tag_to_string(item)
|
||||
date = time.strftime(self.timefmt)
|
||||
articles.append({
|
||||
'title' :title
|
||||
,'date' :date
|
||||
,'url' :url
|
||||
,'description':description
|
||||
})
|
||||
totalfeeds.append((feedtitle, articles))
|
||||
return totalfeeds
|
||||
|
||||
def cleanup(self):
|
||||
#Going back to the default locale
|
||||
locale.setlocale(locale.LC_TIME,'')
|
@ -26,7 +26,8 @@ def initview(request):
|
||||
5. The feeds for the site (ids)
|
||||
"""
|
||||
|
||||
site_id, cachekey = fjlib.getcurrentsite(request.META['HTTP_HOST'], \
|
||||
site_id, cachekey = fjlib.getcurrentsite(request.META.get('HTTP_HOST',
|
||||
'planet.calibre-ebook.com'), \
|
||||
request.META.get('REQUEST_URI', request.META.get('PATH_INFO', '/')), \
|
||||
request.META['QUERY_STRING'])
|
||||
response = fjcache.cache_get(site_id, cachekey)
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
ssh divok "cd /usr/local/calibre && bzr pull"
|
||||
ssh divok "cd /usr/local/calibre && bzr up"
|
||||
ssh divok /etc/init.d/apache2 graceful
|
||||
|
@ -52,7 +52,7 @@
|
||||
<img
|
||||
src="{{ MEDIA_URL }}/img/faces/{{ item.subscriber.shortname}}.png" alt="" />
|
||||
<div class="url">
|
||||
{{ item.feed.title|safe }}
|
||||
{{ item.feed.name|safe }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -667,9 +667,16 @@ class stage3(OptionlessCommand):
|
||||
def misc(cls):
|
||||
check_call('ssh divok rm -f %s/calibre-\*.tar.gz'%DOWNLOADS, shell=True)
|
||||
check_call('scp dist/calibre-*.tar.gz divok:%s/'%DOWNLOADS, shell=True)
|
||||
check_call('gpg --armor --detach-sign dist/calibre-*.tar.gz',
|
||||
shell=True)
|
||||
check_call('scp dist/calibre-*.tar.gz.asc divok:%s/signatures/'%DOWNLOADS,
|
||||
shell=True)
|
||||
check_call('''rm -rf dist/* build/*''', shell=True)
|
||||
check_call('ssh divok bzr update /var/www/calibre.kovidgoyal.net/calibre/',
|
||||
shell=True)
|
||||
check_call('ssh divok bzr update /usr/local/calibre',
|
||||
shell=True)
|
||||
|
||||
|
||||
def run(self):
|
||||
OptionlessCommand.run(self)
|
||||
|
Loading…
x
Reference in New Issue
Block a user