KG wip 0.7.33+

This commit is contained in:
GRiker 2010-12-16 13:09:36 -07:00
commit 167fbe94a4
13 changed files with 444 additions and 133 deletions

View File

@ -5,6 +5,7 @@ newscientist.com
'''
import re
import urllib
from calibre.web.feeds.news import BasicNewsRecipe
class NewScientist(BasicNewsRecipe):
@ -24,7 +25,7 @@ class NewScientist(BasicNewsRecipe):
needs_subscription = 'optional'
extra_css = """
body{font-family: Arial,sans-serif}
img{margin-bottom: 0.8em}
img{margin-bottom: 0.8em; display: block}
.quotebx{font-size: x-large; font-weight: bold; margin-right: 2em; margin-left: 2em}
"""
@ -41,12 +42,14 @@ class NewScientist(BasicNewsRecipe):
def get_browser(self):
br = BasicNewsRecipe.get_browser()
br.open('http://www.newscientist.com/')
if self.username is not None and self.password is not None:
br.open('https://www.newscientist.com/user/login?redirectURL=')
br.select_form(nr=2)
br['loginId' ] = self.username
br['password'] = self.password
br.submit()
if self.username is not None and self.password is not None:
br.open('https://www.newscientist.com/user/login')
data = urllib.urlencode({ 'source':'form'
,'redirectURL':''
,'loginId':self.username
,'password':self.password
})
br.open('https://www.newscientist.com/user/login',data)
return br
remove_tags = [
@ -55,21 +58,22 @@ class NewScientist(BasicNewsRecipe):
,dict(name='p' , attrs={'class':['marker','infotext' ]})
,dict(name='meta' , attrs={'name' :'description' })
,dict(name='a' , attrs={'rel' :'tag' })
,dict(name='ul' , attrs={'class':'markerlist' })
,dict(name=['link','base','meta','iframe','object','embed'])
]
remove_tags_after = dict(attrs={'class':['nbpcopy','comments']})
remove_attributes = ['height','width','lang']
remove_attributes = ['height','width','lang','onclick']
feeds = [
(u'Latest Headlines' , u'http://feeds.newscientist.com/science-news' )
,(u'Magazine' , u'http://www.newscientist.com/feed/magazine' )
,(u'Health' , u'http://www.newscientist.com/feed/view?id=2&type=channel' )
,(u'Life' , u'http://www.newscientist.com/feed/view?id=3&type=channel' )
,(u'Space' , u'http://www.newscientist.com/feed/view?id=6&type=channel' )
,(u'Physics and Mathematics' , u'http://www.newscientist.com/feed/view?id=4&type=channel' )
,(u'Environment' , u'http://www.newscientist.com/feed/view?id=1&type=channel' )
,(u'Science in Society' , u'http://www.newscientist.com/feed/view?id=5&type=channel' )
,(u'Tech' , u'http://www.newscientist.com/feed/view?id=7&type=channel' )
(u'Latest Headlines' , u'http://feeds.newscientist.com/science-news' )
,(u'Magazine' , u'http://feeds.newscientist.com/magazine' )
,(u'Health' , u'http://feeds.newscientist.com/health' )
,(u'Life' , u'http://feeds.newscientist.com/life' )
,(u'Space' , u'http://feeds.newscientist.com/space' )
,(u'Physics and Mathematics' , u'http://feeds.newscientist.com/physics-math' )
,(u'Environment' , u'http://feeds.newscientist.com/environment' )
,(u'Science in Society' , u'http://feeds.newscientist.com/science-in-society' )
,(u'Tech' , u'http://feeds.newscientist.com/tech' )
]
def get_article_url(self, article):
@ -79,11 +83,21 @@ class NewScientist(BasicNewsRecipe):
return url + '?full=true&print=true'
def preprocess_html(self, soup):
if soup.html.has_key('id'):
del soup.html['id']
for item in soup.findAll(style=True):
del item['style']
for item in soup.findAll(['quote','quotetext']):
item.name='p'
for item in soup.findAll(['xref','figref']):
tstr = item.string
item.replaceWith(tstr)
for tg in soup.findAll('a'):
if tg.string == 'Home':
tg.parent.extract()
return self.adeify_images(soup)
return self.adeify_images(soup)
else:
if tg.string is not None:
tstr = tg.string
tg.replaceWith(tstr)
return soup

View File

@ -13,14 +13,16 @@ class Radikal_tr(BasicNewsRecipe):
description = 'News from Turkey'
publisher = 'radikal'
category = 'news, politics, Turkey'
oldest_article = 2
oldest_article = 7
max_articles_per_feed = 150
no_stylesheets = True
encoding = 'cp1254'
use_embedded_content = False
masthead_url = 'http://www.radikal.com.tr/D/i/1/V2/radikal_logo.jpg'
language = 'tr'
extra_css = ' @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} .article_description,body{font-family: Arial,Verdana,Helvetica,sans1,sans-serif } '
extra_css = """ @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
.article_description,body{font-family: Arial,Verdana,Helvetica,sans1,sans-serif}
"""
conversion_options = {
'comment' : description
@ -34,7 +36,13 @@ class Radikal_tr(BasicNewsRecipe):
remove_tags_after = dict(attrs={'id':'haberDetayYazi'})
feeds = [(u'Yazarlar', u'http://www.radikal.com.tr/d/rss/RssYazarlar.xml')]
feeds = [
(u'Yazarlar' , u'http://www.radikal.com.tr/d/rss/RssYazarlar.xml')
,(u'Turkiye' , u'http://www.radikal.com.tr/d/rss/Rss_97.xml' )
,(u'Politika' , u'http://www.radikal.com.tr/d/rss/Rss_98.xml' )
,(u'Dis Haberler', u'http://www.radikal.com.tr/d/rss/Rss_100.xml' )
,(u'Ekonomi' , u'http://www.radikal.com.tr/d/rss/Rss_101.xml' )
]
def print_version(self, url):
articleid = url.rpartition('ArticleID=')[2]

View File

@ -457,7 +457,8 @@ from calibre.devices.blackberry.driver import BLACKBERRY
from calibre.devices.cybook.driver import CYBOOK, ORIZON
from calibre.devices.eb600.driver import EB600, COOL_ER, SHINEBOOK, \
POCKETBOOK360, GER2, ITALICA, ECLICTO, DBOOK, INVESBOOK, \
BOOQ, ELONEX, POCKETBOOK301, MENTOR, POCKETBOOK602
BOOQ, ELONEX, POCKETBOOK301, MENTOR, POCKETBOOK602, \
POCKETBOOK701
from calibre.devices.iliad.driver import ILIAD
from calibre.devices.irexdr.driver import IREXDR1000, IREXDR800
from calibre.devices.jetbook.driver import JETBOOK, MIBUK, JETBOOK_MINI
@ -545,9 +546,7 @@ plugins += [
JETBOOK_MINI,
MIBUK,
SHINEBOOK,
POCKETBOOK360,
POCKETBOOK301,
POCKETBOOK602,
POCKETBOOK360, POCKETBOOK301, POCKETBOOK602, POCKETBOOK701,
KINDLE,
KINDLE2,
KINDLE_DX,

View File

@ -246,3 +246,23 @@ class POCKETBOOK602(USBMS):
VENDOR_NAME = ''
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['PB602', 'PB902']
class POCKETBOOK701(USBMS):
name = 'PocketBook 701 Device Interface'
description = _('Communicate with the PocketBook 701')
author = _('Kovid Goyal')
supported_platforms = ['windows', 'osx', 'linux']
FORMATS = ['epub', 'fb2', 'prc', 'mobi', 'pdf', 'djvu', 'rtf', 'chm',
'doc', 'tcr', 'txt']
EBOOK_DIR_MAIN = 'books'
SUPPORTS_SUB_DIRS = True
VENDOR_ID = [0x18d1]
PRODUCT_ID = [0xa004]
BCD = [0x0224]
VENDOR_NAME = 'ANDROID'
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = '__UMS_COMPOSITE'

View File

@ -23,16 +23,16 @@ class SNE(USBMS):
FORMATS = ['epub', 'pdf', 'txt']
VENDOR_ID = [0x04e8]
PRODUCT_ID = [0x2051, 0x2053]
PRODUCT_ID = [0x2051, 0x2053, 0x2054]
BCD = [0x0323]
VENDOR_NAME = 'SAMSUNG'
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'SNE-60'
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['SNE-60', 'E65']
MAIN_MEMORY_VOLUME_LABEL = 'SNE Main Memory'
STORAGE_CARD_VOLUME_LABEL = 'SNE Storage Card'
EBOOK_DIR_MAIN = 'Books'
EBOOK_DIR_MAIN = EBOOK_DIR_CARD_A = 'Books'
SUPPORTS_SUB_DIRS = True

View File

@ -22,6 +22,9 @@ class UnknownFormatError(Exception):
class DRMError(ValueError):
pass
class ParserError(ValueError):
pass
BOOK_EXTENSIONS = ['lrf', 'rar', 'zip', 'rtf', 'lit', 'txt', 'htm', 'xhtm',
'html', 'xhtml', 'pdf', 'pdb', 'pdr', 'prc', 'mobi', 'azw', 'doc',
'epub', 'fb2', 'djvu', 'lrx', 'cbr', 'cbz', 'cbc', 'oebzip',
@ -39,6 +42,10 @@ class HTMLRenderer(object):
try:
if not ok:
raise RuntimeError('Rendering of HTML failed.')
de = self.page.mainFrame().documentElement()
pe = de.findFirst('parsererror')
if not pe.isNull():
raise ParserError(pe.toPlainText())
image = QImage(self.page.viewportSize(), QImage.Format_ARGB32)
image.setDotsPerMeterX(96*(100/2.54))
image.setDotsPerMeterY(96*(100/2.54))
@ -104,7 +111,7 @@ def render_html_svg_workaround(path_to_html, log, width=590, height=750):
return data
def render_html(path_to_html, width=590, height=750):
def render_html(path_to_html, width=590, height=750, as_xhtml=True):
from PyQt4.QtWebKit import QWebPage
from PyQt4.Qt import QEventLoop, QPalette, Qt, SIGNAL, QUrl, QSize
from calibre.gui2 import is_ok_to_use_qt
@ -122,11 +129,18 @@ def render_html(path_to_html, width=590, height=750):
renderer = HTMLRenderer(page, loop)
page.connect(page, SIGNAL('loadFinished(bool)'), renderer,
Qt.QueuedConnection)
page.mainFrame().load(QUrl.fromLocalFile(path_to_html))
if as_xhtml:
page.mainFrame().setContent(open(path_to_html, 'rb').read(),
'application/xhtml+xml', QUrl.fromLocalFile(path_to_html))
else:
page.mainFrame().load(QUrl.fromLocalFile(path_to_html))
loop.exec_()
renderer.loop = renderer.page = None
del page
del loop
if isinstance(renderer.exception, ParserError) and as_xhtml:
return render_html(path_to_html, width=width, height=height,
as_xhtml=False)
return renderer
def check_ebook_format(stream, current_guess):

View File

@ -17,6 +17,7 @@ pdfreflow, pdfreflow_error = plugins['pdfreflow']
def get_metadata(stream, cover=True):
if pdfreflow is None:
raise RuntimeError(pdfreflow_error)
stream.seek(0)
raw = stream.read()
#isbn = _isbn_pat.search(raw)
#if isbn is not None:

View File

@ -205,7 +205,10 @@ class Stylizer(object):
NameError, # thrown on OS X instead of SelectorSyntaxError
SelectorSyntaxError):
continue
matches = selector(tree)
try:
matches = selector(tree)
except etree.XPathEvalError:
continue
if not matches:
ntext = capital_sel_pat.sub(lambda m: m.group().lower(), text)

View File

@ -593,7 +593,6 @@ class DeviceMenu(QMenu): # {{{
# }}}
class DeviceMixin(object): # {{{
def __init__(self):

View File

@ -7,14 +7,14 @@
<x>0</x>
<y>0</y>
<width>479</width>
<height>606</height>
<height>591</height>
</rect>
</property>
<property name="windowTitle">
<string>Configure Ebook viewer</string>
</property>
<property name="windowIcon">
<iconset>
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/config.png</normaloff>:/images/config.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout_4">
@ -85,11 +85,7 @@
<item row="2" column="1">
<widget class="QFontComboBox" name="mono_family"/>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Default font size:</string>
@ -99,7 +95,7 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="3" column="1">
<widget class="QSpinBox" name="default_font_size">
<property name="suffix">
<string> px</string>
@ -112,7 +108,7 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Monospace &amp;font size:</string>
@ -122,7 +118,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<item row="4" column="1">
<widget class="QSpinBox" name="mono_font_size">
<property name="suffix">
<string> px</string>
@ -135,7 +131,7 @@
</property>
</widget>
</item>
<item row="2" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>S&amp;tandard font:</string>
@ -145,7 +141,7 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="5" column="1">
<widget class="QComboBox" name="standard_font">
<item>
<property name="text">
@ -164,91 +160,125 @@
</item>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="QCheckBox" name="opt_remember_window_size">
<property name="text">
<string>Remember last used &amp;window size</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QCheckBox" name="opt_remember_current_page">
<property name="text">
<string>Remember the &amp;current page when quitting</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="max_view_width">
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Maximum &amp;view width:</string>
</property>
<property name="buddy">
<cstring>max_view_width</cstring>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="hyphenate">
<property name="text">
<string>H&amp;yphenate (break line in the middle of large words)</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="hyphenate_default_lang">
<property name="toolTip">
<string>The default language to use for hyphenation rules. If the book does not specify a language, this will be used.</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Default &amp;language for hyphenation:</string>
</property>
<property name="buddy">
<cstring>hyphenate_default_lang</cstring>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QCheckBox" name="opt_fit_images">
<property name="text">
<string>&amp;Resize images larger than the viewer window (needs restart)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>&amp;User stylesheet</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="1" column="0">
<widget class="QPlainTextEdit" name="css"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="8" column="0" colspan="2">
<widget class="QCheckBox" name="opt_remember_window_size">
<property name="text">
<string>Remember last used &amp;window size</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="QCheckBox" name="opt_remember_current_page">
<property name="text">
<string>Remember the &amp;current page when quitting</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="hyphenate">
<property name="text">
<string>H&amp;yphenate (break line in the middle of large words)</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="hyphenate_default_lang">
<property name="toolTip">
<string>The default language to use for hyphenation rules. If the book does not specify a language, this will be used.</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Default &amp;language for hyphenation:</string>
</property>
<property name="buddy">
<cstring>hyphenate_default_lang</cstring>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="QCheckBox" name="opt_fit_images">
<property name="text">
<string>&amp;Resize images larger than the viewer window (needs restart)</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Page flip &amp;duration:</string>
</property>
<property name="buddy">
<cstring>opt_page_flip_duration</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="opt_page_flip_duration">
<property name="specialValueText">
<string>disabled</string>
</property>
<property name="suffix">
<string> secs</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>3.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.500000000000000</double>
</property>
</widget>
</item>
<item row="10" column="0" colspan="2">
<widget class="QCheckBox" name="opt_wheel_flips_pages">
<property name="text">
<string>Mouse &amp;wheel flips pages</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="max_view_width">
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Maximum &amp;view width:</string>
</property>
<property name="buddy">
<cstring>max_view_width</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
@ -268,6 +298,29 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>User &amp;Stylesheet</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>&lt;p&gt;A CSS stylesheet that can be used to control the look and feel of books. For examples, click &lt;a href=&quot;http://www.mobileread.com/forums/showthread.php?t=51500&quot;&gt;here&lt;/a&gt;.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="css"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
@ -276,12 +329,8 @@
<tabstop>serif_family</tabstop>
<tabstop>sans_family</tabstop>
<tabstop>mono_family</tabstop>
<tabstop>default_font_size</tabstop>
<tabstop>mono_font_size</tabstop>
<tabstop>standard_font</tabstop>
<tabstop>max_view_width</tabstop>
<tabstop>opt_remember_window_size</tabstop>
<tabstop>css</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources>

View File

@ -18,6 +18,7 @@ from PyQt4.QtWebKit import QWebPage, QWebView, QWebSettings
from calibre.utils.config import Config, StringConfig
from calibre.utils.localization import get_language
from calibre.gui2.viewer.config_ui import Ui_Dialog
from calibre.gui2.viewer.flip import SlideFlip
from calibre.gui2.shortcuts import Shortcuts, ShortcutConfig
from calibre.constants import iswindows
from calibre import prints, guess_type
@ -52,6 +53,11 @@ def config(defaults=None):
help=_('Default language for hyphenation rules'))
c.add_opt('remember_current_page', default=True,
help=_('Save the current position in the document, when quitting'))
c.add_opt('wheel_flips_pages', default=False,
help=_('Have the mouse wheel turn pages'))
c.add_opt('page_flip_duration', default=0.5,
help=_('The time, in seconds, for the page flip animation. Default'
' is half a second.'))
fonts = c.add_group('FONTS', _('Font options'))
fonts('serif_family', default='Times New Roman' if iswindows else 'Liberation Serif',
@ -75,6 +81,8 @@ class ConfigDialog(QDialog, Ui_Dialog):
opts = config().parse()
self.opt_remember_window_size.setChecked(opts.remember_window_size)
self.opt_remember_current_page.setChecked(opts.remember_current_page)
self.opt_wheel_flips_pages.setChecked(opts.wheel_flips_pages)
self.opt_page_flip_duration.setValue(opts.page_flip_duration)
self.serif_family.setCurrentFont(QFont(opts.serif_family))
self.sans_family.setCurrentFont(QFont(opts.sans_family))
self.mono_family.setCurrentFont(QFont(opts.mono_family))
@ -122,6 +130,8 @@ class ConfigDialog(QDialog, Ui_Dialog):
c.set('max_view_width', int(self.max_view_width.value()))
c.set('hyphenate', self.hyphenate.isChecked())
c.set('remember_current_page', self.opt_remember_current_page.isChecked())
c.set('wheel_flips_pages', self.opt_wheel_flips_pages.isChecked())
c.set('page_flip_duration', self.opt_page_flip_duration.value())
idx = self.hyphenate_default_lang.currentIndex()
c.set('hyphenate_default_lang',
str(self.hyphenate_default_lang.itemData(idx).toString()))
@ -197,6 +207,9 @@ class Document(QWebPage):
self.hyphenate = opts.hyphenate
self.hyphenate_default_lang = opts.hyphenate_default_lang
self.do_fit_images = opts.fit_images
self.page_flip_duration = opts.page_flip_duration
self.enable_page_flip = self.page_flip_duration > 0.1
self.wheel_flips_pages = opts.wheel_flips_pages
def fit_images(self):
if self.do_fit_images:
@ -453,6 +466,8 @@ class DocumentView(QWebView):
def __init__(self, *args):
QWebView.__init__(self, *args)
self.flipper = SlideFlip(self)
self.is_auto_repeat_event = False
self.debug_javascript = False
self.shortcuts = Shortcuts(SHORTCUTS, 'shortcuts/viewer')
self.self_closing_pat = re.compile(r'<([a-z1-6]+)\s+([^>]+)/>',
@ -693,6 +708,13 @@ class DocumentView(QWebView):
self.manager.scrolled(self.document.scroll_fraction)
self.turn_off_internal_scrollbars()
if self.flipper.isVisible():
if self.flipper.running:
self.flipper.setVisible(False)
else:
self.flipper(self.current_page_image(),
duration=self.document.page_flip_duration)
def turn_off_internal_scrollbars(self):
self.document.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
@ -708,12 +730,17 @@ class DocumentView(QWebView):
return False
return True
def find_next_blank_line(self, overlap):
def current_page_image(self, overlap=-1):
if overlap < 0:
overlap = self.height()
img = QImage(self.width(), overlap, QImage.Format_ARGB32)
painter = QPainter(img)
# Render a region of width x overlap pixels atthe bottom of the current viewport
self.document.mainFrame().render(painter, QRegion(0, 0, self.width(), overlap))
painter.end()
return img
def find_next_blank_line(self, overlap):
img = self.current_page_image(overlap)
for i in range(overlap-1, -1, -1):
if self.test_line(img, i):
self.scroll_by(y=i, notify=False)
@ -721,22 +748,42 @@ class DocumentView(QWebView):
self.scroll_by(y=overlap)
def previous_page(self):
if self.flipper.running and not self.is_auto_repeat_event:
return
if self.loading_url is not None:
return
epf = self.document.enable_page_flip and not self.is_auto_repeat_event
delta_y = self.document.window_height - 25
if self.document.at_top:
if self.manager is not None:
self.to_bottom = True
self.manager.previous_document()
if epf:
self.flipper.initialize(self.current_page_image(), False)
self.manager.previous_document()
else:
opos = self.document.ypos
upper_limit = opos - delta_y
if upper_limit < 0:
upper_limit = 0
if upper_limit < opos:
if epf:
self.flipper.initialize(self.current_page_image(),
forwards=False)
self.document.scroll_to(self.document.xpos, upper_limit)
if epf:
self.flipper(self.current_page_image(),
duration=self.document.page_flip_duration)
if self.manager is not None:
self.manager.scrolled(self.scroll_fraction)
def next_page(self):
if self.flipper.running and not self.is_auto_repeat_event:
return
if self.loading_url is not None:
return
epf = self.document.enable_page_flip and not self.is_auto_repeat_event
window_height = self.document.window_height
document_height = self.document.height
ddelta = document_height - window_height
@ -746,6 +793,8 @@ class DocumentView(QWebView):
delta_y = window_height - 25
if self.document.at_bottom or ddelta <= 0:
if self.manager is not None:
if epf:
self.flipper.initialize(self.current_page_image())
self.manager.next_document()
elif ddelta < 25:
self.scroll_by(y=ddelta)
@ -758,6 +807,8 @@ class DocumentView(QWebView):
#print 'After set padding=0:', self.document.ypos
if opos < oopos:
if self.manager is not None:
if epf:
self.flipper.initialize(self.current_page_image())
self.manager.next_document()
return
lower_limit = opos + delta_y # Max value of top y co-ord after scrolling
@ -766,10 +817,14 @@ class DocumentView(QWebView):
padding = lower_limit - max_y
if padding == window_height:
if self.manager is not None:
if epf:
self.flipper.initialize(self.current_page_image())
self.manager.next_document()
return
#print 'Setting padding to:', lower_limit - max_y
self.document.set_bottom_padding(lower_limit - max_y)
if epf:
self.flipper.initialize(self.current_page_image())
#print 'Document height:', self.document.height
max_y = self.document.height - window_height
lower_limit = min(max_y, lower_limit)
@ -780,6 +835,9 @@ class DocumentView(QWebView):
#print 'After scroll pos:', self.document.ypos
self.find_next_blank_line(window_height - actually_scrolled)
#print 'After blank line pos:', self.document.ypos
if epf:
self.flipper(self.current_page_image(),
duration=self.document.page_flip_duration)
if self.manager is not None:
self.manager.scrolled(self.scroll_fraction)
#print 'After all:', self.document.ypos
@ -833,6 +891,10 @@ class DocumentView(QWebView):
def wheelEvent(self, event):
if event.delta() < -14:
if self.document.wheel_flips_pages:
self.next_page()
event.accept()
return
if self.document.at_bottom:
self.scroll_by(y=15) # at_bottom can lie on windows
if self.manager is not None:
@ -840,6 +902,11 @@ class DocumentView(QWebView):
event.accept()
return
elif event.delta() > 14:
if self.document.wheel_flips_pages:
self.previous_page()
event.accept()
return
if self.document.at_top:
if self.manager is not None:
self.manager.previous_document()
@ -862,7 +929,11 @@ class DocumentView(QWebView):
key = self.shortcuts.get_match(event)
func = self.goto_location_actions.get(key, None)
if func is not None:
func()
self.is_auto_repeat_event = event.isAutoRepeat()
try:
func()
finally:
self.is_auto_repeat_event = False
elif key == 'Down':
self.scroll_by(y=15)
elif key == 'Up':

View File

@ -0,0 +1,116 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from PyQt4.Qt import QWidget, QPainter, QPropertyAnimation, QEasingCurve, \
QRect, QPixmap, Qt, pyqtProperty
class SlideFlip(QWidget):
# API {{{
# In addition the isVisible() and setVisible() methods must be present
def __init__(self, parent):
QWidget.__init__(self, parent)
self.setGeometry(0, 0, 1, 1)
self._current_width = 0
self.before_image = self.after_image = None
self.animation = QPropertyAnimation(self, 'current_width', self)
self.setVisible(False)
self.animation.valueChanged.connect(self.update)
self.animation.finished.connect(self.finished)
self.flip_forwards = True
self.setAttribute(Qt.WA_OpaquePaintEvent)
@property
def running(self):
'True iff animation is currently running'
return self.animation.state() == self.animation.Running
def initialize(self, image, forwards=True):
'''
Initialize the flipper, causes the flipper to show itself displaying
the full `image`.
:param image: The image to display as background
:param forwards: If True flipper will flip forwards, otherwise
backwards
'''
self.flip_forwards = forwards
self.before_image = QPixmap.fromImage(image)
self.after_image = None
self.setGeometry(0, 0, image.width(), image.height())
self.setVisible(True)
def __call__(self, image, duration=0.5):
'''
Start the animation. You must have called :meth:`initialize` first.
:param duration: Animation duration in seconds.
'''
if self.running:
return
self.after_image = QPixmap.fromImage(image)
if self.flip_forwards:
self.animation.setStartValue(image.width())
self.animation.setEndValue(0)
t = self.before_image
self.before_image = self.after_image
self.after_image = t
self.animation.setEasingCurve(QEasingCurve(QEasingCurve.InExpo))
else:
self.animation.setStartValue(0)
self.animation.setEndValue(image.width())
self.animation.setEasingCurve(QEasingCurve(QEasingCurve.OutExpo))
self.animation.setDuration(duration * 1000)
self.animation.start()
# }}}
def finished(self):
self.setVisible(False)
self.before_image = self.after_image = None
def paintEvent(self, ev):
if self.before_image is None:
return
canvas_size = self.rect()
p = QPainter(self)
p.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
p.drawPixmap(canvas_size, self.before_image,
self.before_image.rect())
if self.after_image is not None:
width = self._current_width
iw = self.after_image.width()
sh = min(self.after_image.height(), canvas_size.height())
if self.flip_forwards:
source = QRect(max(0, iw - width), 0, width, sh)
else:
source = QRect(0, 0, width, sh)
target = QRect(source)
target.moveLeft(0)
p.drawPixmap(target, self.after_image, source)
p.end()
def set_current_width(self, val):
self._current_width = val
current_width = pyqtProperty('int',
fget=lambda self: self._current_width,
fset=set_current_width
)

View File

@ -5,6 +5,8 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import gc
## {{{ http://code.activestate.com/recipes/286222/ (r1)
import os
@ -52,4 +54,19 @@ def stacksize(since=0.0):
## end of http://code.activestate.com/recipes/286222/ }}}
def gc_histogram():
"""Returns per-class counts of existing objects."""
result = {}
for o in gc.get_objects():
t = type(o)
count = result.get(t, 0)
result[t] = count + 1
return result
def diff_hists(h1, h2):
"""Prints differences between two results of gc_histogram()."""
for k in h1:
if h1[k] != h2[k]:
print "%s: %d -> %d (%s%d)" % (
k, h1[k], h2[k], h2[k] > h1[k] and "+" or "", h2[k] - h1[k])