Pull from trunk

This commit is contained in:
Kovid Goyal 2009-03-31 19:10:30 -07:00
commit 9ab8caf6f5
17 changed files with 429 additions and 322 deletions

View File

@ -1,5 +1,5 @@
" Project wide builtins " Project wide builtins
let g:pyflakes_builtins += ["dynamic_property", '__'] let g:pyflakes_builtins += ["dynamic_property", "__"]
python << EOFPY python << EOFPY
import os import os

View File

@ -2,7 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
__appname__ = 'calibre' __appname__ = 'calibre'
__version__ = '0.5.3' __version__ = '0.5.4'
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>" __author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
''' '''
Various run time constants. Various run time constants.

View File

@ -510,8 +510,6 @@ class OPF(object):
except: except:
pass pass
def get_text(self, elem): def get_text(self, elem):
return u''.join(self.CONTENT(elem) or self.TEXT(elem)) return u''.join(self.CONTENT(elem) or self.TEXT(elem))

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import os, glob import os, glob, re
from urlparse import urlparse from urlparse import urlparse
from urllib import unquote from urllib import unquote
@ -10,17 +10,17 @@ from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup, BeautifulSoup
from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.chardet import xml_to_unicode
class NCXSoup(BeautifulStoneSoup): class NCXSoup(BeautifulStoneSoup):
NESTABLE_TAGS = {'navpoint':[]} NESTABLE_TAGS = {'navpoint':[]}
def __init__(self, raw): def __init__(self, raw):
BeautifulStoneSoup.__init__(self, raw, BeautifulStoneSoup.__init__(self, raw,
convertEntities=BeautifulSoup.HTML_ENTITIES, convertEntities=BeautifulSoup.HTML_ENTITIES,
selfClosingTags=['meta', 'content']) selfClosingTags=['meta', 'content'])
class TOC(list): 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'): base_path=os.getcwd(), type='unknown'):
self.href = href self.href = href
self.fragment = fragment self.fragment = fragment
@ -31,7 +31,7 @@ class TOC(list):
self.base_path = base_path self.base_path = base_path
self.play_order = play_order self.play_order = play_order
self.type = type self.type = type
def __str__(self): def __str__(self):
lines = ['TOC: %s#%s'%(self.href, self.fragment)] lines = ['TOC: %s#%s'%(self.href, self.fragment)]
for child in self: for child in self:
@ -39,10 +39,10 @@ class TOC(list):
for l in c: for l in c:
lines.append('\t'+l) lines.append('\t'+l)
return '\n'.join(lines) return '\n'.join(lines)
def count(self, type): def count(self, type):
return len([i for i in self.flat() if i.type == type]) return len([i for i in self.flat() if i.type == type])
def purge(self, types, max=0): def purge(self, types, max=0):
remove = [] remove = []
for entry in self.flat(): for entry in self.flat():
@ -54,23 +54,23 @@ class TOC(list):
continue continue
entry.parent.remove(entry) entry.parent.remove(entry)
return remove return remove
def remove(self, entry): def remove(self, entry):
list.remove(self, entry) list.remove(self, entry)
entry.parent = None entry.parent = None
def add_item(self, href, fragment, text, play_order=None, type='unknown'): def add_item(self, href, fragment, text, play_order=None, type='unknown'):
if play_order is None: if play_order is None:
play_order = (self[-1].play_order if len(self) else self.play_order) + 1 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, self.append(TOC(href=href, fragment=fragment, text=text, parent=self,
base_path=self.base_path, play_order=play_order, type=type)) base_path=self.base_path, play_order=play_order, type=type))
return self[-1] return self[-1]
def top_level_items(self): def top_level_items(self):
for item in self: for item in self:
if item.text is not None: if item.text is not None:
yield item yield item
def depth(self): def depth(self):
depth = 1 depth = 1
for obj in self: for obj in self:
@ -78,14 +78,14 @@ class TOC(list):
if c > depth - 1: if c > depth - 1:
depth = c + 1 depth = c + 1
return depth return depth
def flat(self): def flat(self):
'Depth first iteration over the tree rooted at self' 'Depth first iteration over the tree rooted at self'
yield self yield self
for obj in self: for obj in self:
for i in obj.flat(): for i in obj.flat():
yield i yield i
@dynamic_property @dynamic_property
def abspath(self): def abspath(self):
doc='Return the file this toc entry points to as a absolute path to a file on the system.' 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): if not os.path.isabs(path):
path = os.path.join(self.base_path, path) path = os.path.join(self.base_path, path)
return path return path
return property(fget=fget, doc=doc) return property(fget=fget, doc=doc)
def read_from_opf(self, opfreader): def read_from_opf(self, opfreader):
toc = opfreader.soup.find('spine', toc=True) toc = opfreader.soup.find('spine', toc=True)
if toc is not None: if toc is not None:
@ -111,7 +111,7 @@ class TOC(list):
if 'toc' in item.href().lower(): if 'toc' in item.href().lower():
toc = item.href() toc = item.href()
break break
if toc is not None: if toc is not None:
if toc.lower() not in ('ncx', 'ncxtoc'): if toc.lower() not in ('ncx', 'ncxtoc'):
toc = urlparse(unquote(toc))[2] toc = urlparse(unquote(toc))[2]
@ -123,7 +123,7 @@ class TOC(list):
bn = os.path.basename(toc) bn = os.path.basename(toc)
bn = bn.replace('_top.htm', '_toc.htm') # Bug in BAEN OPF files bn = bn.replace('_top.htm', '_toc.htm') # Bug in BAEN OPF files
toc = os.path.join(os.path.dirname(toc), bn) toc = os.path.join(os.path.dirname(toc), bn)
self.read_html_toc(toc) self.read_html_toc(toc)
except: except:
print 'WARNING: Could not read Table of Contents. Continuing anyway.' print 'WARNING: Could not read Table of Contents. Continuing anyway.'
@ -141,43 +141,43 @@ class TOC(list):
if m: if m:
toc = m[0] toc = m[0]
self.read_ncx_toc(toc) self.read_ncx_toc(toc)
def read_ncx_toc(self, toc): def read_ncx_toc(self, toc):
self.base_path = os.path.dirname(toc) self.base_path = os.path.dirname(toc)
soup = NCXSoup(xml_to_unicode(open(toc, 'rb').read())[0]) soup = NCXSoup(xml_to_unicode(open(toc, 'rb').read())[0])
def process_navpoint(np, dest): def process_navpoint(np, dest):
play_order = np.get('playOrder', None) play_order = np.get('playOrder', None)
if play_order is None: if play_order is None:
play_order = int(np.get('playorder', 1)) play_order = int(np.get('playorder', 1))
href = fragment = text = None href = fragment = text = None
nl = np.find('navlabel') nl = np.find(re.compile('navlabel'))
if nl is not None: if nl is not None:
text = u'' 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)]) 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: if content is None or not content.has_key('src') or not txt:
return return
purl = urlparse(unquote(content['src'])) purl = urlparse(unquote(content['src']))
href, fragment = purl[2], purl[5] href, fragment = purl[2], purl[5]
nd = dest.add_item(href, fragment, text) nd = dest.add_item(href, fragment, text)
nd.play_order = play_order nd.play_order = play_order
for c in np: for c in np:
if getattr(c, 'name', None) == 'navpoint': if 'navpoint' in getattr(c, 'name', ''):
process_navpoint(c, nd) process_navpoint(c, nd)
nm = soup.find('navmap') nm = soup.find(re.compile('navmap'))
if nm is None: if nm is None:
raise ValueError('NCX files must have a <navmap> element.') raise ValueError('NCX files must have a <navmap> element.')
for elem in nm: for elem in nm:
if getattr(elem, 'name', None) == 'navpoint': if 'navpoint' in getattr(elem, 'name', ''):
process_navpoint(elem, self) process_navpoint(elem, self)
def read_html_toc(self, toc): def read_html_toc(self, toc):
self.base_path = os.path.dirname(toc) self.base_path = os.path.dirname(toc)
soup = BeautifulSoup(open(toc, 'rb').read(), convertEntities=BeautifulSoup.HTML_ENTITIES) soup = BeautifulSoup(open(toc, 'rb').read(), convertEntities=BeautifulSoup.HTML_ENTITIES)
@ -191,13 +191,13 @@ class TOC(list):
else: else:
fragment = fragment.strip() fragment = fragment.strip()
href = href.strip() href = href.strip()
txt = ''.join([unicode(s).strip() for s in a.findAll(text=True)]) txt = ''.join([unicode(s).strip() for s in a.findAll(text=True)])
add = True add = True
for i in self.flat(): for i in self.flat():
if i.href == href and i.fragment == fragment: if i.href == href and i.fragment == fragment:
add = False add = False
break break
if add: if add:
self.add_item(href, fragment, txt) self.add_item(href, fragment, txt)
@ -208,4 +208,4 @@ class TOC(list):
template = MarkupTemplate(ncx_template) template = MarkupTemplate(ncx_template)
raw = template.generate(uid=uid, toc=self, __appname__=__appname__) raw = template.generate(uid=uid, toc=self, __appname__=__appname__)
raw = raw.render(doctype=doctype) raw = raw.render(doctype=doctype)
stream.write(raw) stream.write(raw)

View File

@ -263,7 +263,7 @@ class EmailAccounts(QAbstractTableModel):
def remove(self, index): def remove(self, index):
if index.isValid(): if index.isValid():
row = self.index.row() row = index.row()
account = self.account_order[row] account = self.account_order[row]
self.accounts.pop(account) self.accounts.pop(account)
self.account_order = sorted(self.accounts.keys()) self.account_order = sorted(self.accounts.keys())
@ -425,6 +425,8 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.email_view.resizeColumnsToContents() self.email_view.resizeColumnsToContents()
self.connect(self.test_email_button, SIGNAL('clicked(bool)'), self.connect(self.test_email_button, SIGNAL('clicked(bool)'),
self.test_email) self.test_email)
self.connect(self.email_remove, SIGNAL('clicked()'),
self.remove_email_account)
def add_email_account(self, checked): def add_email_account(self, checked):
index = self._email_accounts.add() index = self._email_accounts.add()
@ -432,6 +434,10 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.email_view.resizeColumnsToContents() self.email_view.resizeColumnsToContents()
self.email_view.edit(index) 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): def create_gmail_relay(self, *args):
self.relay_username.setText('@gmail.com') self.relay_username.setText('@gmail.com')
self.relay_password.setText('') self.relay_password.setText('')

View File

