mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
c6fab3c849
23
resources/recipes/ajiajin.recipe
Normal file
23
resources/recipes/ajiajin.recipe
Normal file
@ -0,0 +1,23 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
||||
'''
|
||||
ajiajin.com/blog
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AjiajinBlog(BasicNewsRecipe):
|
||||
title = u'Ajiajin blog'
|
||||
__author__ = 'Hiroshi Miura'
|
||||
oldest_article = 5
|
||||
publication_type = 'blog'
|
||||
max_articles_per_feed = 100
|
||||
description = 'The next generation internet trends in Japan and Asia'
|
||||
publisher = ''
|
||||
category = 'internet, asia, japan'
|
||||
language = 'en'
|
||||
encoding = 'utf-8'
|
||||
|
||||
feeds = [(u'blog', u'http://feeds.feedburner.com/Asiajin')]
|
||||
|
||||
|
37
resources/recipes/chouchoublog.recipe
Normal file
37
resources/recipes/chouchoublog.recipe
Normal file
@ -0,0 +1,37 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
||||
'''
|
||||
http://ameblo.jp/
|
||||
'''
|
||||
|
||||
import re
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class SakuraBlog(BasicNewsRecipe):
|
||||
title = u'chou chou blog'
|
||||
__author__ = 'Hiroshi Miura'
|
||||
oldest_article = 4
|
||||
publication_type = 'blog'
|
||||
max_articles_per_feed = 20
|
||||
description = 'Japanese popular dog blog'
|
||||
publisher = ''
|
||||
category = 'dog, pet, japan'
|
||||
language = 'ja'
|
||||
encoding = 'utf-8'
|
||||
use_embedded_content = True
|
||||
|
||||
feeds = [(u'blog', u'http://feedblog.ameba.jp/rss/ameblo/chouchou1218/rss20.xml')]
|
||||
|
||||
def parse_feeds(self):
|
||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||
for curfeed in feeds:
|
||||
delList = []
|
||||
for a,curarticle in enumerate(curfeed.articles):
|
||||
if re.search(r'rssad.jp', curarticle.url):
|
||||
delList.append(curarticle)
|
||||
if len(delList)>0:
|
||||
for d in delList:
|
||||
index = curfeed.articles.index(d)
|
||||
curfeed.articles[index:index+1] = []
|
||||
return feeds
|
||||
|
@ -3,15 +3,16 @@ __copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
http://www.dilbert.com
|
||||
'''
|
||||
import re
|
||||
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
import re
|
||||
|
||||
class DosisDiarias(BasicNewsRecipe):
|
||||
class DilbertBig(BasicNewsRecipe):
|
||||
title = 'Dilbert'
|
||||
__author__ = 'Darko Miletic'
|
||||
__author__ = 'Darko Miletic and Starson17'
|
||||
description = 'Dilbert'
|
||||
oldest_article = 5
|
||||
reverse_article_order = True
|
||||
oldest_article = 15
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
use_embedded_content = True
|
||||
@ -29,20 +30,23 @@ class DosisDiarias(BasicNewsRecipe):
|
||||
|
||||
feeds = [(u'Dilbert', u'http://feeds.dilbert.com/DilbertDailyStrip' )]
|
||||
|
||||
preprocess_regexps = [
|
||||
(re.compile('strip\..*\.gif', re.DOTALL|re.IGNORECASE),
|
||||
lambda match: 'strip.zoom.gif')
|
||||
]
|
||||
|
||||
|
||||
def get_article_url(self, article):
|
||||
return article.get('feedburner_origlink', None)
|
||||
|
||||
preprocess_regexps = [
|
||||
(re.compile('strip\..*\.gif', re.DOTALL|re.IGNORECASE), lambda match: 'strip.zoom.gif')
|
||||
]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for tag in soup.findAll(name='a'):
|
||||
if tag['href'].find('http://feedads') >= 0:
|
||||
tag.extract()
|
||||
return soup
|
||||
|
||||
|
||||
|
||||
extra_css = '''
|
||||
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
|
||||
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
|
||||
img {max-width:100%; min-width:100%;}
|
||||
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
|
||||
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
|
||||
'''
|
||||
|
31
resources/recipes/kahokushinpo.recipe
Normal file
31
resources/recipes/kahokushinpo.recipe
Normal file
@ -0,0 +1,31 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
||||
'''
|
||||
www.kahoku.co.jp
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
|
||||
class KahokuShinpoNews(BasicNewsRecipe):
|
||||
title = u'\u6cb3\u5317\u65b0\u5831'
|
||||
__author__ = 'Hiroshi Miura'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 20
|
||||
description = 'Tohoku regional news paper in Japan'
|
||||
publisher = 'Kahoku Shinpo Sha'
|
||||
category = 'news, japan'
|
||||
language = 'ja'
|
||||
encoding = 'Shift_JIS'
|
||||
no_stylesheets = True
|
||||
|
||||
feeds = [(u'news', u'http://www.kahoku.co.jp/rss/index_thk.xml')]
|
||||
|
||||
keep_only_tags = [ dict(id="page_title"),
|
||||
dict(id="news_detail"),
|
||||
dict(id="bt_title"),
|
||||
{'class':"photoLeft"},
|
||||
dict(id="bt_body")
|
||||
]
|
||||
remove_tags = [ {'class':"button"}]
|
||||
|
38
resources/recipes/nationalgeographic.recipe
Normal file
38
resources/recipes/nationalgeographic.recipe
Normal file
@ -0,0 +1,38 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
||||
'''
|
||||
nationalgeographic.com
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import re
|
||||
|
||||
class NationalGeographicNews(BasicNewsRecipe):
|
||||
title = u'National Geographic News'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
remove_javascript = True
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
|
||||
feeds = [(u'news', u'http://feeds.nationalgeographic.com/ng/News/News_Main')]
|
||||
|
||||
remove_tags_before = dict(id='page_head')
|
||||
remove_tags_after = [dict(id='social_buttons'),{'class':'aside'}]
|
||||
remove_tags = [
|
||||
{'class':'hidden'}
|
||||
|
||||
]
|
||||
|
||||
def parse_feeds(self):
|
||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||
for curfeed in feeds:
|
||||
delList = []
|
||||
for a,curarticle in enumerate(curfeed.articles):
|
||||
if re.search(r'ads\.pheedo\.com', curarticle.url):
|
||||
delList.append(curarticle)
|
||||
if len(delList)>0:
|
||||
for d in delList:
|
||||
index = curfeed.articles.index(d)
|
||||
curfeed.articles[index:index+1] = []
|
||||
return feeds
|
20
resources/recipes/nationalgeographicjp.recipe
Normal file
20
resources/recipes/nationalgeographicjp.recipe
Normal file
@ -0,0 +1,20 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
||||
'''
|
||||
nationalgeographic.co.jp
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import re
|
||||
|
||||
class NationalGeoJp(BasicNewsRecipe):
|
||||
title = u'\u30ca\u30b7\u30e7\u30ca\u30eb\u30fb\u30b8\u30aa\u30b0\u30e9\u30d5\u30a3\u30c3\u30af\u30cb\u30e5\u30fc\u30b9'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
|
||||
feeds = [(u'news', u'http://www.nationalgeographic.co.jp/news/rss.php')]
|
||||
|
||||
def print_version(self, url):
|
||||
return re.sub(r'news_article.php','news_printer_friendly.php', url)
|
||||
|
@ -10,8 +10,8 @@ import mechanize
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
|
||||
|
||||
class NikkeiNet_sub_life(BasicNewsRecipe):
|
||||
title = u'\u65e5\u7d4c\u65b0\u805e\u96fb\u5b50\u7248(\u751f\u6d3b)'
|
||||
class NikkeiNet_sub_shakai(BasicNewsRecipe):
|
||||
title = u'\u65e5\u7d4c\u65b0\u805e\u96fb\u5b50\u7248(Social)'
|
||||
__author__ = 'Hiroshi Miura'
|
||||
description = 'News and current market affairs from Japan'
|
||||
cover_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
||||
|
58
resources/recipes/paperli_topic.recipe
Normal file
58
resources/recipes/paperli_topic.recipe
Normal file
@ -0,0 +1,58 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
||||
'''
|
||||
paperli
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre import strftime
|
||||
|
||||
class paperli_topics(BasicNewsRecipe):
|
||||
# Customize this recipe and change paperli_tag and title below to
|
||||
# download news on your favorite tag
|
||||
paperli_tag = 'climate'
|
||||
title = u'The #climate Daily - paperli'
|
||||
#-------------------------------------------------------------
|
||||
__author__ = 'Hiroshi Miura'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
description = 'paper.li page about '+ paperli_tag
|
||||
publisher = 'paper.li'
|
||||
category = 'paper.li'
|
||||
language = 'en'
|
||||
encoding = 'utf-8'
|
||||
remove_javascript = True
|
||||
masthead_title = u'The '+ paperli_tag +' Daily'
|
||||
timefmt = '[%y/%m/%d]'
|
||||
base_url = 'http://paper.li'
|
||||
index = base_url+'/tag/'+paperli_tag
|
||||
|
||||
|
||||
def parse_index(self):
|
||||
# get topics
|
||||
topics = []
|
||||
soup = self.index_to_soup(self.index)
|
||||
topics_lists = soup.find('div',attrs={'class':'paper-nav-bottom'})
|
||||
for item in topics_lists.findAll('li', attrs={'class':""}):
|
||||
itema = item.find('a',href=True)
|
||||
topics.append({'title': itema.string, 'url': itema['href']})
|
||||
|
||||
#get feeds
|
||||
feeds = []
|
||||
for topic in topics:
|
||||
newsarticles = []
|
||||
soup = self.index_to_soup(''.join([self.base_url, topic['url'] ]))
|
||||
topstories = soup.findAll('div',attrs={'class':'yui-u'})
|
||||
for itt in topstories:
|
||||
itema = itt.find('a',href=True,attrs={'class':'ts'})
|
||||
if itema is not None:
|
||||
itemd = itt.find('div',text=True, attrs={'class':'text'})
|
||||
newsarticles.append({
|
||||
'title' :itema.string
|
||||
,'date' :strftime(self.timefmt)
|
||||
,'url' :itema['href']
|
||||
,'description':itemd.string
|
||||
})
|
||||
feeds.append((topic['title'], newsarticles))
|
||||
return feeds
|
||||
|
36
resources/recipes/uninohimitu.recipe
Normal file
36
resources/recipes/uninohimitu.recipe
Normal file
@ -0,0 +1,36 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
||||
'''
|
||||
http://ameblo.jp/sauta19/
|
||||
'''
|
||||
|
||||
import re
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class UniNoHimituKichiBlog(BasicNewsRecipe):
|
||||
title = u'Uni secret base'
|
||||
__author__ = 'Hiroshi Miura'
|
||||
oldest_article = 2
|
||||
publication_type = 'blog'
|
||||
max_articles_per_feed = 20
|
||||
description = 'Japanese famous Cat blog'
|
||||
publisher = ''
|
||||
category = 'cat, pet, japan'
|
||||
language = 'ja'
|
||||
encoding = 'utf-8'
|
||||
|
||||
feeds = [(u'blog', u'http://feedblog.ameba.jp/rss/ameblo/sauta19/rss20.xml')]
|
||||
|
||||
def parse_feeds(self):
|
||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||
for curfeed in feeds:
|
||||
delList = []
|
||||
for a,curarticle in enumerate(curfeed.articles):
|
||||
if re.search(r'rssad.jp', curarticle.url):
|
||||
delList.append(curarticle)
|
||||
if len(delList)>0:
|
||||
for d in delList:
|
||||
index = curfeed.articles.index(d)
|
||||
curfeed.articles[index:index+1] = []
|
||||
return feeds
|
||||
|
@ -120,7 +120,7 @@ def add_pipeline_options(parser, plumber):
|
||||
[
|
||||
'base_font_size', 'disable_font_rescaling',
|
||||
'font_size_mapping',
|
||||
'line_height',
|
||||
'line_height', 'minimum_line_height',
|
||||
'linearize_tables',
|
||||
'extra_css', 'smarten_punctuation',
|
||||
'margin_top', 'margin_left', 'margin_right',
|
||||
|
@ -160,13 +160,30 @@ OptionRecommendation(name='disable_font_rescaling',
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='minimum_line_height',
|
||||
recommended_value=120.0, level=OptionRecommendation.LOW,
|
||||
help=_(
|
||||
'The minimum line height, as a percentage of the element\'s '
|
||||
'calculated font size. calibre will ensure that every element '
|
||||
'has a line height of at least this setting, irrespective of '
|
||||
'what the input document specifies. Set to zero to disable. '
|
||||
'Default is 120%. Use this setting in preference to '
|
||||
'the direct line height specification, unless you know what '
|
||||
'you are doing. For example, you can achieve "double spaced" '
|
||||
'text by setting this to 240.'
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
OptionRecommendation(name='line_height',
|
||||
recommended_value=0, level=OptionRecommendation.LOW,
|
||||
help=_('The line height in pts. Controls spacing between consecutive '
|
||||
'lines of text. By default no line height manipulation is '
|
||||
'performed.'
|
||||
)
|
||||
help=_(
|
||||
'The line height in pts. Controls spacing between consecutive '
|
||||
'lines of text. Only applies to elements that do not define '
|
||||
'their own line height. In most cases, the minimum line height '
|
||||
'option is more useful. '
|
||||
'By default no line height manipulation is performed.'
|
||||
)
|
||||
),
|
||||
|
||||
OptionRecommendation(name='linearize_tables',
|
||||
|
@ -314,6 +314,8 @@ class HTMLInput(InputFormatPlugin):
|
||||
rewrite_links, urlnormalize, urldefrag, BINARY_MIME, OEB_STYLES, \
|
||||
xpath
|
||||
from calibre import guess_type
|
||||
from calibre.ebooks.oeb.transforms.metadata import \
|
||||
meta_info_to_oeb_metadata
|
||||
import cssutils
|
||||
self.OEB_STYLES = OEB_STYLES
|
||||
oeb = create_oebbook(log, None, opts, self,
|
||||
@ -321,15 +323,7 @@ class HTMLInput(InputFormatPlugin):
|
||||
self.oeb = oeb
|
||||
|
||||
metadata = oeb.metadata
|
||||
if mi.title:
|
||||
metadata.add('title', mi.title)
|
||||
if mi.authors:
|
||||
for a in mi.authors:
|
||||
metadata.add('creator', a, attrib={'role':'aut'})
|
||||
if mi.publisher:
|
||||
metadata.add('publisher', mi.publisher)
|
||||
if mi.isbn:
|
||||
metadata.add('identifier', mi.isbn, attrib={'scheme':'ISBN'})
|
||||
meta_info_to_oeb_metadata(mi, metadata, log)
|
||||
if not metadata.language:
|
||||
oeb.logger.warn(u'Language not specified')
|
||||
metadata.add('language', get_lang().replace('_', '-'))
|
||||
|
@ -170,7 +170,27 @@ def get_metadata_(src, encoding=None):
|
||||
if match:
|
||||
series = match.group(1)
|
||||
if series:
|
||||
pat = re.compile(r'\[([.0-9]+)\]')
|
||||
match = pat.search(series)
|
||||
series_index = None
|
||||
if match is not None:
|
||||
try:
|
||||
series_index = float(match.group(1))
|
||||
except:
|
||||
pass
|
||||
series = series.replace(match.group(), '').strip()
|
||||
|
||||
mi.series = ent_pat.sub(entity_to_unicode, series)
|
||||
if series_index is None:
|
||||
pat = get_meta_regexp_("Seriesnumber")
|
||||
match = pat.search(src)
|
||||
if match:
|
||||
try:
|
||||
series_index = float(match.group(1))
|
||||
except:
|
||||
pass
|
||||
if series_index is not None:
|
||||
mi.series_index = series_index
|
||||
|
||||
# RATING
|
||||
rating = None
|
||||
|
@ -184,7 +184,7 @@ class MobiMLizer(object):
|
||||
para.attrib['value'] = str(istates[-2].list_num)
|
||||
elif tag in NESTABLE_TAGS and istate.rendered:
|
||||
para = wrapper = bstate.nested[-1]
|
||||
elif left > 0 and indent >= 0:
|
||||
elif not self.opts.mobi_ignore_margins and left > 0 and indent >= 0:
|
||||
ems = self.profile.mobi_ems_per_blockquote
|
||||
para = wrapper = etree.SubElement(parent, XHTML('blockquote'))
|
||||
para = wrapper
|
||||
|
@ -39,6 +39,12 @@ class MOBIOutput(OutputFormatPlugin):
|
||||
OptionRecommendation(name='personal_doc', recommended_value='[PDOC]',
|
||||
help=_('Tag marking book to be filed with Personal Docs')
|
||||
),
|
||||
OptionRecommendation(name='mobi_ignore_margins',
|
||||
recommended_value=False,
|
||||
help=_('Ignore margins in the input document. If False, then '
|
||||
'the MOBI output plugin will try to convert margins specified'
|
||||
' in the input document, otherwise it will ignore them.')
|
||||
),
|
||||
])
|
||||
|
||||
def check_for_periodical(self):
|
||||
|
@ -633,12 +633,12 @@ class Style(object):
|
||||
parent = self._getparent()
|
||||
if 'line-height' in self._style:
|
||||
lineh = self._style['line-height']
|
||||
if lineh == 'normal':
|
||||
lineh = '1.2'
|
||||
try:
|
||||
float(lineh)
|
||||
result = float(lineh) * self.fontSize
|
||||
except ValueError:
|
||||
result = self._unit_convert(lineh, base=self.fontSize)
|
||||
else:
|
||||
result = float(lineh) * self.fontSize
|
||||
elif parent is not None:
|
||||
# TODO: proper inheritance
|
||||
result = parent.lineHeight
|
||||
|
@ -245,6 +245,8 @@ class CSSFlattener(object):
|
||||
del node.attrib['bgcolor']
|
||||
if cssdict.get('font-weight', '').lower() == 'medium':
|
||||
cssdict['font-weight'] = 'normal' # ADE chokes on font-weight medium
|
||||
|
||||
fsize = font_size
|
||||
if not self.context.disable_font_rescaling:
|
||||
_sbase = self.sbase if self.sbase is not None else \
|
||||
self.context.source.fbase
|
||||
@ -258,6 +260,14 @@ class CSSFlattener(object):
|
||||
fsize = self.fmap[font_size]
|
||||
cssdict['font-size'] = "%0.5fem" % (fsize / psize)
|
||||
psize = fsize
|
||||
|
||||
try:
|
||||
minlh = self.context.minimum_line_height / 100.
|
||||
if style['line-height'] < minlh * fsize:
|
||||
cssdict['line-height'] = str(minlh)
|
||||
except:
|
||||
self.oeb.logger.exception('Failed to set minimum line-height')
|
||||
|
||||
if cssdict:
|
||||
if self.lineh and self.fbase and tag != 'body':
|
||||
self.clean_edges(cssdict, style, psize)
|
||||
@ -290,6 +300,7 @@ class CSSFlattener(object):
|
||||
lineh = self.lineh / psize
|
||||
cssdict['line-height'] = "%0.5fem" % lineh
|
||||
|
||||
|
||||
if (self.context.remove_paragraph_spacing or
|
||||
self.context.insert_blank_line) and tag in ('p', 'div'):
|
||||
if item_id != 'calibre_jacket' or self.context.output_profile.name == 'Kindle':
|
||||
|
@ -77,10 +77,14 @@ class TXTInput(InputFormatPlugin):
|
||||
base = os.getcwdu()
|
||||
if hasattr(stream, 'name'):
|
||||
base = os.path.dirname(stream.name)
|
||||
htmlfile = open(os.path.join(base, 'temp_calibre_txt_input_to_html.html'),
|
||||
'wb')
|
||||
htmlfile.write(html.encode('utf-8'))
|
||||
htmlfile.close()
|
||||
fname = os.path.join(base, 'index.html')
|
||||
c = 0
|
||||
while os.path.exists(fname):
|
||||
c += 1
|
||||
fname = 'index%d.html'%c
|
||||
htmlfile = open(fname, 'wb')
|
||||
with htmlfile:
|
||||
htmlfile.write(html.encode('utf-8'))
|
||||
cwd = os.getcwdu()
|
||||
odi = options.debug_pipeline
|
||||
options.debug_pipeline = None
|
||||
|
@ -10,7 +10,7 @@ import textwrap
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QWidget, QSpinBox, QDoubleSpinBox, QLineEdit, QTextEdit, \
|
||||
QCheckBox, QComboBox, Qt, QIcon, pyqtSignal
|
||||
QCheckBox, QComboBox, Qt, QIcon, pyqtSignal, QLabel
|
||||
|
||||
from calibre.customize.conversion import OptionRecommendation
|
||||
from calibre.ebooks.conversion.config import load_defaults, \
|
||||
@ -81,6 +81,21 @@ class Widget(QWidget):
|
||||
self.apply_recommendations(defaults)
|
||||
self.setup_help(get_help)
|
||||
|
||||
def process_child(child):
|
||||
for g in child.children():
|
||||
if isinstance(g, QLabel):
|
||||
buddy = g.buddy()
|
||||
if buddy is not None and hasattr(buddy, '_help'):
|
||||
g._help = buddy._help
|
||||
htext = unicode(buddy.toolTip()).strip()
|
||||
g.setToolTip(htext)
|
||||
g.setWhatsThis(htext)
|
||||
g.__class__.enterEvent = lambda obj, event: self.set_help(getattr(obj, '_help', obj.toolTip()))
|
||||
else:
|
||||
process_child(g)
|
||||
process_child(self)
|
||||
|
||||
|
||||
def restore_defaults(self, get_option):
|
||||
defaults = GuiRecommendations()
|
||||
defaults.merge_recommendations(get_option, OptionRecommendation.LOW,
|
||||
|
@ -21,7 +21,7 @@ class LookAndFeelWidget(Widget, Ui_Form):
|
||||
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||
Widget.__init__(self, parent,
|
||||
['change_justification', 'extra_css', 'base_font_size',
|
||||
'font_size_mapping', 'line_height',
|
||||
'font_size_mapping', 'line_height', 'minimum_line_height',
|
||||
'linearize_tables', 'smarten_punctuation',
|
||||
'disable_font_rescaling', 'insert_blank_line',
|
||||
'remove_paragraph_spacing', 'remove_paragraph_spacing_indent_size','input_encoding',
|
||||
|
@ -97,7 +97,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Line &height:</string>
|
||||
@ -107,7 +107,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QDoubleSpinBox" name="opt_line_height">
|
||||
<property name="suffix">
|
||||
<string> pt</string>
|
||||
@ -117,7 +117,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Input character &encoding:</string>
|
||||
@ -127,17 +127,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="3">
|
||||
<item row="5" column="1" colspan="3">
|
||||
<widget class="QLineEdit" name="opt_input_encoding"/>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="opt_remove_paragraph_spacing">
|
||||
<property name="text">
|
||||
<string>Remove &spacing between paragraphs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2" colspan="2">
|
||||
<item row="6" column="2" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
@ -164,21 +164,21 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Text justification:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QCheckBox" name="opt_linearize_tables">
|
||||
<property name="text">
|
||||
<string>&Linearize tables</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="4">
|
||||
<item row="11" column="0" colspan="4">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Extra &CSS</string>
|
||||
@ -190,37 +190,60 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2" colspan="2">
|
||||
<item row="7" column="2" colspan="2">
|
||||
<widget class="QComboBox" name="opt_change_justification"/>
|
||||
</item>
|
||||
<item row="7" column="1" colspan="3">
|
||||
<item row="8" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="opt_asciiize">
|
||||
<property name="text">
|
||||
<string>&Transliterate unicode characters to ASCII</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="opt_insert_blank_line">
|
||||
<property name="text">
|
||||
<string>Insert &blank line</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1" colspan="2">
|
||||
<item row="9" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="opt_keep_ligatures">
|
||||
<property name="text">
|
||||
<string>Keep &ligatures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QCheckBox" name="opt_smarten_punctuation">
|
||||
<property name="text">
|
||||
<string>Smarten &punctuation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Minimum &line height:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_minimum_line_height</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QDoubleSpinBox" name="opt_minimum_line_height">
|
||||
<property name="suffix">
|
||||
<string> %</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>900.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
|
@ -25,6 +25,7 @@ class PluginWidget(Widget, Ui_Form):
|
||||
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||
Widget.__init__(self, parent,
|
||||
['prefer_author_sort', 'rescale_images', 'toc_title',
|
||||
'mobi_ignore_margins',
|
||||
'dont_compress', 'no_inline_toc', 'masthead_font','personal_doc']
|
||||
)
|
||||
self.db, self.book_id = db, book_id
|
||||
|
@ -55,7 +55,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Kindle options</string>
|
||||
@ -101,7 +101,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@ -114,6 +114,13 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="opt_mobi_ignore_margins">
|
||||
<property name="text">
|
||||
<string>Ignore &margins</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
@ -240,37 +240,39 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.cover_fetcher = CoverFetcher(None, None, isbn,
|
||||
self.timeout, title, author)
|
||||
self.cover_fetcher.start()
|
||||
self._hangcheck = QTimer(self)
|
||||
self._hangcheck.timeout.connect(self.hangcheck,
|
||||
type=Qt.QueuedConnection)
|
||||
self.cf_start_time = time.time()
|
||||
self.pi.start(_('Downloading cover...'))
|
||||
self._hangcheck.start(100)
|
||||
QTimer.singleShot(100, self.hangcheck)
|
||||
|
||||
def hangcheck(self):
|
||||
if self.cover_fetcher.is_alive() and \
|
||||
time.time()-self.cf_start_time < self.COVER_FETCH_TIMEOUT:
|
||||
cf = self.cover_fetcher
|
||||
if cf is None:
|
||||
# Called after dialog closed
|
||||
return
|
||||
|
||||
if cf.is_alive() and \
|
||||
time.time()-self.cf_start_time < self.COVER_FETCH_TIMEOUT:
|
||||
QTimer.singleShot(100, self.hangcheck)
|
||||
return
|
||||
|
||||
self._hangcheck.stop()
|
||||
try:
|
||||
if self.cover_fetcher.is_alive():
|
||||
if cf.is_alive():
|
||||
error_dialog(self, _('Cannot fetch cover'),
|
||||
_('<b>Could not fetch cover.</b><br/>')+
|
||||
_('The download timed out.')).exec_()
|
||||
return
|
||||
if self.cover_fetcher.needs_isbn:
|
||||
if cf.needs_isbn:
|
||||
error_dialog(self, _('Cannot fetch cover'),
|
||||
_('Could not find cover for this book. Try '
|
||||
'specifying the ISBN first.')).exec_()
|
||||
return
|
||||
if self.cover_fetcher.exception is not None:
|
||||
err = self.cover_fetcher.exception
|
||||
if cf.exception is not None:
|
||||
err = cf.exception
|
||||
error_dialog(self, _('Cannot fetch cover'),
|
||||
_('<b>Could not fetch cover.</b><br/>')+unicode(err)).exec_()
|
||||
return
|
||||
if self.cover_fetcher.errors and self.cover_fetcher.cover_data is None:
|
||||
details = u'\n\n'.join([e[-1] + ': ' + e[1] for e in self.cover_fetcher.errors])
|
||||
if cf.errors and cf.cover_data is None:
|
||||
details = u'\n\n'.join([e[-1] + ': ' + e[1] for e in cf.errors])
|
||||
error_dialog(self, _('Cannot fetch cover'),
|
||||
_('<b>Could not fetch cover.</b><br/>') +
|
||||
_('For the error message from each cover source, '
|
||||
@ -278,7 +280,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
return
|
||||
|
||||
pix = QPixmap()
|
||||
pix.loadFromData(self.cover_fetcher.cover_data)
|
||||
pix.loadFromData(cf.cover_data)
|
||||
if pix.isNull():
|
||||
error_dialog(self, _('Bad cover'),
|
||||
_('The cover is not a valid picture')).exec_()
|
||||
@ -287,7 +289,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.update_cover_tooltip()
|
||||
self.cover_changed = True
|
||||
self.cpixmap = pix
|
||||
self.cover_data = self.cover_fetcher.cover_data
|
||||
self.cover_data = cf.cover_data
|
||||
finally:
|
||||
self.fetch_cover_button.setEnabled(True)
|
||||
self.unsetCursor()
|
||||
@ -438,6 +440,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
def __init__(self, window, row, db, prev=None,
|
||||
next_=None):
|
||||
ResizableDialog.__init__(self, window)
|
||||
self.cover_fetcher = None
|
||||
self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter)
|
||||
self.cancel_all = False
|
||||
base = unicode(self.author_sort.toolTip())
|
||||
@ -828,10 +831,6 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.accept()
|
||||
|
||||
def accept(self):
|
||||
cf = getattr(self, 'cover_fetcher', None)
|
||||
if cf is not None and hasattr(cf, 'terminate'):
|
||||
cf.terminate()
|
||||
cf.wait()
|
||||
try:
|
||||
if self.formats_changed:
|
||||
self.sync_formats()
|
||||
@ -888,14 +887,12 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
show=True)
|
||||
raise
|
||||
self.save_state()
|
||||
self.cover_fetcher = None
|
||||
QDialog.accept(self)
|
||||
|
||||
def reject(self, *args):
|
||||
cf = getattr(self, 'cover_fetcher', None)
|
||||
if cf is not None and hasattr(cf, 'terminate'):
|
||||
cf.terminate()
|
||||
cf.wait()
|
||||
self.save_state()
|
||||
self.cover_fetcher = None
|
||||
QDialog.reject(self, *args)
|
||||
|
||||
def read_state(self):
|
||||
|
@ -251,10 +251,28 @@ class Preferences(QMainWindow):
|
||||
self.close()
|
||||
self.run_wizard_requested.emit()
|
||||
|
||||
def set_tooltips_for_labels(self):
|
||||
|
||||
def process_child(child):
|
||||
for g in child.children():
|
||||
if isinstance(g, QLabel):
|
||||
buddy = g.buddy()
|
||||
if buddy is not None and hasattr(buddy, 'toolTip'):
|
||||
htext = unicode(buddy.toolTip()).strip()
|
||||
etext = unicode(g.toolTip()).strip()
|
||||
if htext and not etext:
|
||||
g.setToolTip(htext)
|
||||
g.setWhatsThis(htext)
|
||||
else:
|
||||
process_child(g)
|
||||
|
||||
process_child(self.showing_widget)
|
||||
|
||||
def show_plugin(self, plugin):
|
||||
self.showing_widget = plugin.create_widget(self.scroll_area)
|
||||
self.showing_widget.genesis(self.gui)
|
||||
self.showing_widget.initialize()
|
||||
self.set_tooltips_for_labels()
|
||||
self.scroll_area.setWidget(self.showing_widget)
|
||||
self.stack.setCurrentIndex(1)
|
||||
self.showing_widget.show()
|
||||
|
Loading…
x
Reference in New Issue
Block a user