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
let g:pyflakes_builtins += ["dynamic_property", '__']
let g:pyflakes_builtins += ["dynamic_property", "__"]
python << EOFPY
import os

View File

@ -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.

View File

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

View File

@ -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)

View File

@ -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('')

View File

@ -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>

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, \
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)

View File

@ -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

View File

@ -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);
'''
'''

View File

@ -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__':

View File

@ -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

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)
"""
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)

View File

@ -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

View File

@ -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>

View File

@ -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)