@ -727,7 +727,7 @@
<string> px</string> <string> px</string>
</property> </property>
<property name="maximum" > <property name="maximum" >
<number>200</number> <number>250</number>
</property> </property>
<property name="value" > <property name="value" >
<number>20</number> <number>20</number>
@ -750,7 +750,7 @@
<string> px</string> <string> px</string>
</property> </property>
<property name="maximum" > <property name="maximum" >
<number>200</number> <number>250</number>
</property> </property>
<property name="value" > <property name="value" >
<number>20</number> <number>20</number>
@ -773,7 +773,7 @@
<string> px</string> <string> px</string>
</property> </property>
<property name="maximum" > <property name="maximum" >
<number>200</number> <number>250</number>
</property> </property>
<property name="value" > <property name="value" >
<number>10</number> <number>10</number>
@ -796,7 +796,7 @@
<string> px</string> <string> px</string>
</property> </property>
<property name="maximum" > <property name="maximum" >
<number>200</number> <number>250</number>
</property> </property>
<property name="value" > <property name="value" >
<number>0</number> <number>0</number>

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

View File

@ -6,7 +6,7 @@ from PyQt4.QtCore import Qt, QByteArray, SIGNAL
from PyQt4.QtGui import QGraphicsRectItem, QGraphicsScene, QPen, \ from PyQt4.QtGui import QGraphicsRectItem, QGraphicsScene, QPen, \
QBrush, QColor, QFontDatabase, \ QBrush, QColor, QFontDatabase, \
QGraphicsItem, QGraphicsLineItem QGraphicsItem, QGraphicsLineItem
from calibre.gui2.lrf_renderer.text import TextBlock, FontLoader, COLOR, PixmapItem from calibre.gui2.lrf_renderer.text import TextBlock, FontLoader, COLOR, PixmapItem
@ -25,17 +25,17 @@ class Pen(QPen):
class ContentObject(object): class ContentObject(object):
has_content = True has_content = True
def reset(self): def reset(self):
self.has_content = True self.has_content = True
class RuledLine(QGraphicsLineItem, ContentObject): class RuledLine(QGraphicsLineItem, ContentObject):
map = {'solid': Qt.SolidLine, 'dashed': Qt.DashLine, 'dotted': Qt.DotLine, 'double': Qt.DashDotLine} map = {'solid': Qt.SolidLine, 'dashed': Qt.DashLine, 'dotted': Qt.DotLine, 'double': Qt.DashDotLine}
def __init__(self, rl): def __init__(self, rl):
QGraphicsLineItem.__init__(self, 0, 0, rl.linelength, 0) QGraphicsLineItem.__init__(self, 0, 0, rl.linelength, 0)
ContentObject.__init__(self) ContentObject.__init__(self)
@ -43,7 +43,7 @@ class RuledLine(QGraphicsLineItem, ContentObject):
class ImageBlock(PixmapItem, ContentObject): class ImageBlock(PixmapItem, ContentObject):
def __init__(self, obj): def __init__(self, obj):
ContentObject.__init__(self) ContentObject.__init__(self)
x0, y0, x1, y1 = obj.attrs['x0'], obj.attrs['y0'], obj.attrs['x1'], obj.attrs['y1'] 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 data, encoding = refstream.stream, refstream.encoding
PixmapItem.__init__(self, data, encoding, x0, y0, x1, y1, xsize, ysize) PixmapItem.__init__(self, data, encoding, x0, y0, x1, y1, xsize, ysize)
self.block_id = obj.id self.block_id = obj.id
def object_factory(container, obj, respect_max_y=False): def object_factory(container, obj, respect_max_y=False):
if hasattr(obj, 'name'): if hasattr(obj, 'name'):
if obj.name.endswith('TextBlock'): if obj.name.endswith('TextBlock'):
return TextBlock(obj, container.font_loader, respect_max_y, container.text_width, 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) container.link_activated)
elif obj.name.endswith('ImageBlock'): elif obj.name.endswith('ImageBlock'):
return ImageBlock(obj) return ImageBlock(obj)
elif isinstance(obj, _RuledLine): elif isinstance(obj, _RuledLine):
return RuledLine(obj) return RuledLine(obj)
elif isinstance(obj, __Canvas): elif isinstance(obj, __Canvas):
return Canvas(container.font_loader, obj, container.logger, container.opts, return Canvas(container.font_loader, obj, container.logger, container.opts,
container.ruby_tags, container.link_activated) container.ruby_tags, container.link_activated)
return None return None
class _Canvas(QGraphicsRectItem): class _Canvas(QGraphicsRectItem):
def __init__(self, font_loader, logger, opts, width=0, height=0, parent=None, x=0, y=0): 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) QGraphicsRectItem.__init__(self, x, y, width, height, parent)
self.font_loader, self.logger, self.opts = font_loader, logger, opts self.font_loader, self.logger, self.opts = font_loader, logger, opts
@ -79,7 +79,7 @@ class _Canvas(QGraphicsRectItem):
pen = QPen() pen = QPen()
pen.setStyle(Qt.NoPen) pen.setStyle(Qt.NoPen)
self.setPen(pen) self.setPen(pen)
def layout_block(self, block, x, y): def layout_block(self, block, x, y):
if isinstance(block, TextBlock): if isinstance(block, TextBlock):
self.layout_text_block(block, x, y) self.layout_text_block(block, x, y)
@ -89,17 +89,17 @@ class _Canvas(QGraphicsRectItem):
self.layout_image_block(block, x, y) self.layout_image_block(block, x, y)
elif isinstance(block, Canvas): elif isinstance(block, Canvas):
self.layout_canvas(block, x, y) self.layout_canvas(block, x, y)
def layout_canvas(self, canvas, x, y): def layout_canvas(self, canvas, x, y):
if canvas.max_y + y > self.max_y and y > 0: if canvas.max_y + y > self.max_y and y > 0:
self.is_full = True self.is_full = True
return return
canvas.setParentItem(self) canvas.setParentItem(self)
canvas.setPos(x, y) canvas.setPos(x, y)
canvas.has_content = False canvas.has_content = False
canvas.put_objects() canvas.put_objects()
self.current_y += canvas.max_y self.current_y += canvas.max_y
def layout_text_block(self, block, x, y): def layout_text_block(self, block, x, y):
textwidth = block.bs.blockwidth - block.bs.sidemargin textwidth = block.bs.blockwidth - block.bs.sidemargin
if block.max_y == 0 or not block.lines: # Empty block skipping if block.max_y == 0 or not block.lines: # Empty block skipping
@ -128,15 +128,15 @@ class _Canvas(QGraphicsRectItem):
line = block.peek() line = block.peek()
self.current_y = y self.current_y = y
self.is_full = not block_consumed self.is_full = not block_consumed
def layout_ruled_line(self, rl, x, y): def layout_ruled_line(self, rl, x, y):
br = rl.boundingRect() br = rl.boundingRect()
rl.setParentItem(self) rl.setParentItem(self)
rl.setPos(x, y+1) rl.setPos(x, y+1)
self.current_y = y + br.height() + 1 self.current_y = y + br.height() + 1
self.is_full = y > self.max_y-5 self.is_full = y > self.max_y-5
rl.has_content = False rl.has_content = False
def layout_image_block(self, ib, x, y): def layout_image_block(self, ib, x, y):
mw, mh = self.max_x - x, self.max_y - 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: if self.current_y + ib.height > self.max_y-y and self.current_y > 5:
@ -161,8 +161,8 @@ class _Canvas(QGraphicsRectItem):
print print
print ib.block_id, ib.has_content, self.is_full print ib.block_id, ib.has_content, self.is_full
print self.current_y, self.max_y, y, br.height() print self.current_y, self.max_y, y, br.height()
print print
def search(self, phrase): def search(self, phrase):
matches = [] matches = []
for child in self.children(): for child in self.children():
@ -174,11 +174,11 @@ class _Canvas(QGraphicsRectItem):
else: else:
matches.append(res) matches.append(res)
return matches return matches
class Canvas(_Canvas, ContentObject): class Canvas(_Canvas, ContentObject):
def __init__(self, font_loader, canvas, logger, opts, ruby_tags, link_activated, width=0, height=0): def __init__(self, font_loader, canvas, logger, opts, ruby_tags, link_activated, width=0, height=0):
if hasattr(canvas, 'canvaswidth'): if hasattr(canvas, 'canvaswidth'):
width, height = canvas.canvaswidth, canvas.canvasheight width, height = canvas.canvaswidth, canvas.canvasheight
@ -198,11 +198,11 @@ class Canvas(_Canvas, ContentObject):
item = object_factory(self, obj, respect_max_y=True) item = object_factory(self, obj, respect_max_y=True)
if item: if item:
self.items.append((item, po.x1, po.y1)) self.items.append((item, po.x1, po.y1))
def put_objects(self): def put_objects(self):
for block, x, y in self.items: for block, x, y in self.items:
self.layout_block(block, x, y) self.layout_block(block, x, y)
def layout_block(self, block, x, y): def layout_block(self, block, x, y):
block.reset() block.reset()
_Canvas.layout_block(self, block, x, y) _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, Canvas.__init__(self, font_loader, header, logger, opts, ruby_tags, link_activated,
page_style.textwidth, page_style.headheight) page_style.textwidth, page_style.headheight)
if opts.visual_debug: if opts.visual_debug:
self.setPen(QPen(Qt.blue, 1, Qt.DashLine)) self.setPen(QPen(Qt.blue, 1, Qt.DashLine))
class Footer(Canvas): class Footer(Canvas):
def __init__(self, font_loader, footer, page_style, logger, opts, ruby_tags, link_activated): 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, Canvas.__init__(self, font_loader, footer, logger, opts, ruby_tags, link_activated,
page_style.textwidth, page_style.footheight) page_style.textwidth, page_style.footheight)
if opts.visual_debug: if opts.visual_debug:
self.setPen(QPen(Qt.blue, 1, Qt.DashLine)) self.setPen(QPen(Qt.blue, 1, Qt.DashLine))
class Screen(_Canvas): class Screen(_Canvas):
def __init__(self, font_loader, chapter, odd, logger, opts, ruby_tags, link_activated): def __init__(self, font_loader, chapter, odd, logger, opts, ruby_tags, link_activated):
self.logger, self.opts = logger, opts self.logger, self.opts = logger, opts
page_style = chapter.style page_style = chapter.style
@ -231,11 +231,11 @@ class Screen(_Canvas):
self.content_x = 0 + sidemargin self.content_x = 0 + sidemargin
self.text_width = page_style.textwidth self.text_width = page_style.textwidth
self.header_y = page_style.topmargin self.header_y = page_style.topmargin
self.text_y = self.header_y + page_style.headheight + page_style.headsep self.text_y = self.header_y + page_style.headheight + page_style.headsep
self.text_height = page_style.textheight self.text_height = page_style.textheight
self.footer_y = self.text_y + self.text_height + (page_style.footspace - page_style.footheight) 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) _Canvas.__init__(self, font_loader, logger, opts, width=width, height=self.footer_y+page_style.footheight)
if opts.visual_debug: if opts.visual_debug:
self.setPen(QPen(Qt.red, 1, Qt.SolidLine)) self.setPen(QPen(Qt.red, 1, Qt.SolidLine))
@ -256,57 +256,57 @@ class Screen(_Canvas):
if footer: if footer:
footer = Footer(font_loader, footer, page_style, logger, opts, ruby_tags, link_activated) footer = Footer(font_loader, footer, page_style, logger, opts, ruby_tags, link_activated)
self.layout_canvas(footer, self.content_x, self.header_y) self.layout_canvas(footer, self.content_x, self.header_y)
self.page = None self.page = None
def set_page(self, page): def set_page(self, page):
if self.page is not None and self.page.scene(): 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 = page
self.page.setPos(self.content_x, self.text_y) self.page.setPos(self.content_x, self.text_y)
self.scene().addItem(self.page) self.scene().addItem(self.page)
def remove(self): def remove(self):
if self.scene(): if self.scene():
if self.page is not None and self.page.scene(): if self.page is not None and self.page.scene():
self.scene().removeItem(self.page) self.scene().removeItem(self.page)
self.scene().removeItem(self) self.scene().removeItem(self)
class Page(_Canvas): class Page(_Canvas):
def __init__(self, font_loader, logger, opts, width, height): def __init__(self, font_loader, logger, opts, width, height):
_Canvas.__init__(self, font_loader, logger, opts, width, height) _Canvas.__init__(self, font_loader, logger, opts, width, height)
if opts.visual_debug: if opts.visual_debug:
self.setPen(QPen(Qt.cyan, 1, Qt.DashLine)) self.setPen(QPen(Qt.cyan, 1, Qt.DashLine))
def id(self): def id(self):
for child in self.children(): for child in self.children():
if hasattr(child, 'block_id'): if hasattr(child, 'block_id'):
return child.block_id return child.block_id
def add_block(self, block): def add_block(self, block):
self.layout_block(block, 0, self.current_y) self.layout_block(block, 0, self.current_y)
class Chapter(object): class Chapter(object):
num_of_pages = property(fget=lambda self: len(self.pages)) num_of_pages = property(fget=lambda self: len(self.pages))
def __init__(self, oddscreen, evenscreen, pages, object_to_page_map): def __init__(self, oddscreen, evenscreen, pages, object_to_page_map):
self.oddscreen, self.evenscreen, self.pages, self.object_to_page_map = \ self.oddscreen, self.evenscreen, self.pages, self.object_to_page_map = \
oddscreen, evenscreen, pages, object_to_page_map oddscreen, evenscreen, pages, object_to_page_map
def page_of_object(self, id): def page_of_object(self, id):
return self.object_to_page_map[id] return self.object_to_page_map[id]
def page(self, num): def page(self, num):
return self.pages[num-1] return self.pages[num-1]
def screen(self, odd): def screen(self, odd):
return self.oddscreen if odd else self.evenscreen return self.oddscreen if odd else self.evenscreen
def search(self, phrase): def search(self, phrase):
pages = [] pages = []
for i in range(len(self.pages)): for i in range(len(self.pages)):
@ -314,36 +314,36 @@ class Chapter(object):
if matches: if matches:
pages.append([i, matches]) pages.append([i, matches])
return pages return pages
class History(collections.deque): class History(collections.deque):
def __init__(self): def __init__(self):
collections.deque.__init__(self) collections.deque.__init__(self)
self.pos = 0 self.pos = 0
def back(self): def back(self):
if self.pos - 1 < 0: return None if self.pos - 1 < 0: return None
self.pos -= 1 self.pos -= 1
return self[self.pos] return self[self.pos]
def forward(self): def forward(self):
if self.pos + 1 >= len(self): return None if self.pos + 1 >= len(self): return None
self.pos += 1 self.pos += 1
return self[self.pos] return self[self.pos]
def add(self, item): def add(self, item):
while len(self) > self.pos+1: while len(self) > self.pos+1:
self.pop() self.pop()
self.append(item) self.append(item)
self.pos += 1 self.pos += 1
class Document(QGraphicsScene): class Document(QGraphicsScene):
num_of_pages = property(fget=lambda self: sum(self.chapter_layout)) num_of_pages = property(fget=lambda self: sum(self.chapter_layout))
def __init__(self, logger, opts): def __init__(self, logger, opts):
QGraphicsScene.__init__(self) QGraphicsScene.__init__(self)
self.logger, self.opts = logger, opts self.logger, self.opts = logger, opts
@ -358,23 +358,23 @@ class Document(QGraphicsScene):
self.last_search = iter([]) self.last_search = iter([])
if not opts.white_background: if not opts.white_background:
self.setBackgroundBrush(QBrush(QColor(0xee, 0xee, 0xee))) self.setBackgroundBrush(QBrush(QColor(0xee, 0xee, 0xee)))
def page_of(self, oid): def page_of(self, oid):
for chapter in self.chapters: for chapter in self.chapters:
if oid in chapter.object_to_page_map: if oid in chapter.object_to_page_map:
return chapter.object_to_page_map[oid] return chapter.object_to_page_map[oid]
def get_page_num(self, chapterid, objid): def get_page_num(self, chapterid, objid):
cnum = self.chapter_map[chapterid] cnum = self.chapter_map[chapterid]
page = self.chapters[cnum].object_to_page_map[objid] page = self.chapters[cnum].object_to_page_map[objid]
return sum(self.chapter_layout[:cnum])+page return sum(self.chapter_layout[:cnum])+page
def add_to_history(self): def add_to_history(self):
page = self.chapter_page(self.current_page)[1] page = self.chapter_page(self.current_page)[1]
page_id = page.id() page_id = page.id()
if page_id is not None: if page_id is not None:
self.history.add(page_id) self.history.add(page_id)
def link_activated(self, objid, on_creation=None): def link_activated(self, objid, on_creation=None):
if on_creation is None: if on_creation is None:
cid, oid = self.link_map[objid] cid, oid = self.link_map[objid]
@ -385,30 +385,30 @@ class Document(QGraphicsScene):
else: else:
jb = self.objects[objid] jb = self.objects[objid]
self.link_map[objid] = (jb.refpage, jb.refobj) self.link_map[objid] = (jb.refpage, jb.refobj)
def back(self): def back(self):
oid = self.history.back() oid = self.history.back()
if oid is not None: if oid is not None:
page = self.page_of(oid) page = self.page_of(oid)
self.show_page(page) self.show_page(page)
def forward(self): def forward(self):
oid = self.history.forward() oid = self.history.forward()
if oid is not None: if oid is not None:
page = self.page_of(oid) page = self.page_of(oid)
self.show_page(page) self.show_page(page)
def load_fonts(self, lrf, load_substitutions=True): def load_fonts(self, lrf, load_substitutions=True):
font_map = {} font_map = {}
for font in lrf.font_map: for font in lrf.font_map:
fdata = QByteArray(lrf.font_map[font].data) fdata = QByteArray(lrf.font_map[font].data)
id = QFontDatabase.addApplicationFontFromData(fdata) id = QFontDatabase.addApplicationFontFromData(fdata)
if id != -1: if id != -1:
font_map[font] = [str(i) for i in QFontDatabase.applicationFontFamilies(id)][0] font_map[font] = [str(i) for i in QFontDatabase.applicationFontFamilies(id)][0]
if load_substitutions: if load_substitutions:
from calibre.ebooks.lrf.fonts.liberation import LiberationMono_BoldItalic from calibre.ebooks.lrf.fonts.liberation import LiberationMono_BoldItalic
QFontDatabase.addApplicationFontFromData(QByteArray(LiberationMono_BoldItalic.font_data)) QFontDatabase.addApplicationFontFromData(QByteArray(LiberationMono_BoldItalic.font_data))
@ -434,10 +434,10 @@ class Document(QGraphicsScene):
QFontDatabase.addApplicationFontFromData(QByteArray(LiberationSerif_BoldItalic.font_data)) QFontDatabase.addApplicationFontFromData(QByteArray(LiberationSerif_BoldItalic.font_data))
from calibre.ebooks.lrf.fonts.liberation import LiberationSans_Regular from calibre.ebooks.lrf.fonts.liberation import LiberationSans_Regular
QFontDatabase.addApplicationFontFromData(QByteArray(LiberationSans_Regular.font_data)) QFontDatabase.addApplicationFontFromData(QByteArray(LiberationSans_Regular.font_data))
self.font_loader = FontLoader(font_map, self.dpi) self.font_loader = FontLoader(font_map, self.dpi)
def render_chapter(self, chapter, lrf): def render_chapter(self, chapter, lrf):
oddscreen, evenscreen = Screen(self.font_loader, chapter, True, self.logger, self.opts, self.ruby_tags, self.link_activated), \ 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) 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: if current_page:
pages.append(current_page) pages.append(current_page)
self.chapters.append(Chapter(oddscreen, evenscreen, pages, object_to_page_map)) 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): def render(self, lrf, load_substitutions=True):
self.dpi = lrf.device_info.dpi/10. self.dpi = lrf.device_info.dpi/10.
self.ruby_tags = dict(**lrf.ruby_tags) self.ruby_tags = dict(**lrf.ruby_tags)
self.load_fonts(lrf, load_substitutions) self.load_fonts(lrf, load_substitutions)
self.objects = lrf.objects self.objects = lrf.objects
num_chaps = 0 num_chaps = 0
for pt in lrf.page_trees: for pt in lrf.page_trees:
for chapter in pt: for chapter in pt:
num_chaps += 1 num_chaps += 1
self.emit(SIGNAL('chapter_rendered(int)'), num_chaps) self.emit(SIGNAL('chapter_rendered(int)'), num_chaps)
for pt in lrf.page_trees: for pt in lrf.page_trees:
for chapter in pt: for chapter in pt:
self.render_chapter(chapter, lrf) self.render_chapter(chapter, lrf)
self.emit(SIGNAL('chapter_rendered(int)'), -1) self.emit(SIGNAL('chapter_rendered(int)'), -1)
self.chapter_layout = [i.num_of_pages for i in self.chapters] self.chapter_layout = [i.num_of_pages for i in self.chapters]
self.objects = None self.objects = None
def chapter_page(self, num): def chapter_page(self, num):
for chapter in self.chapters: for chapter in self.chapters:
if num <= chapter.num_of_pages: if num <= chapter.num_of_pages:
break break
num -= chapter.num_of_pages num -= chapter.num_of_pages
return chapter, chapter.page(num) return chapter, chapter.page(num)
def show_page(self, num): def show_page(self, num):
if num < 1 or num > self.num_of_pages or num == self.current_page: if num < 1 or num > self.num_of_pages or num == self.current_page:
return return
@ -496,33 +496,33 @@ class Document(QGraphicsScene):
self.current_page = num self.current_page = num
chapter, page = self.chapter_page(num) chapter, page = self.chapter_page(num)
screen = chapter.screen(odd) screen = chapter.screen(odd)
if self.current_screen is not None and self.current_screen is not screen: if self.current_screen is not None and self.current_screen is not screen:
self.current_screen.remove() self.current_screen.remove()
self.current_screen = screen self.current_screen = screen
if self.current_screen.scene() is None: if self.current_screen.scene() is None:
self.addItem(self.current_screen) self.addItem(self.current_screen)
self.current_screen.set_page(page) self.current_screen.set_page(page)
self.emit(SIGNAL('page_changed(PyQt_PyObject)'), self.current_page) self.emit(SIGNAL('page_changed(PyQt_PyObject)'), self.current_page)
def next(self): def next(self):
self.next_by(1) self.next_by(1)
def previous(self): def previous(self):
self.previous_by(1) self.previous_by(1)
def next_by(self, num): def next_by(self, num):
self.show_page(self.current_page + num) self.show_page(self.current_page + num)
def previous_by(self, num): def previous_by(self, num):
self.show_page(self.current_page - num) self.show_page(self.current_page - num)
def show_page_at_percent(self, p): def show_page_at_percent(self, p):
num = self.num_of_pages*(p/100.) num = self.num_of_pages*(p/100.)
self.show_page(num) self.show_page(num)
def search(self, phrase): def search(self, phrase):
if not phrase: if not phrase:
return return
@ -534,7 +534,7 @@ class Document(QGraphicsScene):
matches += cmatches matches += cmatches
self.last_search = itertools.cycle(matches) self.last_search = itertools.cycle(matches)
self.next_match() self.next_match()
def next_match(self): def next_match(self):
page_num = self.last_search.next()[0] page_num = self.last_search.next()[0]
if self.current_page == page_num: if self.current_page == page_num:
@ -542,4 +542,4 @@ class Document(QGraphicsScene):
else: else:
self.add_to_history() self.add_to_history()
self.show_page(page_num) self.show_page(page_num)

