mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
GwR patches for 'change_justification'
This commit is contained in:
commit
a8db54b6fa
BIN
resources/images/news/kurier.png
Normal file
BIN
resources/images/news/kurier.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 658 B |
BIN
resources/images/news/virtualshackles.png
Normal file
BIN
resources/images/news/virtualshackles.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
@ -119,5 +119,7 @@ class Guardian(BasicNewsRecipe):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
def postprocess_html(self,soup,first):
|
||||||
|
return soup.findAll('html')[0]
|
||||||
|
|
||||||
|
|
||||||
|
50
resources/recipes/kurier.recipe
Normal file
50
resources/recipes/kurier.recipe
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
kurier.at
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class Kurier(BasicNewsRecipe):
|
||||||
|
title = 'Kurier'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'News from Austria'
|
||||||
|
publisher = 'KURIER'
|
||||||
|
category = 'news, politics, Austria'
|
||||||
|
oldest_article = 2
|
||||||
|
max_articles_per_feed = 200
|
||||||
|
no_stylesheets = True
|
||||||
|
encoding = 'cp1252'
|
||||||
|
use_embedded_content = False
|
||||||
|
language = 'de_AT'
|
||||||
|
remove_empty_feeds = True
|
||||||
|
publication_type = 'newspaper'
|
||||||
|
extra_css = ' body{font-family: Verdana,Helvetica,sans-serif } img{margin-bottom: 0.4em} .bild_us{font-size: x-small} '
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comment' : description
|
||||||
|
, 'tags' : category
|
||||||
|
, 'publisher' : publisher
|
||||||
|
, 'language' : language
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_tags = [dict(attrs={'class':['contenttabs','drucken','versenden','leserbrief','kommentieren','addthis_button']})]
|
||||||
|
keep_only_tags = [dict(attrs={'id':'content'})]
|
||||||
|
remove_tags_after = dict(attrs={'id':'author'})
|
||||||
|
remove_attributes = ['width','height']
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Nachrichten', u'http://kurier.at/rss/nachrichten_nachrichten_rss.xml' )
|
||||||
|
,(u'Techno' , u'http://kurier.at/rss/techno_techno_rss.xml' )
|
||||||
|
,(u'Wirtschaft' , u'http://kurier.at/rss/wirtschaft_wirtschaft_rss.xml' )
|
||||||
|
,(u'Kultur' , u'http://kurier.at/rss/kultur_kultur_rss.xml' )
|
||||||
|
,(u'Freizeit' , u'http://kurier.at/rss/freizeit_freizeit_rss.xml' )
|
||||||
|
,(u'Wetter' , u'http://kurier.at/rss/oewetter_rss.xml' )
|
||||||
|
,(u'Verkehr' , u'http://kurier.at/rss/verkehr_rss.xml' )
|
||||||
|
]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
for item in soup.findAll(style=True):
|
||||||
|
del item['style']
|
||||||
|
return self.adeify_images(soup)
|
@ -22,21 +22,36 @@ class LaRepublica(BasicNewsRecipe):
|
|||||||
language = 'it'
|
language = 'it'
|
||||||
timefmt = '[%a, %d %b, %Y]'
|
timefmt = '[%a, %d %b, %Y]'
|
||||||
|
|
||||||
oldest_article = 1
|
oldest_article = 5
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
recursion = 10
|
recursion = 10
|
||||||
|
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
|
def get_article_url(self, article):
|
||||||
|
link = article.get('id', article.get('guid', None))
|
||||||
|
if link is None:
|
||||||
|
return article
|
||||||
|
return link
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'class':'articolo'}),
|
||||||
|
dict(name='div', attrs={'class':'body-text'}),
|
||||||
|
dict(name='div', attrs={'class':'page-content'}),
|
||||||
|
dict(name='div', attrs={'id':'contA'})
|
||||||
|
]
|
||||||
|
|
||||||
keep_only_tags = [dict(name='div', attrs={'class':'articolo'})]
|
|
||||||
|
|
||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(name=['object','link']),
|
dict(name=['object','link']),
|
||||||
dict(name='span',attrs={'class':'linkindice'}),
|
dict(name='span',attrs={'class':'linkindice'}),
|
||||||
dict(name='div',attrs={'class':'bottom-mobile'}),
|
dict(name='div', attrs={'class':'bottom-mobile'}),
|
||||||
dict(name='div',attrs={'id':['rssdiv','blocco']})
|
dict(name='div', attrs={'id':['rssdiv','blocco']}),
|
||||||
|
dict(name='div', attrs={'class':'utility'}),
|
||||||
|
dict(name='div', attrs={'class':'generalbox'})
|
||||||
]
|
]
|
||||||
|
remove_tags_after = [
|
||||||
|
dict(name='div',attrs={'id':'ugc_linkUpload'})
|
||||||
|
]
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
(u'Repubblica Rilievo', u'http://www.repubblica.it/rss/homepage/rss2.0.xml'),
|
(u'Repubblica Rilievo', u'http://www.repubblica.it/rss/homepage/rss2.0.xml'),
|
||||||
@ -48,8 +63,12 @@ class LaRepublica(BasicNewsRecipe):
|
|||||||
(u'Repubblica Tecnologia', u'http://www.repubblica.it/rss/tecnologia/rss2.0.xml'),
|
(u'Repubblica Tecnologia', u'http://www.repubblica.it/rss/tecnologia/rss2.0.xml'),
|
||||||
(u'Repubblica Scuola e Universita', u'http://www.repubblica.it/rss/scuola_e_universita/rss2.0.xml'),
|
(u'Repubblica Scuola e Universita', u'http://www.repubblica.it/rss/scuola_e_universita/rss2.0.xml'),
|
||||||
(u'Repubblica Ambiente', u'http://www.repubblica.it/rss/ambiente/rss2.0.xml'),
|
(u'Repubblica Ambiente', u'http://www.repubblica.it/rss/ambiente/rss2.0.xml'),
|
||||||
(u'Repubblica Cultura', u'http://www.repubblica.it/rss/spettacoli_e_cultura/rss2.0.xml'),
|
(u'Repubblica Cultura', u'http://www.repubblica.it/rss/spettacoli_e_cultura/rss2.0.xml'),
|
||||||
(u'Repubblica Persone', u'http://www.repubblica.it/rss/persone/rss2.0.xml'),
|
(u'Repubblica Persone', u'http://www.repubblica.it/rss/persone/rss2.0.xml'),
|
||||||
(u'Repubblica Sport', u'http://www.repubblica.it/rss/sport/rss2.0.xml'),
|
(u'Repubblica Sport', u'http://www.repubblica.it/rss/sport/rss2.0.xml'),
|
||||||
(u'Repubblica Calcio', u'http://www.repubblica.it/rss/sport/calcio/rss2.0.xml')
|
(u'Repubblica Calcio', u'http://www.repubblica.it/rss/sport/calcio/rss2.0.xml'),
|
||||||
]
|
(u'Repubblica Motori', u'http://www.repubblica.it/rss/motori/rss2.0.xml'),
|
||||||
|
(u'Repubblica Roma', u'http://roma.repubblica.it/rss/rss2.0.xml'),
|
||||||
|
(u'Repubblica Torino', u'http://torino.repubblica.it/rss/rss2.0.xml')
|
||||||
|
]
|
||||||
|
|
||||||
|
18
resources/recipes/npr_music_blogs.recipe
Normal file
18
resources/recipes/npr_music_blogs.recipe
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class nprmusic(BasicNewsRecipe):
|
||||||
|
title = 'NPR Music Blogs'
|
||||||
|
__author__ = 'cix3'
|
||||||
|
timefmt = ' [%b %d, %Y]'
|
||||||
|
language = 'en'
|
||||||
|
|
||||||
|
oldest_article = 30
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
|
||||||
|
remove_tags = [dict(name='div', attrs={'id':['logo', 'comments', 'related_objects', 'inset module', 'footer', 'strip_control', 'header', 'navigation']}), dict(name='hr'), dict(name='img')]
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
('A Blog Supreme', 'http://www.npr.org/blogs/ablogsupreme/index.xml'),
|
||||||
|
('All Songs Considered', 'http://www.npr.org/blogs/allsongs/index.xml'),
|
||||||
|
('Monitor Mix', 'http://www.npr.org/blogs/monitormix/index.xml')]
|
@ -377,8 +377,9 @@ class USAToday(BasicNewsRecipe):
|
|||||||
if byline:
|
if byline:
|
||||||
byline['class'] = 'byline'
|
byline['class'] = 'byline'
|
||||||
# Replace comma with middot
|
# Replace comma with middot
|
||||||
byline.contents[0].replaceWith(re.sub(","," ·", byline.renderContents()))
|
byline.contents[0].replaceWith(re.sub(u",", u" ·",
|
||||||
return byline.renderContents()
|
byline.renderContents(encoding=None)))
|
||||||
|
return byline.renderContents(encoding=None)
|
||||||
else :
|
else :
|
||||||
paras = soup.findAll(text=True)
|
paras = soup.findAll(text=True)
|
||||||
for para in paras:
|
for para in paras:
|
||||||
|
33
resources/recipes/virtualshackles.recipe
Normal file
33
resources/recipes/virtualshackles.recipe
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
www.virtualshackles.com
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||||
|
|
||||||
|
class Virtualshackles(BasicNewsRecipe):
|
||||||
|
title = 'Virtual Shackles'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = "The adventures of Orion and Jack, making games they'd never play for people they don't like."
|
||||||
|
category = 'virtual shackles, virtualshackles, games, webcomic, comic, video game, orion, jack'
|
||||||
|
oldest_article = 10
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = True
|
||||||
|
encoding = 'cp1252'
|
||||||
|
publisher = 'Virtual Shackles'
|
||||||
|
language = 'en'
|
||||||
|
publication_type = 'comic'
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comments' : description
|
||||||
|
,'tags' : category
|
||||||
|
,'language' : language
|
||||||
|
,'publisher' : publisher
|
||||||
|
}
|
||||||
|
|
||||||
|
feeds = [(u'Virtual Shackles', u'http://feeds2.feedburner.com/virtualshackles' )]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
return self.adeify_images(soup)
|
@ -399,38 +399,49 @@ def my_unichr(num):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return u'?'
|
return u'?'
|
||||||
|
|
||||||
def entity_to_unicode(match, exceptions=[], encoding='cp1252'):
|
def entity_to_unicode(match, exceptions=[], encoding='cp1252',
|
||||||
|
result_exceptions={}):
|
||||||
'''
|
'''
|
||||||
@param match: A match object such that '&'+match.group(1)';' is the entity.
|
:param match: A match object such that '&'+match.group(1)';' is the entity.
|
||||||
@param exceptions: A list of entities to not convert (Each entry is the name of the entity, for e.g. 'apos' or '#1234'
|
|
||||||
@param encoding: The encoding to use to decode numeric entities between 128 and 256.
|
:param exceptions: A list of entities to not convert (Each entry is the name of the entity, for e.g. 'apos' or '#1234'
|
||||||
|
|
||||||
|
:param encoding: The encoding to use to decode numeric entities between 128 and 256.
|
||||||
If None, the Unicode UCS encoding is used. A common encoding is cp1252.
|
If None, the Unicode UCS encoding is used. A common encoding is cp1252.
|
||||||
|
|
||||||
|
:param result_exceptions: A mapping of characters to entities. If the result
|
||||||
|
is in result_exceptions, result_exception[result] is returned instead.
|
||||||
|
Convenient way to specify exception for things like < or > that can be
|
||||||
|
specified by various actual entities.
|
||||||
'''
|
'''
|
||||||
|
def check(ch):
|
||||||
|
return result_exceptions.get(ch, ch)
|
||||||
|
|
||||||
ent = match.group(1)
|
ent = match.group(1)
|
||||||
if ent in exceptions:
|
if ent in exceptions:
|
||||||
return '&'+ent+';'
|
return '&'+ent+';'
|
||||||
if ent == 'apos':
|
if ent == 'apos':
|
||||||
return "'"
|
return check("'")
|
||||||
if ent == 'hellips':
|
if ent == 'hellips':
|
||||||
ent = 'hellip'
|
ent = 'hellip'
|
||||||
if ent.startswith(u'#x'):
|
if ent.lower().startswith(u'#x'):
|
||||||
num = int(ent[2:], 16)
|
num = int(ent[2:], 16)
|
||||||
if encoding is None or num > 255:
|
if encoding is None or num > 255:
|
||||||
return my_unichr(num)
|
return check(my_unichr(num))
|
||||||
return chr(num).decode(encoding)
|
return check(chr(num).decode(encoding))
|
||||||
if ent.startswith(u'#'):
|
if ent.startswith(u'#'):
|
||||||
try:
|
try:
|
||||||
num = int(ent[1:])
|
num = int(ent[1:])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return '&'+ent+';'
|
return '&'+ent+';'
|
||||||
if encoding is None or num > 255:
|
if encoding is None or num > 255:
|
||||||
return my_unichr(num)
|
return check(my_unichr(num))
|
||||||
try:
|
try:
|
||||||
return chr(num).decode(encoding)
|
return check(chr(num).decode(encoding))
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
return my_unichr(num)
|
return check(my_unichr(num))
|
||||||
try:
|
try:
|
||||||
return my_unichr(name2codepoint[ent])
|
return check(my_unichr(name2codepoint[ent]))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return '&'+ent+';'
|
return '&'+ent+';'
|
||||||
|
|
||||||
|
@ -444,7 +444,7 @@ from calibre.devices.eslick.driver import ESLICK
|
|||||||
from calibre.devices.nuut2.driver import NUUT2
|
from calibre.devices.nuut2.driver import NUUT2
|
||||||
from calibre.devices.iriver.driver import IRIVER_STORY
|
from calibre.devices.iriver.driver import IRIVER_STORY
|
||||||
from calibre.devices.binatone.driver import README
|
from calibre.devices.binatone.driver import README
|
||||||
from calibre.devices.hanvon.driver import N516, EB511
|
from calibre.devices.hanvon.driver import N516, EB511, ALEX
|
||||||
from calibre.devices.edge.driver import EDGE
|
from calibre.devices.edge.driver import EDGE
|
||||||
from calibre.devices.teclast.driver import TECLAST_K3
|
from calibre.devices.teclast.driver import TECLAST_K3
|
||||||
from calibre.devices.sne.driver import SNE
|
from calibre.devices.sne.driver import SNE
|
||||||
@ -526,7 +526,8 @@ plugins += [
|
|||||||
ELONEX,
|
ELONEX,
|
||||||
TECLAST_K3,
|
TECLAST_K3,
|
||||||
EDGE,
|
EDGE,
|
||||||
SNE
|
SNE,
|
||||||
|
ALEX
|
||||||
]
|
]
|
||||||
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
||||||
x.__name__.endswith('MetadataReader')]
|
x.__name__.endswith('MetadataReader')]
|
||||||
|
@ -34,6 +34,22 @@ class N516(USBMS):
|
|||||||
EBOOK_DIR_MAIN = 'e_book'
|
EBOOK_DIR_MAIN = 'e_book'
|
||||||
SUPPORTS_SUB_DIRS = True
|
SUPPORTS_SUB_DIRS = True
|
||||||
|
|
||||||
|
class ALEX(N516):
|
||||||
|
|
||||||
|
name = 'Alex driver'
|
||||||
|
gui_name = 'SpringDesign Alex'
|
||||||
|
description = _('Communicate with the SpringDesign Alex eBook reader.')
|
||||||
|
author = 'Kovid Goyal'
|
||||||
|
|
||||||
|
FORMATS = ['epub', 'pdf']
|
||||||
|
VENDOR_NAME = 'ALEX'
|
||||||
|
WINDOWS_MAIN_MEM = 'READER'
|
||||||
|
|
||||||
|
MAIN_MEMORY_VOLUME_LABEL = 'Alex Internal Memory'
|
||||||
|
|
||||||
|
EBOOK_DIR_MAIN = 'eBooks'
|
||||||
|
SUPPORTS_SUB_DIRS = True
|
||||||
|
|
||||||
class EB511(USBMS):
|
class EB511(USBMS):
|
||||||
name = 'Elonex EB 511 driver'
|
name = 'Elonex EB 511 driver'
|
||||||
gui_name = 'EB 511'
|
gui_name = 'EB 511'
|
||||||
|
@ -322,7 +322,7 @@ class ComicInput(InputFormatPlugin):
|
|||||||
('margin_bottom', 0, OptionRecommendation.HIGH),
|
('margin_bottom', 0, OptionRecommendation.HIGH),
|
||||||
('insert_blank_line', False, OptionRecommendation.HIGH),
|
('insert_blank_line', False, OptionRecommendation.HIGH),
|
||||||
('remove_paragraph_spacing', False, OptionRecommendation.HIGH),
|
('remove_paragraph_spacing', False, OptionRecommendation.HIGH),
|
||||||
('dont_justify', True, OptionRecommendation.HIGH),
|
('change_justification', 'left', OptionRecommendation.HIGH),
|
||||||
('dont_split_on_pagebreaks', True, OptionRecommendation.HIGH),
|
('dont_split_on_pagebreaks', True, OptionRecommendation.HIGH),
|
||||||
('chapter', None, OptionRecommendation.HIGH),
|
('chapter', None, OptionRecommendation.HIGH),
|
||||||
('page_breaks_brefore', None, OptionRecommendation.HIGH),
|
('page_breaks_brefore', None, OptionRecommendation.HIGH),
|
||||||
|
@ -124,7 +124,7 @@ def add_pipeline_options(parser, plumber):
|
|||||||
'linearize_tables',
|
'linearize_tables',
|
||||||
'extra_css',
|
'extra_css',
|
||||||
'margin_top', 'margin_left', 'margin_right',
|
'margin_top', 'margin_left', 'margin_right',
|
||||||
'margin_bottom', 'dont_justify',
|
'margin_bottom', 'change_justification',
|
||||||
'insert_blank_line', 'remove_paragraph_spacing','remove_paragraph_spacing_indent_size',
|
'insert_blank_line', 'remove_paragraph_spacing','remove_paragraph_spacing_indent_size',
|
||||||
'asciiize', 'remove_header', 'header_regex',
|
'asciiize', 'remove_header', 'header_regex',
|
||||||
'remove_footer', 'footer_regex',
|
'remove_footer', 'footer_regex',
|
||||||
|
@ -299,12 +299,13 @@ OptionRecommendation(name='margin_right',
|
|||||||
help=_('Set the right margin in pts. Default is %default. '
|
help=_('Set the right margin in pts. Default is %default. '
|
||||||
'Note: 72 pts equals 1 inch')),
|
'Note: 72 pts equals 1 inch')),
|
||||||
|
|
||||||
OptionRecommendation(name='dont_justify',
|
OptionRecommendation(name='change_justification',
|
||||||
recommended_value=False, level=OptionRecommendation.LOW,
|
recommended_value='original', level=OptionRecommendation.LOW,
|
||||||
help=_('Do not force text to be justified in output. Whether text '
|
choices=['left','justify','original'],
|
||||||
'is actually displayed justified or not depends on whether '
|
help=_('Specify optional justification override. A value of '
|
||||||
'the ebook format and reading device support justification.')
|
'"left" or "justify" overrides default justification.'
|
||||||
),
|
'A value of '
|
||||||
|
'"original" uses existing alignment.')),
|
||||||
|
|
||||||
OptionRecommendation(name='remove_paragraph_spacing',
|
OptionRecommendation(name='remove_paragraph_spacing',
|
||||||
recommended_value=False, level=OptionRecommendation.LOW,
|
recommended_value=False, level=OptionRecommendation.LOW,
|
||||||
|
@ -130,7 +130,7 @@ class LRFOutput(OutputFormatPlugin):
|
|||||||
])
|
])
|
||||||
|
|
||||||
recommendations = set([
|
recommendations = set([
|
||||||
('dont_justify', True, OptionRecommendation.HIGH),
|
('change_justification', 'original', OptionRecommendation.HIGH),
|
||||||
])
|
])
|
||||||
|
|
||||||
def convert_images(self, pages, opts, wide):
|
def convert_images(self, pages, opts, wide):
|
||||||
|
@ -303,7 +303,12 @@ class MobiReader(object):
|
|||||||
for pat in ENCODING_PATS:
|
for pat in ENCODING_PATS:
|
||||||
self.processed_html = pat.sub('', self.processed_html)
|
self.processed_html = pat.sub('', self.processed_html)
|
||||||
e2u = functools.partial(entity_to_unicode,
|
e2u = functools.partial(entity_to_unicode,
|
||||||
exceptions=['lt', 'gt', 'amp', 'apos', 'quot', '#60', '#62'])
|
result_exceptions={
|
||||||
|
'<' : u'<',
|
||||||
|
'>' : u'>',
|
||||||
|
'&' : u'&',
|
||||||
|
'"' : u'"',
|
||||||
|
"'" : u'''})
|
||||||
self.processed_html = re.sub(r'&(\S+?);', e2u,
|
self.processed_html = re.sub(r'&(\S+?);', e2u,
|
||||||
self.processed_html)
|
self.processed_html)
|
||||||
self.extract_images(processed_records, output_dir)
|
self.extract_images(processed_records, output_dir)
|
||||||
@ -619,6 +624,7 @@ class MobiReader(object):
|
|||||||
opf.cover = None
|
opf.cover = None
|
||||||
|
|
||||||
cover = opf.cover
|
cover = opf.cover
|
||||||
|
cover_copied = None
|
||||||
if cover is not None:
|
if cover is not None:
|
||||||
cover = cover.replace('/', os.sep)
|
cover = cover.replace('/', os.sep)
|
||||||
if os.path.exists(cover):
|
if os.path.exists(cover):
|
||||||
@ -626,13 +632,19 @@ class MobiReader(object):
|
|||||||
if os.path.exists(ncover):
|
if os.path.exists(ncover):
|
||||||
os.remove(ncover)
|
os.remove(ncover)
|
||||||
shutil.copyfile(cover, ncover)
|
shutil.copyfile(cover, ncover)
|
||||||
opf.cover = ncover.replace(os.sep, '/')
|
cover_copied = os.path.abspath(ncover)
|
||||||
|
opf.cover = ncover.replace(os.sep, '/')
|
||||||
|
|
||||||
manifest = [(htmlfile, 'application/xhtml+xml'),
|
manifest = [(htmlfile, 'application/xhtml+xml'),
|
||||||
(os.path.abspath('styles.css'), 'text/css')]
|
(os.path.abspath('styles.css'), 'text/css')]
|
||||||
bp = os.path.dirname(htmlfile)
|
bp = os.path.dirname(htmlfile)
|
||||||
|
added = set([])
|
||||||
for i in getattr(self, 'image_names', []):
|
for i in getattr(self, 'image_names', []):
|
||||||
manifest.append((os.path.join(bp, 'images/', i), 'image/jpeg'))
|
path = os.path.join(bp, 'images', i)
|
||||||
|
added.add(path)
|
||||||
|
manifest.append((path, 'image/jpeg'))
|
||||||
|
if cover_copied is not None:
|
||||||
|
manifest.append((cover_copied, 'image/jpeg'))
|
||||||
|
|
||||||
opf.create_manifest(manifest)
|
opf.create_manifest(manifest)
|
||||||
opf.create_spine([os.path.basename(htmlfile)])
|
opf.create_spine([os.path.basename(htmlfile)])
|
||||||
|
@ -212,11 +212,12 @@ class EbookIterator(object):
|
|||||||
|
|
||||||
cover = self.opf.cover
|
cover = self.opf.cover
|
||||||
if self.ebook_ext in ('lit', 'mobi', 'prc', 'opf') and cover:
|
if self.ebook_ext in ('lit', 'mobi', 'prc', 'opf') and cover:
|
||||||
cfile = os.path.join(os.path.dirname(self.spine[0]),
|
cfile = os.path.join(self.base, 'calibre_iterator_cover.html')
|
||||||
'calibre_iterator_cover.html')
|
chtml = (TITLEPAGE%os.path.relpath(cover, self.base).replace(os.sep,
|
||||||
chtml = (TITLEPAGE%cover).encode('utf-8')
|
'/')).encode('utf-8')
|
||||||
open(cfile, 'wb').write(chtml)
|
open(cfile, 'wb').write(chtml)
|
||||||
self.spine[0:0] = [SpineItem(cfile)]
|
self.spine[0:0] = [SpineItem(cfile,
|
||||||
|
mime_type='application/xhtml+xml')]
|
||||||
self.delete_on_exit.append(cfile)
|
self.delete_on_exit.append(cfile)
|
||||||
|
|
||||||
if self.opf.path_to_html_toc is not None and \
|
if self.opf.path_to_html_toc is not None and \
|
||||||
|
@ -318,8 +318,8 @@ class Stylizer(object):
|
|||||||
if text == 'inherit':
|
if text == 'inherit':
|
||||||
style['text-align'] = 'inherit'
|
style['text-align'] = 'inherit'
|
||||||
else:
|
else:
|
||||||
if text in ('left', 'justify'):
|
if text in ('left', 'justify') and self.opts.change_justification in ('left', 'justify'):
|
||||||
val = 'left' if self.opts.dont_justify else 'justify'
|
val = self.opts.change_justification
|
||||||
style['text-align'] = val
|
style['text-align'] = val
|
||||||
else:
|
else:
|
||||||
style['text-align'] = text
|
style['text-align'] = text
|
||||||
|
@ -138,8 +138,8 @@ class CSSFlattener(object):
|
|||||||
float(self.context.margin_left))
|
float(self.context.margin_left))
|
||||||
bs.append('margin-right : %fpt'%\
|
bs.append('margin-right : %fpt'%\
|
||||||
float(self.context.margin_right))
|
float(self.context.margin_right))
|
||||||
bs.append('text-align: '+ \
|
if self.context.change_justification != 'original':
|
||||||
('left' if self.context.dont_justify else 'justify'))
|
bs.append('text-align: '+ self.context.change_justification)
|
||||||
body.set('style', '; '.join(bs))
|
body.set('style', '; '.join(bs))
|
||||||
stylizer = Stylizer(html, item.href, self.oeb, self.context, profile,
|
stylizer = Stylizer(html, item.href, self.oeb, self.context, profile,
|
||||||
user_css=self.context.extra_css,
|
user_css=self.context.extra_css,
|
||||||
|
@ -19,7 +19,7 @@ class LookAndFeelWidget(Widget, Ui_Form):
|
|||||||
|
|
||||||
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||||
Widget.__init__(self, parent, 'look_and_feel',
|
Widget.__init__(self, parent, 'look_and_feel',
|
||||||
['dont_justify', 'extra_css', 'base_font_size',
|
['change_justification', 'extra_css', 'base_font_size',
|
||||||
'font_size_mapping', 'line_height',
|
'font_size_mapping', 'line_height',
|
||||||
'linearize_tables',
|
'linearize_tables',
|
||||||
'disable_font_rescaling', 'insert_blank_line',
|
'disable_font_rescaling', 'insert_blank_line',
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../../../resources/images.qrc">
|
<iconset>
|
||||||
<normaloff>:/images/wizard.svg</normaloff>:/images/wizard.svg</iconset>
|
<normaloff>:/images/wizard.svg</normaloff>:/images/wizard.svg</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="iconSize">
|
<property name="iconSize">
|
||||||
@ -181,21 +181,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
|
||||||
<widget class="QCheckBox" name="opt_insert_blank_line">
|
|
||||||
<property name="text">
|
|
||||||
<string>Insert &blank line</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="0">
|
<item row="7" column="0">
|
||||||
<widget class="QCheckBox" name="opt_dont_justify">
|
|
||||||
<property name="text">
|
|
||||||
<string>No text &justification</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="8" column="0">
|
|
||||||
<widget class="QCheckBox" name="opt_linearize_tables">
|
<widget class="QCheckBox" name="opt_linearize_tables">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Linearize tables</string>
|
<string>&Linearize tables</string>
|
||||||
@ -221,6 +207,42 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_insert_blank_line">
|
||||||
|
<property name="text">
|
||||||
|
<string>Insert &blank line</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Text justification:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="2">
|
||||||
|
<widget class="QComboBox" name="opt_change_justification">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>justify</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>left</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>original</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
|
@ -29,6 +29,7 @@ class SchedulerDialog(QDialog, Ui_Dialog):
|
|||||||
self.recipe_model.do_refresh()
|
self.recipe_model.do_refresh()
|
||||||
|
|
||||||
self.search = SearchBox2(self)
|
self.search = SearchBox2(self)
|
||||||
|
self.search.setMinimumContentsLength(25)
|
||||||
self.search.initialize('scheduler_search_history')
|
self.search.initialize('scheduler_search_history')
|
||||||
self.recipe_box.layout().insertWidget(0, self.search)
|
self.recipe_box.layout().insertWidget(0, self.search)
|
||||||
self.connect(self.search, SIGNAL('search(PyQt_PyObject,PyQt_PyObject)'),
|
self.connect(self.search, SIGNAL('search(PyQt_PyObject,PyQt_PyObject)'),
|
||||||
|
@ -7,9 +7,9 @@ from math import cos, sin, pi
|
|||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
||||||
from PyQt4.QtGui import QTableView, QAbstractItemView, QColor, \
|
from PyQt4.QtGui import QTableView, QAbstractItemView, QColor, \
|
||||||
QItemDelegate, QPainterPath, QLinearGradient, QBrush, \
|
QPainterPath, QLinearGradient, QBrush, \
|
||||||
QPen, QStyle, QPainter, \
|
QPen, QStyle, QPainter, QStyleOptionViewItemV4, \
|
||||||
QImage, QApplication, QMenu, \
|
QImage, QMenu, \
|
||||||
QStyledItemDelegate, QCompleter
|
QStyledItemDelegate, QCompleter
|
||||||
from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, pyqtSignal, \
|
from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, pyqtSignal, \
|
||||||
SIGNAL, QObject, QSize, QModelIndex, QDate
|
SIGNAL, QObject, QSize, QModelIndex, QDate
|
||||||
@ -28,14 +28,15 @@ from calibre.ebooks.metadata import string_to_authors, fmt_sidx, \
|
|||||||
from calibre.utils.config import tweaks
|
from calibre.utils.config import tweaks
|
||||||
from calibre.utils.date import dt_factory, qt_to_dt, isoformat
|
from calibre.utils.date import dt_factory, qt_to_dt, isoformat
|
||||||
|
|
||||||
class LibraryDelegate(QItemDelegate):
|
class LibraryDelegate(QStyledItemDelegate):
|
||||||
COLOR = QColor("blue")
|
COLOR = QColor("blue")
|
||||||
SIZE = 16
|
SIZE = 16
|
||||||
PEN = QPen(COLOR, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
|
PEN = QPen(COLOR, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QItemDelegate.__init__(self, parent)
|
QStyledItemDelegate.__init__(self, parent)
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
|
self.dummy = QModelIndex()
|
||||||
self.star_path = QPainterPath()
|
self.star_path = QPainterPath()
|
||||||
self.star_path.moveTo(90, 50)
|
self.star_path.moveTo(90, 50)
|
||||||
for i in range(1, 5):
|
for i in range(1, 5):
|
||||||
@ -54,6 +55,9 @@ class LibraryDelegate(QItemDelegate):
|
|||||||
return QSize(5*(self.SIZE), self.SIZE+4)
|
return QSize(5*(self.SIZE), self.SIZE+4)
|
||||||
|
|
||||||
def paint(self, painter, option, index):
|
def paint(self, painter, option, index):
|
||||||
|
style = self._parent.style()
|
||||||
|
option = QStyleOptionViewItemV4(option)
|
||||||
|
self.initStyleOption(option, self.dummy)
|
||||||
num = index.model().data(index, Qt.DisplayRole).toInt()[0]
|
num = index.model().data(index, Qt.DisplayRole).toInt()[0]
|
||||||
def draw_star():
|
def draw_star():
|
||||||
painter.save()
|
painter.save()
|
||||||
@ -66,11 +70,10 @@ class LibraryDelegate(QItemDelegate):
|
|||||||
|
|
||||||
painter.save()
|
painter.save()
|
||||||
if hasattr(QStyle, 'CE_ItemViewItem'):
|
if hasattr(QStyle, 'CE_ItemViewItem'):
|
||||||
QApplication.style().drawControl(QStyle.CE_ItemViewItem, option,
|
style.drawControl(QStyle.CE_ItemViewItem, option,
|
||||||
painter, self._parent)
|
painter, self._parent)
|
||||||
elif option.state & QStyle.State_Selected:
|
elif option.state & QStyle.State_Selected:
|
||||||
painter.fillRect(option.rect, option.palette.highlight())
|
painter.fillRect(option.rect, option.palette.highlight())
|
||||||
self.drawFocus(painter, option, option.rect)
|
|
||||||
try:
|
try:
|
||||||
painter.setRenderHint(QPainter.Antialiasing)
|
painter.setRenderHint(QPainter.Antialiasing)
|
||||||
painter.setClipRect(option.rect)
|
painter.setClipRect(option.rect)
|
||||||
@ -89,7 +92,7 @@ class LibraryDelegate(QItemDelegate):
|
|||||||
painter.restore()
|
painter.restore()
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
sb = QItemDelegate.createEditor(self, parent, option, index)
|
sb = QStyledItemDelegate.createEditor(self, parent, option, index)
|
||||||
sb.setMinimum(0)
|
sb.setMinimum(0)
|
||||||
sb.setMaximum(5)
|
sb.setMaximum(5)
|
||||||
return sb
|
return sb
|
||||||
|
@ -194,6 +194,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
|||||||
self.tool_bar2.insertSeparator(self.action_find_next)
|
self.tool_bar2.insertSeparator(self.action_find_next)
|
||||||
self.setFocusPolicy(Qt.StrongFocus)
|
self.setFocusPolicy(Qt.StrongFocus)
|
||||||
self.search = SearchBox2(self)
|
self.search = SearchBox2(self)
|
||||||
|
self.search.setMinimumContentsLength(20)
|
||||||
self.search.initialize('viewer_search_history')
|
self.search.initialize('viewer_search_history')
|
||||||
self.search.setToolTip(_('Search for text in book'))
|
self.search.setToolTip(_('Search for text in book'))
|
||||||
self.search.setMinimumWidth(200)
|
self.search.setMinimumWidth(200)
|
||||||
|
@ -551,7 +551,8 @@ class LineEditECM(object):
|
|||||||
self.setText(unicode(self.text()).swapcase())
|
self.setText(unicode(self.text()).swapcase())
|
||||||
|
|
||||||
def title_case(self):
|
def title_case(self):
|
||||||
self.setText(unicode(self.text()).title())
|
from calibre.utils.titlecase import titlecase
|
||||||
|
self.setText(titlecase(unicode(self.text())))
|
||||||
|
|
||||||
|
|
||||||
class EnLineEdit(LineEditECM, QLineEdit):
|
class EnLineEdit(LineEditECM, QLineEdit):
|
||||||
|
@ -123,10 +123,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
self.is_case_sensitive = not iswindows and not isosx and \
|
self.is_case_sensitive = not iswindows and not isosx and \
|
||||||
not os.path.exists(self.dbpath.replace('metadata.db', 'MeTAdAtA.dB'))
|
not os.path.exists(self.dbpath.replace('metadata.db', 'MeTAdAtA.dB'))
|
||||||
SchemaUpgrade.__init__(self)
|
SchemaUpgrade.__init__(self)
|
||||||
CustomColumns.__init__(self)
|
|
||||||
self.initialize_dynamic()
|
self.initialize_dynamic()
|
||||||
|
|
||||||
def initialize_dynamic(self):
|
def initialize_dynamic(self):
|
||||||
|
CustomColumns.__init__(self)
|
||||||
template = '''\
|
template = '''\
|
||||||
(SELECT {query} FROM books_{table}_link AS link INNER JOIN
|
(SELECT {query} FROM books_{table}_link AS link INNER JOIN
|
||||||
{table} ON(link.{link_col}={table}.id) WHERE link.book=books.id)
|
{table} ON(link.{link_col}={table}.id) WHERE link.book=books.id)
|
||||||
@ -1428,6 +1428,7 @@ books_series_link feeds
|
|||||||
os.remove(self.dbpath)
|
os.remove(self.dbpath)
|
||||||
shutil.copyfile(dest, self.dbpath)
|
shutil.copyfile(dest, self.dbpath)
|
||||||
self.connect()
|
self.connect()
|
||||||
|
self.initialize_dynamic()
|
||||||
self.refresh()
|
self.refresh()
|
||||||
if os.path.exists(dest):
|
if os.path.exists(dest):
|
||||||
os.remove(dest)
|
os.remove(dest)
|
||||||
|
@ -81,7 +81,7 @@ Device Integration
|
|||||||
|
|
||||||
What devices does |app| support?
|
What devices does |app| support?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
At the moment |app| has full support for the SONY PRS 300/500/505/600/700/900, Barnes & Noble Nook, Cybook Gen 3/Opus, Amazon Kindle 1/2/DX, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook 360, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3, various Android phones and the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
At the moment |app| has full support for the SONY PRS 300/500/505/600/700/900, Barnes & Noble Nook, Cybook Gen 3/Opus, Amazon Kindle 1/2/DX, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook 360, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3, SpringDesign Alex, various Android phones and the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
||||||
|
|
||||||
How can I help get my device supported in |app|?
|
How can I help get my device supported in |app|?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
94
src/calibre/utils/titlecase.py
Executable file
94
src/calibre/utils/titlecase.py
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Original Perl version by: John Gruber http://daringfireball.net/ 10 May 2008
|
||||||
|
Python version by Stuart Colville http://muffinresearch.co.uk
|
||||||
|
License: http://www.opensource.org/licenses/mit-license.php
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
__all__ = ['titlecase']
|
||||||
|
__version__ = '0.5'
|
||||||
|
|
||||||
|
SMALL = 'a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v\.?|via|vs\.?'
|
||||||
|
PUNCT = r"""!"#$%&'‘()*+,\-./:;?@[\\\]_`{|}~"""
|
||||||
|
|
||||||
|
SMALL_WORDS = re.compile(r'^(%s)$' % SMALL, re.I)
|
||||||
|
INLINE_PERIOD = re.compile(r'[a-z][.][a-z]', re.I)
|
||||||
|
UC_ELSEWHERE = re.compile(r'[%s]*?[a-zA-Z]+[A-Z]+?' % PUNCT)
|
||||||
|
CAPFIRST = re.compile(r"^[%s]*?([A-Za-z])" % PUNCT)
|
||||||
|
SMALL_FIRST = re.compile(r'^([%s]*)(%s)\b' % (PUNCT, SMALL), re.I)
|
||||||
|
SMALL_LAST = re.compile(r'\b(%s)[%s]?$' % (SMALL, PUNCT), re.I)
|
||||||
|
SUBPHRASE = re.compile(r'([:.;?!][ ])(%s)' % SMALL)
|
||||||
|
APOS_SECOND = re.compile(r"^[dol]{1}['‘]{1}[a-z]+$", re.I)
|
||||||
|
ALL_CAPS = re.compile(r'^[A-Z\s%s]+$' % PUNCT)
|
||||||
|
UC_INITIALS = re.compile(r"^(?:[A-Z]{1}\.{1}|[A-Z]{1}\.{1}[A-Z]{1})+$")
|
||||||
|
MAC_MC = re.compile(r"^([Mm]a?c)(\w+)")
|
||||||
|
|
||||||
|
def titlecase(text):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Titlecases input text
|
||||||
|
|
||||||
|
This filter changes all words to Title Caps, and attempts to be clever
|
||||||
|
about *un*capitalizing SMALL words like a/an/the in the input.
|
||||||
|
|
||||||
|
The list of "SMALL words" which are not capped comes from
|
||||||
|
the New York Times Manual of Style, plus 'vs' and 'v'.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
all_caps = ALL_CAPS.match(text)
|
||||||
|
|
||||||
|
words = re.split('\s', text)
|
||||||
|
line = []
|
||||||
|
for word in words:
|
||||||
|
if all_caps:
|
||||||
|
if UC_INITIALS.match(word):
|
||||||
|
line.append(word)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
word = word.lower()
|
||||||
|
|
||||||
|
if APOS_SECOND.match(word):
|
||||||
|
word = word.replace(word[0], word[0].upper())
|
||||||
|
word = word.replace(word[2], word[2].upper())
|
||||||
|
line.append(word)
|
||||||
|
continue
|
||||||
|
if INLINE_PERIOD.search(word) or UC_ELSEWHERE.match(word):
|
||||||
|
line.append(word)
|
||||||
|
continue
|
||||||
|
if SMALL_WORDS.match(word):
|
||||||
|
line.append(word.lower())
|
||||||
|
continue
|
||||||
|
|
||||||
|
match = MAC_MC.match(word)
|
||||||
|
if match:
|
||||||
|
line.append("%s%s" % (match.group(1).capitalize(),
|
||||||
|
match.group(2).capitalize()))
|
||||||
|
continue
|
||||||
|
|
||||||
|
hyphenated = []
|
||||||
|
for item in word.split('-'):
|
||||||
|
hyphenated.append(CAPFIRST.sub(lambda m: m.group(0).upper(), item))
|
||||||
|
line.append("-".join(hyphenated))
|
||||||
|
|
||||||
|
|
||||||
|
result = " ".join(line)
|
||||||
|
|
||||||
|
result = SMALL_FIRST.sub(lambda m: '%s%s' % (
|
||||||
|
m.group(1),
|
||||||
|
m.group(2).capitalize()
|
||||||
|
), result)
|
||||||
|
|
||||||
|
result = SMALL_LAST.sub(lambda m: m.group(0).capitalize(), result)
|
||||||
|
|
||||||
|
result = SUBPHRASE.sub(lambda m: '%s%s' % (
|
||||||
|
m.group(1),
|
||||||
|
m.group(2).capitalize()
|
||||||
|
), result)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
@ -113,7 +113,7 @@ class NewsItem(NewsTreeItem):
|
|||||||
return NONE
|
return NONE
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(self.title, getattr(other, 'title', ''))
|
return cmp(self.title.lower(), getattr(other, 'title', '').lower())
|
||||||
|
|
||||||
class RecipeModel(QAbstractItemModel, SearchQueryParser):
|
class RecipeModel(QAbstractItemModel, SearchQueryParser):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user