View File

@ -52,29 +52,29 @@ def config(defaults=None):
c = Config('viewer', desc) c = Config('viewer', desc)
else: else:
c = StringConfig(defaults, desc) c = StringConfig(defaults, desc)
c.add_opt('user_css', default='', c.add_opt('user_css', default='',
help=_('Set the user CSS stylesheet. This can be used to customize the look of all books.')) 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 = 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')) 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')) 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')) help=_('The monospaced font family'))
fonts('default_font_size', default=20, help=_('The standard font size in px')) 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('mono_font_size', default=16, help=_('The monospaced font size in px'))
fonts('standard_font', default='serif', help=_('The standard font type')) fonts('standard_font', default='serif', help=_('The standard font type'))
return c return c
class ConfigDialog(QDialog, Ui_Dialog): class ConfigDialog(QDialog, Ui_Dialog):
def __init__(self, *args): def __init__(self, *args):
QDialog.__init__(self, *args) QDialog.__init__(self, *args)
self.setupUi(self) self.setupUi(self)
opts = config().parse() opts = config().parse()
self.serif_family.setCurrentFont(QFont(opts.serif_family)) self.serif_family.setCurrentFont(QFont(opts.serif_family))
self.sans_family.setCurrentFont(QFont(opts.sans_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.standard_font.setCurrentIndex({'serif':0, 'sans':1, 'mono':2}[opts.standard_font])
self.css.setPlainText(opts.user_css) 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.')) self.css.setToolTip(_('Set the user CSS stylesheet. This can be used to customize the look of all books.'))
def accept(self, *args): def accept(self, *args):
c = config() c = config()
c.set('serif_family', unicode(self.serif_family.currentFont().family())) 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('standard_font', {0:'serif', 1:'sans', 2:'mono'}[self.standard_font.currentIndex()])
c.set('user_css', unicode(self.css.toPlainText())) c.set('user_css', unicode(self.css.toPlainText()))
return QDialog.accept(self, *args) return QDialog.accept(self, *args)
class Document(QWebPage): class Document(QWebPage):
def set_font_settings(self): def set_font_settings(self):
opts = config().parse() opts = config().parse()
settings = self.settings() settings = self.settings()
@ -110,14 +110,14 @@ class Document(QWebPage):
settings.setFontFamily(QWebSettings.SerifFont, opts.serif_family) settings.setFontFamily(QWebSettings.SerifFont, opts.serif_family)
settings.setFontFamily(QWebSettings.SansSerifFont, opts.sans_family) settings.setFontFamily(QWebSettings.SansSerifFont, opts.sans_family)
settings.setFontFamily(QWebSettings.FixedFont, opts.mono_family) settings.setFontFamily(QWebSettings.FixedFont, opts.mono_family)
def do_config(self, parent=None): def do_config(self, parent=None):
d = ConfigDialog(parent) d = ConfigDialog(parent)
if d.exec_() == QDialog.Accepted: if d.exec_() == QDialog.Accepted:
self.set_font_settings() self.set_font_settings()
self.set_user_stylesheet() self.set_user_stylesheet()
self.triggerAction(QWebPage.Reload) self.triggerAction(QWebPage.Reload)
def __init__(self, *args): def __init__(self, *args):
QWebPage.__init__(self, *args) QWebPage.__init__(self, *args)
self.setLinkDelegationPolicy(self.DelegateAllLinks) self.setLinkDelegationPolicy(self.DelegateAllLinks)
@ -125,53 +125,53 @@ class Document(QWebPage):
pal = self.palette() pal = self.palette()
pal.setBrush(QPalette.Background, QColor(0xee, 0xee, 0xee)) pal.setBrush(QPalette.Background, QColor(0xee, 0xee, 0xee))
self.setPalette(pal) self.setPalette(pal)
settings = self.settings() settings = self.settings()
# Fonts # Fonts
load_builtin_fonts() load_builtin_fonts()
self.set_font_settings() self.set_font_settings()
# Security # Security
settings.setAttribute(QWebSettings.JavaEnabled, False) settings.setAttribute(QWebSettings.JavaEnabled, False)
settings.setAttribute(QWebSettings.PluginsEnabled, False) settings.setAttribute(QWebSettings.PluginsEnabled, False)
settings.setAttribute(QWebSettings.JavascriptCanOpenWindows, False) settings.setAttribute(QWebSettings.JavascriptCanOpenWindows, False)
settings.setAttribute(QWebSettings.JavascriptCanAccessClipboard, False) settings.setAttribute(QWebSettings.JavascriptCanAccessClipboard, False)
# Miscellaneous # Miscellaneous
settings.setAttribute(QWebSettings.LinksIncludedInFocusChain, True) settings.setAttribute(QWebSettings.LinksIncludedInFocusChain, True)
self.set_user_stylesheet() self.set_user_stylesheet()
# Load jQuery # Load jQuery
self.connect(self.mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'), self.connect(self.mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'),
self.load_javascript_libraries) self.load_javascript_libraries)
def set_user_stylesheet(self): def set_user_stylesheet(self):
raw = config().parse().user_css raw = config().parse().user_css
pt = PersistentTemporaryFile('_user_stylesheet.css') pt = PersistentTemporaryFile('_user_stylesheet.css')
pt.write(raw.encode('utf-8')) pt.write(raw.encode('utf-8'))
pt.close() pt.close()
self.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(pt.name)) self.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(pt.name))
def load_javascript_libraries(self): def load_javascript_libraries(self):
from calibre.resources import jquery, jquery_scrollTo from calibre.resources import jquery, jquery_scrollTo
self.javascript(jquery) self.javascript(jquery)
self.javascript(jquery_scrollTo) self.javascript(jquery_scrollTo)
self.javascript(bookmarks) self.javascript(bookmarks)
self.javascript(referencing) self.javascript(referencing)
def reference_mode(self, enable): def reference_mode(self, enable):
self.javascript(('enter' if enable else 'leave')+'_reference_mode()') self.javascript(('enter' if enable else 'leave')+'_reference_mode()')
def set_reference_prefix(self, prefix): def set_reference_prefix(self, prefix):
self.javascript('reference_prefix = "%s"'%prefix) self.javascript('reference_prefix = "%s"'%prefix)
def goto(self, ref): def goto(self, ref):
self.javascript('goto_reference("%s")'%ref) self.javascript('goto_reference("%s")'%ref)
def goto_bookmark(self, bm): def goto_bookmark(self, bm):
self.javascript('scroll_to_bookmark("%s")'%bm) self.javascript('scroll_to_bookmark("%s")'%bm)
def javascript(self, string, typ=None): def javascript(self, string, typ=None):
ans = self.mainFrame().evaluateJavaScript(string) ans = self.mainFrame().evaluateJavaScript(string)
if typ == 'int': if typ == 'int':
@ -182,65 +182,65 @@ class Document(QWebPage):
if typ == 'string': if typ == 'string':
return unicode(ans.toString()) return unicode(ans.toString())
return ans return ans
def scroll_by(self, x=0, y=0): def scroll_by(self, x=0, y=0):
self.javascript('window.scrollBy(%d, %d)'%(x, y)) self.javascript('window.scrollBy(%d, %d)'%(x, y))
def scroll_to(self, x=0, y=0): def scroll_to(self, x=0, y=0):
self.javascript('window.scrollTo(%d, %d)'%(x, y)) self.javascript('window.scrollTo(%d, %d)'%(x, y))
def jump_to_anchor(self, anchor): def jump_to_anchor(self, anchor):
self.javascript('document.location.hash = "%s"'%anchor) self.javascript('document.location.hash = "%s"'%anchor)
def quantize(self): def quantize(self):
if self.height > self.window_height: if self.height > self.window_height:
r = self.height%self.window_height r = self.height%self.window_height
if r > 0: if r > 0:
self.javascript('document.body.style.paddingBottom = "%dpx"'%r) self.javascript('document.body.style.paddingBottom = "%dpx"'%r)
def bookmark(self): def bookmark(self):
return self.javascript('calculate_bookmark(%d)'%(self.ypos+25), 'string') return self.javascript('calculate_bookmark(%d)'%(self.ypos+25), 'string')
@dynamic_property @dynamic_property
def at_bottom(self): def at_bottom(self):
def fget(self): def fget(self):
return self.height - self.ypos <= self.window_height return self.height - self.ypos <= self.window_height
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def at_top(self): def at_top(self):
def fget(self): def fget(self):
return self.ypos <= 0 return self.ypos <= 0
return property(fget=fget) return property(fget=fget)
def test(self): def test(self):
pass pass
@dynamic_property @dynamic_property
def ypos(self): def ypos(self):
def fget(self): def fget(self):
return self.javascript('window.pageYOffset', 'int') return self.javascript('window.pageYOffset', 'int')
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def window_height(self): def window_height(self):
def fget(self): def fget(self):
return self.javascript('window.innerHeight', 'int') return self.javascript('window.innerHeight', 'int')
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def window_width(self): def window_width(self):
def fget(self): def fget(self):
return self.javascript('window.innerWidth', 'int') return self.javascript('window.innerWidth', 'int')
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def xpos(self): def xpos(self):
def fget(self): def fget(self):
return self.javascript('window.pageXOffset', 'int') return self.javascript('window.pageXOffset', 'int')
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def scroll_fraction(self): def scroll_fraction(self):
def fget(self): def fget(self):
@ -249,19 +249,19 @@ class Document(QWebPage):
except ZeroDivisionError: except ZeroDivisionError:
return 0. return 0.
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def hscroll_fraction(self): def hscroll_fraction(self):
def fget(self): def fget(self):
return float(self.xpos)/self.width return float(self.xpos)/self.width
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def height(self): def height(self):
def fget(self): def fget(self):
return self.javascript('document.body.offsetHeight', 'int') # contentsSize gives inaccurate results return self.javascript('document.body.offsetHeight', 'int') # contentsSize gives inaccurate results
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def width(self): def width(self):
def fget(self): def fget(self):
@ -269,7 +269,7 @@ class Document(QWebPage):
return property(fget=fget) return property(fget=fget)
class EntityDeclarationProcessor(object): class EntityDeclarationProcessor(object):
def __init__(self, html): def __init__(self, html):
self.declared_entities = {} self.declared_entities = {}
for match in re.finditer(r'<!\s*ENTITY\s+([^>]+)>', html): 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) self.processed_html = self.processed_html.replace('&%s;'%key, val)
class DocumentView(QWebView): class DocumentView(QWebView):
DISABLED_BRUSH = QBrush(Qt.lightGray, Qt.Dense5Pattern) DISABLED_BRUSH = QBrush(Qt.lightGray, Qt.Dense5Pattern)
def __init__(self, *args): def __init__(self, *args):
QWidget.__init__(self, *args) QWidget.__init__(self, *args)
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) 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('linkClicked(QUrl)'), self.link_clicked)
self.connect(self.document, SIGNAL('linkHovered(QString,QString,QString)'), self.link_hovered) self.connect(self.document, SIGNAL('linkHovered(QString,QString,QString)'), self.link_hovered)
self.connect(self.document, SIGNAL('selectionChanged()'), self.selection_changed) self.connect(self.document, SIGNAL('selectionChanged()'), self.selection_changed)
def reference_mode(self, enable): def reference_mode(self, enable):
self._reference_mode = enable self._reference_mode = enable
self.document.reference_mode(enable) self.document.reference_mode(enable)
def goto(self, ref): def goto(self, ref):
self.document.goto(ref) self.document.goto(ref)
def goto_bookmark(self, bm): def goto_bookmark(self, bm):
self.document.goto_bookmark(bm) self.document.goto_bookmark(bm)
def config(self, parent=None): def config(self, parent=None):
self.document.do_config(parent) self.document.do_config(parent)
def bookmark(self): def bookmark(self):
return self.document.bookmark() return self.document.bookmark()
def selection_changed(self): def selection_changed(self):
if self.manager is not None: if self.manager is not None:
self.manager.selection_changed(unicode(self.document.selectedText())) self.manager.selection_changed(unicode(self.document.selectedText()))
def set_manager(self, manager): def set_manager(self, manager):
self.manager = manager self.manager = manager
self.scrollbar = manager.horizontal_scrollbar self.scrollbar = manager.horizontal_scrollbar
self.connect(self.scrollbar, SIGNAL('valueChanged(int)'), self.scroll_horizontally) self.connect(self.scrollbar, SIGNAL('valueChanged(int)'), self.scroll_horizontally)
def scroll_horizontally(self, amount): def scroll_horizontally(self, amount):
self.document.scroll_to(y=self.document.ypos, x=amount) self.document.scroll_to(y=self.document.ypos, x=amount)
def link_hovered(self, link, text, context): def link_hovered(self, link, text, context):
link, text = unicode(link), unicode(text) link, text = unicode(link), unicode(text)
if link: if link:
self.setCursor(Qt.PointingHandCursor) self.setCursor(Qt.PointingHandCursor)
else: else:
self.unsetCursor() self.unsetCursor()
def link_clicked(self, url): def link_clicked(self, url):
if self.manager is not None: if self.manager is not None:
self.manager.link_clicked(url) self.manager.link_clicked(url)
def sizeHint(self): def sizeHint(self):
return self._size_hint return self._size_hint
@dynamic_property @dynamic_property
def scroll_fraction(self): def scroll_fraction(self):
def fget(self): def fget(self):
return self.document.scroll_fraction return self.document.scroll_fraction
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def hscroll_fraction(self): def hscroll_fraction(self):
def fget(self): def fget(self):
return self.document.hscroll_fraction return self.document.hscroll_fraction
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def content_size(self): def content_size(self):
def fget(self): def fget(self):
return self.document.width, self.document.height return self.document.width, self.document.height
return property(fget=fget) return property(fget=fget)
def search(self, text): def search(self, text):
return self.findText(text) return self.findText(text)
def path(self): def path(self):
return os.path.abspath(unicode(self.url().toLocalFile())) return os.path.abspath(unicode(self.url().toLocalFile()))
def load_path(self, path, pos=0.0): def load_path(self, path, pos=0.0):
self.initial_pos = pos 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 html = EntityDeclarationProcessor(html).processed_html
self.setHtml(html, QUrl.fromLocalFile(path)) self.setHtml(html, QUrl.fromLocalFile(path))
def load_started(self): def load_started(self):
if self.manager is not None: if self.manager is not None:
self.manager.load_started() self.manager.load_started()
def initialize_scrollbar(self): def initialize_scrollbar(self):
if getattr(self, 'scrollbar', None) is not None: if getattr(self, 'scrollbar', None) is not None:
delta = self.document.width - self.size().width() delta = self.document.width - self.size().width()
@ -387,7 +387,7 @@ class DocumentView(QWebView):
self.scrollbar.setPageStep(int(delta/10.)) self.scrollbar.setPageStep(int(delta/10.))
self.scrollbar.blockSignals(False) self.scrollbar.blockSignals(False)
self.scrollbar.setVisible(delta > 0) self.scrollbar.setVisible(delta > 0)
def load_finished(self, ok): def load_finished(self, ok):
self.document.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff) self.document.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
self.document.mainFrame().setScrollBarPolicy(Qt.Horizontal, 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)) self.document.set_reference_prefix('%d.'%(spine_index+1))
if scrolled: if scrolled:
self.manager.scrolled(self.document.scroll_fraction) self.manager.scrolled(self.document.scroll_fraction)
@classmethod @classmethod
def test_line(cls, img, y): def test_line(cls, img, y):
start = img.pixel(0, y) start = img.pixel(0, y)
@ -418,7 +418,7 @@ class DocumentView(QWebView):
if img.pixel(i, y) != start: if img.pixel(i, y) != start:
return False return False
return True return True
def find_next_blank_line(self, overlap): def find_next_blank_line(self, overlap):
img = QImage(self.width(), overlap, QImage.Format_ARGB32) img = QImage(self.width(), overlap, QImage.Format_ARGB32)
painter = QPainter(img) painter = QPainter(img)
@ -428,8 +428,8 @@ class DocumentView(QWebView):
if self.test_line(img, i): if self.test_line(img, i):
self.scroll_by(y=i, notify=False) self.scroll_by(y=i, notify=False)
return return
self.scroll_by(y=overlap) self.scroll_by(y=overlap)
def previous_page(self): def previous_page(self):
if self.document.at_top: if self.document.at_top:
if self.manager is not None: if self.manager is not None:
@ -448,12 +448,12 @@ class DocumentView(QWebView):
break break
if self.manager is not None: if self.manager is not None:
self.manager.scrolled(self.scroll_fraction) self.manager.scrolled(self.scroll_fraction)
def wheel_event(self, down=True): def wheel_event(self, down=True):
QWebView.wheelEvent(self, QWebView.wheelEvent(self,
QWheelEvent(QPoint(100, 100), (-120 if down else 120), QWheelEvent(QPoint(100, 100), (-120 if down else 120),
Qt.NoButton, Qt.NoModifier)) Qt.NoButton, Qt.NoModifier))
def next_page(self): def next_page(self):
if self.document.at_bottom: if self.document.at_bottom:
if self.manager is not None: if self.manager is not None:
@ -472,14 +472,14 @@ class DocumentView(QWebView):
self.find_next_blank_line( self.height() - (self.document.ypos-opos) ) self.find_next_blank_line( self.height() - (self.document.ypos-opos) )
if self.manager is not None: if self.manager is not None:
self.manager.scrolled(self.scroll_fraction) self.manager.scrolled(self.scroll_fraction)
def scroll_by(self, x=0, y=0, notify=True): def scroll_by(self, x=0, y=0, notify=True):
old_pos = self.document.ypos old_pos = self.document.ypos
self.document.scroll_by(x, y) self.document.scroll_by(x, y)
if notify and self.manager is not None and self.document.ypos != old_pos: if notify and self.manager is not None and self.document.ypos != old_pos:
self.manager.scrolled(self.scroll_fraction) self.manager.scrolled(self.scroll_fraction)
def scroll_to(self, pos, notify=True): def scroll_to(self, pos, notify=True):
old_pos = self.document.ypos old_pos = self.document.ypos
if isinstance(pos, basestring): if isinstance(pos, basestring):
@ -492,30 +492,30 @@ class DocumentView(QWebView):
pos*(self.document.height-self.document.window_height)))) pos*(self.document.height-self.document.window_height))))
if notify and self.manager is not None and self.document.ypos != old_pos: if notify and self.manager is not None and self.document.ypos != old_pos:
self.manager.scrolled(self.scroll_fraction) self.manager.scrolled(self.scroll_fraction)
def multiplier(self): def multiplier(self):
return self.document.mainFrame().textSizeMultiplier() return self.document.mainFrame().textSizeMultiplier()
def magnify_fonts(self): def magnify_fonts(self):
self.document.mainFrame().setTextSizeMultiplier(self.multiplier()+0.2) self.document.mainFrame().setTextSizeMultiplier(self.multiplier()+0.2)
return self.document.scroll_fraction return self.document.scroll_fraction
def shrink_fonts(self): def shrink_fonts(self):
self.document.mainFrame().setTextSizeMultiplier(max(self.multiplier()-0.2, 0)) self.document.mainFrame().setTextSizeMultiplier(max(self.multiplier()-0.2, 0))
return self.document.scroll_fraction return self.document.scroll_fraction
def changeEvent(self, event): def changeEvent(self, event):
if event.type() == event.EnabledChange: if event.type() == event.EnabledChange:
self.update() self.update()
return QWebView.changeEvent(self, event) return QWebView.changeEvent(self, event)
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QPainter(self)
self.document.mainFrame().render(painter, event.region()) self.document.mainFrame().render(painter, event.region())
if not self.isEnabled(): if not self.isEnabled():
painter.fillRect(event.region().boundingRect(), self.DISABLED_BRUSH) painter.fillRect(event.region().boundingRect(), self.DISABLED_BRUSH)
painter.end() painter.end()
def wheelEvent(self, event): def wheelEvent(self, event):
if event.delta() < -14: if event.delta() < -14:
if self.document.at_bottom: if self.document.at_bottom:
@ -533,7 +533,7 @@ class DocumentView(QWebView):
if self.manager is not None: if self.manager is not None:
self.manager.scrolled(self.scroll_fraction) self.manager.scrolled(self.scroll_fraction)
return ret return ret
def keyPressEvent(self, event): def keyPressEvent(self, event):
key = event.key() key = event.key()
if key in [Qt.Key_PageDown, Qt.Key_Space, Qt.Key_Down]: if key in [Qt.Key_PageDown, Qt.Key_Space, Qt.Key_Down]:
@ -562,14 +562,14 @@ class DocumentView(QWebView):
self.scroll_by(x=15) self.scroll_by(x=15)
else: else:
return QWebView.keyPressEvent(self, event) return QWebView.keyPressEvent(self, event)
def resizeEvent(self, event): def resizeEvent(self, event):
ret = QWebView.resizeEvent(self, event) ret = QWebView.resizeEvent(self, event)
QTimer.singleShot(10, self.initialize_scrollbar) QTimer.singleShot(10, self.initialize_scrollbar)
if self.manager is not None: if self.manager is not None:
self.manager.viewport_resized(self.scroll_fraction) self.manager.viewport_resized(self.scroll_fraction)
return ret return ret
def mouseReleaseEvent(self, ev): def mouseReleaseEvent(self, ev):
opos = self.document.ypos opos = self.document.ypos
ret = QWebView.mouseReleaseEvent(self, ev) ret = QWebView.mouseReleaseEvent(self, ev)
@ -578,4 +578,4 @@ class DocumentView(QWebView):
self.manager.scrolled(self.scroll_fraction) self.manager.scrolled(self.scroll_fraction)
return ret return ret

View File

@ -18,7 +18,7 @@ function find_enclosing_block(y) {
if (min != 0 && min.height() < 200) break; if (min != 0 && min.height() < 200) break;
} }
if (y <= 0) return document.body; 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; return min;
} }
@ -93,7 +93,7 @@ function enter_reference_mode() {
} }
function leave_reference_mode() { function leave_reference_mode() {
$("p").unbind("mouseenter mouseleave", toggle_reference); $("p").unbind("mouseenter mouseleave", toggle_reference);
} }
function goto_reference(ref) { function goto_reference(ref) {
@ -118,4 +118,4 @@ $(document.body).click(function(e) {
$(document).ready(enter_reference_mode); $(document).ready(enter_reference_mode);
''' '''

View File

@ -27,7 +27,7 @@ from calibre.gui2.library import SearchBox
from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata import MetaInformation
class TOCItem(QStandardItem): class TOCItem(QStandardItem):
def __init__(self, toc): def __init__(self, toc):
QStandardItem.__init__(self, toc.text if toc.text else '') QStandardItem.__init__(self, toc.text if toc.text else '')
self.abspath = toc.abspath self.abspath = toc.abspath
@ -35,23 +35,23 @@ class TOCItem(QStandardItem):
for t in toc: for t in toc:
self.appendRow(TOCItem(t)) self.appendRow(TOCItem(t))
self.setFlags(Qt.ItemIsEnabled|Qt.ItemIsSelectable) self.setFlags(Qt.ItemIsEnabled|Qt.ItemIsSelectable)
@classmethod @classmethod
def type(cls): def type(cls):
return QStandardItem.UserType+10 return QStandardItem.UserType+10
class TOC(QStandardItemModel): class TOC(QStandardItemModel):
def __init__(self, toc): def __init__(self, toc):
QStandardItemModel.__init__(self) QStandardItemModel.__init__(self)
for t in toc: for t in toc:
self.appendRow(TOCItem(t)) self.appendRow(TOCItem(t))
self.setHorizontalHeaderItem(0, QStandardItem(_('Table of Contents'))) self.setHorizontalHeaderItem(0, QStandardItem(_('Table of Contents')))
class Worker(Thread): class Worker(Thread):
def run(self): def run(self):
try: try:
Thread.run(self) Thread.run(self)
@ -61,7 +61,7 @@ class Worker(Thread):
self.traceback = traceback.format_exc() self.traceback = traceback.format_exc()
class ProgressIndicator(QWidget): class ProgressIndicator(QWidget):
def __init__(self, *args): def __init__(self, *args):
QWidget.__init__(self, *args) QWidget.__init__(self, *args)
self.setGeometry(0, 0, 300, 500) self.setGeometry(0, 0, 300, 500)
@ -76,7 +76,7 @@ class ProgressIndicator(QWidget):
self.status.font().setBold(True) self.status.font().setBold(True)
self.status.font().setPointSize(self.font().pointSize()+6) self.status.font().setPointSize(self.font().pointSize()+6)
self.setVisible(False) self.setVisible(False)
def start(self, msg=''): def start(self, msg=''):
view = self.parent() view = self.parent()
pwidth, pheight = view.size().width(), view.size().height() pwidth, pheight = view.size().width(), view.size().height()
@ -89,25 +89,25 @@ class ProgressIndicator(QWidget):
self.status.setText(msg) self.status.setText(msg)
self.setVisible(True) self.setVisible(True)
self.movie.setPaused(False) self.movie.setPaused(False)
def stop(self): def stop(self):
if self.movie.state() == self.movie.Running: if self.movie.state() == self.movie.Running:
self.movie.setPaused(True) self.movie.setPaused(True)
self.setVisible(False) self.setVisible(False)
class History(collections.deque): class History(collections.deque):
def __init__(self, action_back, action_forward): def __init__(self, action_back, action_forward):
self.action_back = action_back self.action_back = action_back
self.action_forward = action_forward self.action_forward = action_forward
collections.deque.__init__(self) collections.deque.__init__(self)
self.pos = 0 self.pos = 0
self.set_actions() self.set_actions()
def set_actions(self): def set_actions(self):
self.action_back.setDisabled(self.pos < 1) self.action_back.setDisabled(self.pos < 1)
self.action_forward.setDisabled(self.pos + 1 >= len(self)) self.action_forward.setDisabled(self.pos + 1 >= len(self))
def back(self, from_pos): def back(self, from_pos):
if self.pos - 1 < 0: return None if self.pos - 1 < 0: return None
if self.pos == len(self): if self.pos == len(self):
@ -116,56 +116,56 @@ class History(collections.deque):
self.pos -= 1 self.pos -= 1
self.set_actions() self.set_actions()
return self[self.pos] return self[self.pos]
def forward(self): def forward(self):
if self.pos + 1 >= len(self): return None if self.pos + 1 >= len(self): return None
self.pos += 1 self.pos += 1
self.set_actions() self.set_actions()
return self[self.pos] return self[self.pos]
def add(self, item): def add(self, item):
while len(self) > self.pos+1: while len(self) > self.pos+1:
self.pop() self.pop()
self.append(item) self.append(item)
self.pos += 1 self.pos += 1
self.set_actions() self.set_actions()
class Metadata(QLabel): class Metadata(QLabel):
def __init__(self, parent): def __init__(self, parent):
QTextBrowser.__init__(self, parent.centralWidget()) QTextBrowser.__init__(self, parent.centralWidget())
self.view = parent.splitter self.view = parent.splitter
self.setGeometry(self.view.geometry()) self.setGeometry(self.view.geometry())
self.setWordWrap(True) self.setWordWrap(True)
self.setVisible(False) self.setVisible(False)
def show_opf(self, opf): def show_opf(self, opf):
mi = MetaInformation(opf) mi = MetaInformation(opf)
html = '<h2 align="center">%s</h2>%s'%(_('Metadata'), u''.join(mi.to_html())) html = '<h2 align="center">%s</h2>%s'%(_('Metadata'), u''.join(mi.to_html()))
self.setText(html) self.setText(html)
def setVisible(self, x): def setVisible(self, x):
self.setGeometry(self.view.geometry()) self.setGeometry(self.view.geometry())
QLabel.setVisible(self, x) QLabel.setVisible(self, x)
def paintEvent(self, ev): def paintEvent(self, ev):
p = QPainter(self) p = QPainter(self)
p.fillRect(ev.region().boundingRect(), QBrush(QColor(200, 200, 200, 220), Qt.SolidPattern)) p.fillRect(ev.region().boundingRect(), QBrush(QColor(200, 200, 200, 220), Qt.SolidPattern))
p.end() p.end()
QLabel.paintEvent(self, ev) QLabel.paintEvent(self, ev)
class DoubleSpinBox(QDoubleSpinBox): class DoubleSpinBox(QDoubleSpinBox):
def set_value(self, val): def set_value(self, val):
self.blockSignals(True) self.blockSignals(True)
self.setValue(val) self.setValue(val)
self.blockSignals(False) self.blockSignals(False)
class HelpfulLineEdit(QLineEdit): class HelpfulLineEdit(QLineEdit):
HELP_TEXT = _('Go to...') HELP_TEXT = _('Go to...')
def __init__(self, *args): def __init__(self, *args):
QLineEdit.__init__(self, *args) QLineEdit.__init__(self, *args)
self.default_palette = QApplication.palette(self) self.default_palette = QApplication.palette(self)
@ -174,22 +174,22 @@ class HelpfulLineEdit(QLineEdit):
self.connect(self, SIGNAL('editingFinished()'), self.connect(self, SIGNAL('editingFinished()'),
lambda : self.emit(SIGNAL('goto(PyQt_PyObject)'), unicode(self.text()))) lambda : self.emit(SIGNAL('goto(PyQt_PyObject)'), unicode(self.text())))
self.clear_to_help_mode() self.clear_to_help_mode()
def focusInEvent(self, ev): def focusInEvent(self, ev):
self.setPalette(QApplication.palette(self)) self.setPalette(QApplication.palette(self))
if self.in_help_mode(): if self.in_help_mode():
self.setText('') self.setText('')
return QLineEdit.focusInEvent(self, ev) return QLineEdit.focusInEvent(self, ev)
def in_help_mode(self): def in_help_mode(self):
return unicode(self.text()) == self.HELP_TEXT return unicode(self.text()) == self.HELP_TEXT
def clear_to_help_mode(self): def clear_to_help_mode(self):
self.setPalette(self.gray) self.setPalette(self.gray)
self.setText(self.HELP_TEXT) self.setText(self.HELP_TEXT)
class EbookViewer(MainWindow, Ui_EbookViewer): class EbookViewer(MainWindow, Ui_EbookViewer):
def __init__(self, pathtoebook=None): def __init__(self, pathtoebook=None):
MainWindow.__init__(self, None) MainWindow.__init__(self, None)
self.setupUi(self) self.setupUi(self)
@ -224,14 +224,14 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.action_quit = QAction(self) self.action_quit = QAction(self)
self.addAction(self.action_quit) self.addAction(self.action_quit)
self.action_quit.setShortcut(Qt.CTRL+Qt.Key_Q) 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()) lambda x:QApplication.instance().quit())
self.action_copy.setDisabled(True) self.action_copy.setDisabled(True)
self.action_metadata.setCheckable(True) self.action_metadata.setCheckable(True)
self.action_metadata.setShortcut(Qt.CTRL+Qt.Key_I) self.action_metadata.setShortcut(Qt.CTRL+Qt.Key_I)
self.action_table_of_contents.setCheckable(True) self.action_table_of_contents.setCheckable(True)
self.action_reference_mode.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)) 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_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)) 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()) lambda x:self.view.next_page())
self.connect(self.action_previous_page, SIGNAL('triggered(bool)'), self.connect(self.action_previous_page, SIGNAL('triggered(bool)'),
lambda x:self.view.previous_page()) 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)) lambda x:self.find(unicode(self.search.text()), True, repeat=True))
self.connect(self.action_full_screen, SIGNAL('triggered(bool)'), self.connect(self.action_full_screen, SIGNAL('triggered(bool)'),
self.toggle_fullscreen) 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_forward, SIGNAL('triggered(bool)'), self.forward)
self.connect(self.action_preferences, SIGNAL('triggered(bool)'), lambda x: self.view.config(self)) 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.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.)) lambda x: self.goto_page(x/100.))
self.connect(self.search, SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), self.find) 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.toc, SIGNAL('clicked(QModelIndex)'), self.toc_clicked)
self.connect(self.reference, SIGNAL('goto(PyQt_PyObject)'), self.goto) self.connect(self.reference, SIGNAL('goto(PyQt_PyObject)'), self.goto)
self.bookmarks_menu = QMenu() self.bookmarks_menu = QMenu()
self.action_bookmark.setMenu(self.bookmarks_menu) self.action_bookmark.setMenu(self.bookmarks_menu)
self.set_bookmarks([]) self.set_bookmarks([])
if pathtoebook is not None: if pathtoebook is not None:
f = functools.partial(self.load_ebook, pathtoebook) f = functools.partial(self.load_ebook, pathtoebook)
QTimer.singleShot(50, f) QTimer.singleShot(50, f)
@ -277,7 +276,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.tool_bar2.setContextMenuPolicy(Qt.PreventContextMenu) self.tool_bar2.setContextMenuPolicy(Qt.PreventContextMenu)
self.tool_bar.widgetForAction(self.action_bookmark).setPopupMode(QToolButton.MenuButtonPopup) self.tool_bar.widgetForAction(self.action_bookmark).setPopupMode(QToolButton.MenuButtonPopup)
self.action_full_screen.setCheckable(True) self.action_full_screen.setCheckable(True)
self.print_menu = QMenu() self.print_menu = QMenu()
self.print_menu.addAction(QIcon(':/images/print-preview.svg'), _('Print Preview')) self.print_menu.addAction(QIcon(':/images/print-preview.svg'), _('Print Preview'))
self.action_print.setMenu(self.print_menu) self.action_print.setMenu(self.print_menu)
@ -293,18 +292,18 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.showNormal() self.showNormal()
else: else:
self.showFullScreen() self.showFullScreen()
def goto(self, ref): def goto(self, ref):
if ref: if ref:
tokens = ref.split('.') tokens = ref.split('.')
if len(tokens) > 1: if len(tokens) > 1:
spine_index = int(tokens[0]) -1 spine_index = int(tokens[0]) -1
if spine_index == self.current_index: if spine_index == self.current_index:
self.view.goto(ref) self.view.goto(ref)
else: else:
self.pending_reference = ref self.pending_reference = ref
self.load_path(self.iterator.spine[spine_index]) self.load_path(self.iterator.spine[spine_index])
def goto_bookmark(self, bm): def goto_bookmark(self, bm):
m = bm[1].split('#') m = bm[1].split('#')
if len(m) > 1: if len(m) > 1:
@ -314,39 +313,39 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
else: else:
self.pending_bookmark = bm self.pending_bookmark = bm
self.load_path(self.iterator.spine[spine_index]) self.load_path(self.iterator.spine[spine_index])
def toc_clicked(self, index): def toc_clicked(self, index):
item = self.toc_model.itemFromIndex(index) item = self.toc_model.itemFromIndex(index)
url = QUrl.fromLocalFile(item.abspath) url = QUrl.fromLocalFile(item.abspath)
if item.fragment: if item.fragment:
url.setFragment(item.fragment) url.setFragment(item.fragment)
self.link_clicked(url) self.link_clicked(url)
def selection_changed(self, selected_text): def selection_changed(self, selected_text):
self.selected_text = selected_text.strip() self.selected_text = selected_text.strip()
self.action_copy.setEnabled(bool(self.selected_text)) self.action_copy.setEnabled(bool(self.selected_text))
def copy(self, x): def copy(self, x):
if self.selected_text: if self.selected_text:
QApplication.clipboard().setText(self.selected_text) QApplication.clipboard().setText(self.selected_text)
def back(self, x): def back(self, x):
pos = self.history.back(self.pos.value()) pos = self.history.back(self.pos.value())
if pos is not None: if pos is not None:
self.goto_page(pos) self.goto_page(pos)
def forward(self, x): def forward(self, x):
pos = self.history.forward() pos = self.history.forward()
if pos is not None: if pos is not None:
self.goto_page(pos) self.goto_page(pos)
def goto_start(self): def goto_start(self):
self.goto_page(1) self.goto_page(1)
def goto_end(self): def goto_end(self):
self.goto_page(self.pos.maximum()) self.goto_page(self.pos.maximum())
def goto_page(self, new_page): def goto_page(self, new_page):
if self.current_page is not None: if self.current_page is not None:
for page in self.iterator.spine: for page in self.iterator.spine:
@ -359,7 +358,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.view.scroll_to(frac) self.view.scroll_to(frac)
else: else:
self.load_path(page, pos=frac) self.load_path(page, pos=frac)
def open_ebook(self, checked): def open_ebook(self, checked):
files = choose_files(self, 'ebook viewer open dialog', files = choose_files(self, 'ebook viewer open dialog',
_('Choose ebook'), _('Choose ebook'),
@ -367,19 +366,19 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
select_only_single_file=True) select_only_single_file=True)
if files: if files:
self.load_ebook(files[0]) self.load_ebook(files[0])
def font_size_larger(self, checked): def font_size_larger(self, checked):
frac = self.view.magnify_fonts() frac = self.view.magnify_fonts()
self.action_font_size_larger.setEnabled(self.view.multiplier() < 3) self.action_font_size_larger.setEnabled(self.view.multiplier() < 3)
self.action_font_size_smaller.setEnabled(self.view.multiplier() > 0.2) self.action_font_size_smaller.setEnabled(self.view.multiplier() > 0.2)
self.set_page_number(frac) self.set_page_number(frac)
def font_size_smaller(self, checked): def font_size_smaller(self, checked):
frac = self.view.shrink_fonts() frac = self.view.shrink_fonts()
self.action_font_size_larger.setEnabled(self.view.multiplier() < 3) self.action_font_size_larger.setEnabled(self.view.multiplier() < 3)
self.action_font_size_smaller.setEnabled(self.view.multiplier() > 0.2) self.action_font_size_smaller.setEnabled(self.view.multiplier() > 0.2)
self.set_page_number(frac) self.set_page_number(frac)
def bookmark(self, *args): def bookmark(self, *args):
title, ok = QInputDialog.getText(self, _('Add bookmark'), _('Enter title for bookmark:')) title, ok = QInputDialog.getText(self, _('Add bookmark'), _('Enter title for bookmark:'))
title = unicode(title).strip() title = unicode(title).strip()
@ -388,8 +387,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
bookmark = '%d#%s'%(self.current_index, pos) bookmark = '%d#%s'%(self.current_index, pos)
self.iterator.add_bookmark((title, bookmark)) self.iterator.add_bookmark((title, bookmark))
self.set_bookmarks(self.iterator.bookmarks) self.set_bookmarks(self.iterator.bookmarks)
def find(self, text, refinement, repeat=False): def find(self, text, refinement, repeat=False):
if not text: if not text:
return return
@ -401,18 +400,18 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
if self.current_index > 0: if self.current_index > 0:
index = self.iterator.search(text, 0) index = self.iterator.search(text, 0)
if index is None: if index is None:
info_dialog(self, _('No matches found'), info_dialog(self, _('No matches found'),
_('No matches found for: %s')%text).exec_() _('No matches found for: %s')%text).exec_()
return return
return return
self.pending_search = text self.pending_search = text
self.load_path(self.iterator.spine[index]) self.load_path(self.iterator.spine[index])
def do_search(self, text): def do_search(self, text):
self.pending_search = None self.pending_search = None
if self.view.search(text): if self.view.search(text):
self.scrolled(self.view.scroll_fraction) self.scrolled(self.view.scroll_fraction)
def keyPressEvent(self, event): def keyPressEvent(self, event):
if event.key() == Qt.Key_F3: if event.key() == Qt.Key_F3:
text = unicode(self.search.text()) text = unicode(self.search.text())
@ -421,10 +420,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.search.setFocus(Qt.OtherFocusReason) self.search.setFocus(Qt.OtherFocusReason)
else: else:
return MainWindow.keyPressEvent(self, event) return MainWindow.keyPressEvent(self, event)
def internal_link_clicked(self, frac): def internal_link_clicked(self, frac):
self.history.add(self.pos.value()) self.history.add(self.pos.value())
def link_clicked(self, url): def link_clicked(self, url):
path = os.path.abspath(unicode(url.toLocalFile())) path = os.path.abspath(unicode(url.toLocalFile()))
frag = None frag = None
@ -440,10 +439,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.view.scroll_to(frag) self.view.scroll_to(frag)
else: else:
QDesktopServices.openUrl(url) QDesktopServices.openUrl(url)
def load_started(self): def load_started(self):
self.open_progress_indicator(_('Loading flow...')) self.open_progress_indicator(_('Loading flow...'))
def load_finished(self, ok): def load_finished(self, ok):
self.close_progress_indicator() self.close_progress_indicator()
path = self.view.path() path = self.view.path()
@ -467,11 +466,11 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.goto_bookmark(self.pending_bookmark) self.goto_bookmark(self.pending_bookmark)
self.pending_bookmark = None self.pending_bookmark = None
return self.current_index return self.current_index
def load_path(self, path, pos=0.0): def load_path(self, path, pos=0.0):
self.open_progress_indicator(_('Laying out %s')%self.current_title) self.open_progress_indicator(_('Laying out %s')%self.current_title)
self.view.load_path(path, pos=pos) self.view.load_path(path, pos=pos)
def viewport_resized(self, frac): def viewport_resized(self, frac):
new_page = self.pos.value() new_page = self.pos.value()
if self.current_page is not None: if self.current_page is not None:
@ -482,20 +481,20 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.view.scroll_to(frac, notify=False) self.view.scroll_to(frac, notify=False)
else: else:
self.set_page_number(frac) self.set_page_number(frac)
def close_progress_indicator(self): def close_progress_indicator(self):
self.pi.stop() self.pi.stop()
for o in ('tool_bar', 'tool_bar2', 'view', 'horizontal_scrollbar', 'vertical_scrollbar'): for o in ('tool_bar', 'tool_bar2', 'view', 'horizontal_scrollbar', 'vertical_scrollbar'):
getattr(self, o).setEnabled(True) getattr(self, o).setEnabled(True)
self.unsetCursor() self.unsetCursor()
self.view.setFocus(Qt.PopupFocusReason) self.view.setFocus(Qt.PopupFocusReason)
def open_progress_indicator(self, msg=''): def open_progress_indicator(self, msg=''):
self.pi.start(msg) self.pi.start(msg)
for o in ('tool_bar', 'tool_bar2', 'view', 'horizontal_scrollbar', 'vertical_scrollbar'): for o in ('tool_bar', 'tool_bar2', 'view', 'horizontal_scrollbar', 'vertical_scrollbar'):
getattr(self, o).setEnabled(False) getattr(self, o).setEnabled(False)
self.setCursor(Qt.BusyCursor) self.setCursor(Qt.BusyCursor)
def set_bookmarks(self, bookmarks): def set_bookmarks(self, bookmarks):
self.bookmarks_menu.clear() self.bookmarks_menu.clear()
self.bookmarks_menu.addAction(_("Manage Bookmarks"), self.manage_bookmarks) self.bookmarks_menu.addAction(_("Manage Bookmarks"), self.manage_bookmarks)
@ -507,19 +506,19 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
else: else:
self.bookmarks_menu.addAction(bm[0], partial(self.goto_bookmark, bm)) self.bookmarks_menu.addAction(bm[0], partial(self.goto_bookmark, bm))
return current_page return current_page
def manage_bookmarks(self): def manage_bookmarks(self):
bmm = BookmarkManager(self, self.iterator.bookmarks) bmm = BookmarkManager(self, self.iterator.bookmarks)
if bmm.exec_() != BookmarkManager.Accepted: if bmm.exec_() != BookmarkManager.Accepted:
return return
bookmarks = bmm.get_bookmarks() bookmarks = bmm.get_bookmarks()
if bookmarks != self.iterator.bookmarks: if bookmarks != self.iterator.bookmarks:
self.iterator.set_bookmarks(bookmarks) self.iterator.set_bookmarks(bookmarks)
self.iterator.save_bookmarks() self.iterator.save_bookmarks()
self.set_bookmarks(bookmarks) self.set_bookmarks(bookmarks)
def save_current_position(self): def save_current_position(self):
try: try:
pos = self.view.bookmark() pos = self.view.bookmark()
@ -527,7 +526,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.iterator.add_bookmark(('calibre_current_page_bookmark', bookmark)) self.iterator.add_bookmark(('calibre_current_page_bookmark', bookmark))
except: except:
traceback.print_exc() traceback.print_exc()
def load_ebook(self, pathtoebook): def load_ebook(self, pathtoebook):
if self.iterator is not None: if self.iterator is not None:
self.save_current_position() self.save_current_position()
@ -543,7 +542,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
if isinstance(worker.exception, DRMError): 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_() error_dialog(self, _('DRM Error'), _('<p>This book is protected by <a href="%s">DRM</a>')%'http://wiki.mobileread.com/wiki/DRM').exec_()
else: 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) _('<b>%s</b><br/><p>%s</p>')%(worker.exception, worker.traceback.replace('\n', '<br>')), show=True)
self.close_progress_indicator() self.close_progress_indicator()
else: else:
@ -571,37 +570,37 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.goto_bookmark(previous) self.goto_bookmark(previous)
else: else:
self.next_document() self.next_document()
def set_vscrollbar_value(self, pagenum): def set_vscrollbar_value(self, pagenum):
self.vertical_scrollbar.blockSignals(True) self.vertical_scrollbar.blockSignals(True)
self.vertical_scrollbar.setValue(int(pagenum*100)) self.vertical_scrollbar.setValue(int(pagenum*100))
self.vertical_scrollbar.blockSignals(False) self.vertical_scrollbar.blockSignals(False)
def set_page_number(self, frac): def set_page_number(self, frac):
if getattr(self, 'current_page', None) is not None: if getattr(self, 'current_page', None) is not None:
page = self.current_page.start_page + frac*float(self.current_page.pages-1) page = self.current_page.start_page + frac*float(self.current_page.pages-1)
self.pos.set_value(page) self.pos.set_value(page)
self.set_vscrollbar_value(page) self.set_vscrollbar_value(page)
def scrolled(self, frac): def scrolled(self, frac):
self.set_page_number(frac) self.set_page_number(frac)
def next_document(self): def next_document(self):
if self.current_index < len(self.iterator.spine) - 1: if self.current_index < len(self.iterator.spine) - 1:
self.load_path(self.iterator.spine[self.current_index+1]) self.load_path(self.iterator.spine[self.current_index+1])
def previous_document(self): def previous_document(self):
if self.current_index > 0: if self.current_index > 0:
self.load_path(self.iterator.spine[self.current_index-1], pos=1.0) self.load_path(self.iterator.spine[self.current_index-1], pos=1.0)
def __enter__(self): def __enter__(self):
return self return self
def __exit__(self, *args): def __exit__(self, *args):
if self.iterator is not None: if self.iterator is not None:
self.save_current_position() self.save_current_position()
self.iterator.__exit__(*args) self.iterator.__exit__(*args)
def config(defaults=None): def config(defaults=None):
desc = _('Options to control the ebook viewer') desc = _('Options to control the ebook viewer')
@ -609,8 +608,8 @@ def config(defaults=None):
c = Config('viewer', desc) c = Config('viewer', desc)
else: else:
c = StringConfig(defaults, desc) 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 ' help=_('If specified, viewer window will try to come to the '
'front when started.')) 'front when started.'))
return c return c
@ -620,7 +619,7 @@ def option_parser():
return c.option_parser(usage=_('''\ return c.option_parser(usage=_('''\
%prog [options] file %prog [options] file
View an ebook. View an ebook.
''')) '''))
@ -639,7 +638,7 @@ def main(args=sys.argv):
if opts.raise_window: if opts.raise_window:
main.raise_() main.raise_()
with main: with main:
return app.exec_() return app.exec_()
return 0 return 0
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -37,7 +37,7 @@ recipe_modules = ['recipe_' + r for r in (
'new_york_review_of_books_no_sub', 'politico', 'adventuregamers', 'new_york_review_of_books_no_sub', 'politico', 'adventuregamers',
'mondedurable', 'instapaper', 'dnevnik_cro', 'vecernji_list', 'mondedurable', 'instapaper', 'dnevnik_cro', 'vecernji_list',
'nacional_cro', '24sata', 'dnevni_avaz', 'glas_srpske', '24sata_rs', '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 import re, imp, inspect, time, os

View 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,'')

View File

@ -26,7 +26,8 @@ def initview(request):
5. The feeds for the site (ids) 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.get('REQUEST_URI', request.META.get('PATH_INFO', '/')), \
request.META['QUERY_STRING']) request.META['QUERY_STRING'])
response = fjcache.cache_get(site_id, cachekey) response = fjcache.cache_get(site_id, cachekey)

View File

@ -1,4 +1,4 @@
#!/bin/sh #!/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 ssh divok /etc/init.d/apache2 graceful

View File

@ -52,7 +52,7 @@
<img <img
src="{{ MEDIA_URL }}/img/faces/{{ item.subscriber.shortname}}.png" alt="" /> src="{{ MEDIA_URL }}/img/faces/{{ item.subscriber.shortname}}.png" alt="" />
<div class="url"> <div class="url">
{{ item.feed.title|safe }} {{ item.feed.name|safe }}
</div> </div>
</a> </a>
</div> </div>

View File

@ -667,9 +667,16 @@ class stage3(OptionlessCommand):
def misc(cls): def misc(cls):
check_call('ssh divok rm -f %s/calibre-\*.tar.gz'%DOWNLOADS, shell=True) 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('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('''rm -rf dist/* build/*''', shell=True)
check_call('ssh divok bzr update /var/www/calibre.kovidgoyal.net/calibre/', check_call('ssh divok bzr update /var/www/calibre.kovidgoyal.net/calibre/',
shell=True) shell=True)
check_call('ssh divok bzr update /usr/local/calibre',
shell=True)
def run(self): def run(self):
OptionlessCommand.run(self) OptionlessCommand.run(self)