Merge from trunk

This commit is contained in:
Charles Haley 2011-02-09 17:10:55 +00:00
commit 4ce4469d0f
23 changed files with 199 additions and 88 deletions

View File

@ -32,9 +32,10 @@ series_index_auto_increment = 'next'
# Should the completion separator be append # Should the completion separator be append
# to the end of the completed text to # to the end of the completed text to
# automatically begin a new completion operation. # automatically begin a new completion operation
# for authors.
# Can be either True or False # Can be either True or False
completer_append_separator = False authors_completer_append_separator = False
# The algorithm used to copy author to author_sort # The algorithm used to copy author to author_sort

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

View File

@ -1,6 +1,6 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2011, Darko Miletic <darko.miletic at gmail.com>'
''' '''
b92.net b92.net
''' '''
@ -10,7 +10,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
class B92(BasicNewsRecipe): class B92(BasicNewsRecipe):
title = 'B92' title = 'B92'
__author__ = 'Darko Miletic' __author__ = 'Darko Miletic'
description = 'B92 info, najnovije vesti iz Srbije, regiona i sveta' description = 'Najnovije vesti iz Srbije, regiona i sveta, aktuelne teme iz sveta politike, ekonomije, drustva, foto galerija, kolumne'
publisher = 'B92' publisher = 'B92'
category = 'news, politics, Serbia' category = 'news, politics, Serbia'
oldest_article = 2 oldest_article = 2
@ -20,34 +20,44 @@ class B92(BasicNewsRecipe):
encoding = 'cp1250' encoding = 'cp1250'
language = 'sr' language = 'sr'
publication_type = 'newsportal' publication_type = 'newsportal'
extra_css = ' @font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: serif1, serif} ' masthead_url = 'http://www.b92.net/images/fp/logo.gif'
extra_css = """
@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
body{font-family: Arial,Helvetica,sans1,sans-serif}
.articledescription{font-family: serif1, serif}
.article-info2,.article-info1{text-transform: uppercase; font-size: small}
"""
conversion_options = { conversion_options = {
'comment' : description 'comment' : description
, 'tags' : category , 'tags' : category
, 'publisher' : publisher , 'publisher': publisher
, 'language' : language , 'language' : language
, 'linearize_tables' : True , 'linearize_tables' : True
} }
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
keep_only_tags = [dict(name='table', attrs={'class':'maindocument'})] keep_only_tags = [dict(attrs={'class':['article-info1','article-text']})]
remove_attributes = ['width','height','align','hspace','vspace','border']
remove_tags = [ remove_tags = [dict(name=['embed','link','base','meta'])]
dict(name='ul', attrs={'class':'comment-nav'})
,dict(name=['embed','link','base'] )
,dict(name='div', attrs={'class':'udokum'} )
]
feeds = [ feeds = [
(u'Vesti', u'http://www.b92.net/info/rss/vesti.xml') (u'Vesti' , u'http://www.b92.net/info/rss/vesti.xml' )
,(u'Biz' , u'http://www.b92.net/info/rss/biz.xml' ) ,(u'Biz' , u'http://www.b92.net/info/rss/biz.xml' )
,(u'Sport' , u'http://www.b92.net/info/rss/sport.xml' )
,(u'Zivot' , u'http://www.b92.net/info/rss/zivot.xml' )
,(u'Kultura' , u'http://www.b92.net/info/rss/kultura.xml' )
,(u'Automobili' , u'http://www.b92.net/info/rss/automobili.xml')
,(u'Tehnopolis' , u'http://www.b92.net/info/rss/tehnopolis.xml')
] ]
def print_version(self, url):
return url + '&version=print'
def preprocess_html(self, soup): def preprocess_html(self, soup):
return self.adeify_images(soup) for item in soup.findAll(style=True):
del item['style']
for alink in soup.findAll('a'):
if alink.string is not None:
tstr = alink.string
alink.replaceWith(tstr)
return soup

View File

@ -0,0 +1,61 @@
__license__ = 'GPL v3'
__copyright__ = '2011, Darko Miletic <darko.miletic at gmail.com>'
'''
njuz.net
'''
import re
from calibre.web.feeds.news import BasicNewsRecipe
class NjuzNet(BasicNewsRecipe):
title = 'Njuz.net'
__author__ = 'Darko Miletic'
description = 'Iscasene vesti iz Srbije, regiona i sveta'
publisher = 'njuz.net'
category = 'news, politics, humor, Serbia'
oldest_article = 2
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
encoding = 'utf8'
language = 'sr'
publication_type = 'newsportal'
masthead_url = 'http://www.njuz.net/njuznet.jpg'
extra_css = """
@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
body{font-family: serif1, serif}
.articledescription{font-family: serif1, serif}
.wp-caption-text{font-size: x-small}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
keep_only_tags = [
dict(attrs={'id':'entryMeta'})
,dict(attrs={'class':'post'})
]
remove_tags = [
dict(name=['embed','link','base','iframe','object','meta','fb:like'])
,dict(name='div', attrs={'id':'tagsandcats'})
]
remove_tags_after= dict(name='div', attrs={'id':'tagsandcats'})
remove_attributes= ['lang']
feeds = [(u'Clanci', u'http://www.njuz.net/feed/')]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
for alink in soup.findAll('a'):
if alink.string is not None:
tstr = alink.string
alink.replaceWith(tstr)
return soup

View File

@ -27,7 +27,7 @@ class TazDigiabo(BasicNewsRecipe):
} }
def build_index(self): def build_index(self):
domain = "http://www.taz.de" domain = "http://dl.taz.de"
url = domain + "/epub/" url = domain + "/epub/"

View File

@ -62,6 +62,12 @@ class ANDROID(USBMS):
# Archos # Archos
0x0e79 : { 0x1419: [0x0216], 0x1420 : [0x0216], 0x1422 : [0x0216]}, 0x0e79 : { 0x1419: [0x0216], 0x1420 : [0x0216], 0x1422 : [0x0216]},
# Huawei
0x45e : { 0x00e1 : [0x007], },
# T-Mobile
0x0408 : { 0x03ba : [0x0109], },
} }
EBOOK_DIR_MAIN = ['eBooks/import', 'wordplayer/calibretransfer', 'Books'] EBOOK_DIR_MAIN = ['eBooks/import', 'wordplayer/calibretransfer', 'Books']
EXTRA_CUSTOMIZATION_MESSAGE = _('Comma separated list of directories to ' EXTRA_CUSTOMIZATION_MESSAGE = _('Comma separated list of directories to '
@ -71,12 +77,13 @@ class ANDROID(USBMS):
VENDOR_NAME = ['HTC', 'MOTOROLA', 'GOOGLE_', 'ANDROID', 'ACER', VENDOR_NAME = ['HTC', 'MOTOROLA', 'GOOGLE_', 'ANDROID', 'ACER',
'GT-I5700', 'SAMSUNG', 'DELL', 'LINUX', 'GOOGLE', 'ARCHOS', 'GT-I5700', 'SAMSUNG', 'DELL', 'LINUX', 'GOOGLE', 'ARCHOS',
'TELECHIP'] 'TELECHIP', 'HUAWEI', 'T-MOBILE', ]
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE', WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897', '__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID',
'SCH-I500_CARD', 'SPH-D700_CARD', 'MB810', 'GT-P1000', 'DESIRE', 'SCH-I500_CARD', 'SPH-D700_CARD', 'MB810', 'GT-P1000', 'DESIRE',
'SGH-T849', '_MB300', 'A70S', 'S_ANDROID', 'A101IT', 'A70H'] 'SGH-T849', '_MB300', 'A70S', 'S_ANDROID', 'A101IT', 'A70H',
'IDEOS_TABLET', 'MYTOUCH_4G']
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897', WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
'A70S', 'A101IT'] 'A70S', 'A101IT']

View File

@ -81,22 +81,23 @@ class HeuristicProcessor(object):
def insert_indent(self, match): def insert_indent(self, match):
pstyle = match.group('formatting') pstyle = match.group('formatting')
tag = match.group('tagtype')
span = match.group('span') span = match.group('span')
self.found_indents = self.found_indents + 1 self.found_indents = self.found_indents + 1
if pstyle: if pstyle:
if pstyle.lower().find('style'): if pstyle.lower().find('style') != -1:
pstyle = re.sub(r'"$', '; text-indent:3%"', pstyle) pstyle = re.sub(r'"$', '; text-indent:3%"', pstyle)
else: else:
pstyle = pstyle+' style="text-indent:3%"' pstyle = pstyle+' style="text-indent:3%"'
if not span: if not span:
return '<p '+pstyle+'>' return '<'+tag+' '+pstyle+'>'
else: else:
return '<p '+pstyle+'>'+span return '<'+tag+' '+pstyle+'>'+span
else: else:
if not span: if not span:
return '<p style="text-indent:3%">' return '<'+tag+' style="text-indent:3%">'
else: else:
return '<p style="text-indent:3%">'+span return '<'+tag+' style="text-indent:3%">'+span
def no_markup(self, raw, percent): def no_markup(self, raw, percent):
''' '''
@ -369,7 +370,7 @@ class HeuristicProcessor(object):
return html return html
def fix_nbsp_indents(self, html): def fix_nbsp_indents(self, html):
txtindent = re.compile(ur'<p(?P<formatting>[^>]*)>\s*(?P<span>(<span[^>]*>\s*)+)?\s*(\u00a0){2,}', re.IGNORECASE) txtindent = re.compile(ur'<(?P<tagtype>p|div)(?P<formatting>[^>]*)>\s*(?P<span>(<span[^>]*>\s*)+)?\s*(\u00a0){2,}', re.IGNORECASE)
html = txtindent.sub(self.insert_indent, html) html = txtindent.sub(self.insert_indent, html)
if self.found_indents > 1: if self.found_indents > 1:
self.log.debug("replaced "+unicode(self.found_indents)+ " nbsp indents with inline styles") self.log.debug("replaced "+unicode(self.found_indents)+ " nbsp indents with inline styles")

View File

@ -103,6 +103,8 @@ class OEBReader(object):
data = self.oeb.container.read(None) data = self.oeb.container.read(None)
data = self.oeb.decode(data) data = self.oeb.decode(data)
data = XMLDECL_RE.sub('', data) data = XMLDECL_RE.sub('', data)
data = data.replace('http://openebook.org/namespaces/oeb-package/1.0',
OPF1_NS)
try: try:
opf = etree.fromstring(data) opf = etree.fromstring(data)
except etree.XMLSyntaxError: except etree.XMLSyntaxError:

View File

@ -41,7 +41,6 @@ class TextileMLizer(object):
html = re.sub(r'<\s*img[^>]*>', '', html) html = re.sub(r'<\s*img[^>]*>', '', html)
text = html2textile(html) text = html2textile(html)
text = text.replace('%', '')
# Ensure the section ends with at least two new line characters. # Ensure the section ends with at least two new line characters.
# This is to prevent the last paragraph from a section being # This is to prevent the last paragraph from a section being

View File

@ -9,10 +9,9 @@ __docformat__ = 'restructuredtext en'
from PyQt4.Qt import QLineEdit, QAbstractListModel, Qt, \ from PyQt4.Qt import QLineEdit, QAbstractListModel, Qt, \
QApplication, QCompleter QApplication, QCompleter
from calibre.utils.config import tweaks
from calibre.utils.icu import sort_key, lower from calibre.utils.icu import sort_key, lower
from calibre.gui2 import NONE from calibre.gui2 import NONE
from calibre.gui2.widgets import EnComboBox from calibre.gui2.widgets import EnComboBox, LineEditECM
class CompleteModel(QAbstractListModel): class CompleteModel(QAbstractListModel):
@ -39,7 +38,7 @@ class CompleteModel(QAbstractListModel):
return NONE return NONE
class MultiCompleteLineEdit(QLineEdit): class MultiCompleteLineEdit(QLineEdit, LineEditECM):
''' '''
A line edit that completes on multiple items separated by a A line edit that completes on multiple items separated by a
separator. Use the :meth:`update_items_cache` to set the list of separator. Use the :meth:`update_items_cache` to set the list of
@ -55,6 +54,8 @@ class MultiCompleteLineEdit(QLineEdit):
self.sep = ',' self.sep = ','
self.space_before_sep = False self.space_before_sep = False
self.add_separator = True
self.original_cursor_pos = None
self._model = CompleteModel(parent=self) self._model = CompleteModel(parent=self)
self._completer = c = QCompleter(self._model, self) self._completer = c = QCompleter(self._model, self)
@ -82,6 +83,9 @@ class MultiCompleteLineEdit(QLineEdit):
def set_space_before_sep(self, space_before): def set_space_before_sep(self, space_before):
self.space_before_sep = space_before self.space_before_sep = space_before
def set_add_separator(self, what):
self.add_separator = bool(what)
# }}} # }}}
def item_entered(self, idx): def item_entered(self, idx):
@ -93,7 +97,7 @@ class MultiCompleteLineEdit(QLineEdit):
def update_completions(self): def update_completions(self):
' Update the list of completions ' ' Update the list of completions '
cpos = self.cursorPosition() self.original_cursor_pos = cpos = self.cursorPosition()
text = unicode(self.text()) text = unicode(self.text())
prefix = text[:cpos] prefix = text[:cpos]
self.current_prefix = prefix self.current_prefix = prefix
@ -103,38 +107,38 @@ class MultiCompleteLineEdit(QLineEdit):
self._completer.setCompletionPrefix(complete_prefix) self._completer.setCompletionPrefix(complete_prefix)
def get_completed_text(self, text): def get_completed_text(self, text):
''' 'Get completed text in before and after parts'
Get completed text from current cursor position and the completion
text
'''
if self.sep is None: if self.sep is None:
return -1, text return text, ''
else: else:
cursor_pos = self.original_cursor_pos
if cursor_pos is None:
cursor_pos = self.cursorPosition() cursor_pos = self.cursorPosition()
before_text = unicode(self.text())[:cursor_pos] self.original_cursor_pos = None
after_text = unicode(self.text())[cursor_pos:] # Split text
prefix_len = len(before_text.split(self.sep)[-1].lstrip()) curtext = unicode(self.text())
if tweaks['completer_append_separator']: before_text = curtext[:cursor_pos]
prefix_len = len(before_text.split(self.sep)[-1].lstrip()) after_text = curtext[cursor_pos:].rstrip()
completed_text = before_text[:cursor_pos - prefix_len] + text + self.sep + ' ' + after_text # Remove the completion prefix from the before text
prefix_len = prefix_len - len(self.sep) - 1 before_text = self.sep.join(before_text.split(self.sep)[:-1]).rstrip()
if prefix_len < 0: if before_text:
prefix_len = 0 # Add the separator to the end of before_text
if self.space_before_sep:
before_text += ' '
before_text += self.sep + ' '
if self.add_separator or after_text:
# Add separator to the end of completed text
if self.space_before_sep:
text = text.rstrip() + ' '
completed_text = text + self.sep + ' '
else: else:
prefix_len = len(before_text.split(self.sep)[-1].lstrip()) completed_text = text
completed_text = before_text[:cursor_pos - prefix_len] + text + after_text return before_text + completed_text, after_text
return prefix_len, completed_text
def completion_selected(self, text): def completion_selected(self, text):
prefix_len, ctext = self.get_completed_text(unicode(text)) before_text, after_text = self.get_completed_text(unicode(text))
if self.sep is None: self.setText(before_text + after_text)
self.setText(ctext) self.setCursorPosition(len(before_text))
self.setCursorPosition(len(ctext))
else:
cursor_pos = self.cursorPosition()
self.setText(ctext)
self.setCursorPosition(cursor_pos - prefix_len + len(text))
@dynamic_property @dynamic_property
def all_items(self): def all_items(self):
@ -164,6 +168,9 @@ class MultiCompleteComboBox(EnComboBox):
def set_space_before_sep(self, space_before): def set_space_before_sep(self, space_before):
self.lineEdit().set_space_before_sep(space_before) self.lineEdit().set_space_before_sep(space_before)
def set_add_separator(self, what):
self.lineEdit().set_add_separator(what)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -19,6 +19,7 @@ from calibre.ptempfile import PersistentTemporaryFile
from calibre.gui2.convert import Widget from calibre.gui2.convert import Widget
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
from calibre.library.comments import comments_to_html from calibre.library.comments import comments_to_html
from calibre.utils.config import tweaks
def create_opf_file(db, book_id): def create_opf_file(db, book_id):
mi = db.get_metadata(book_id, index_is_id=True) mi = db.get_metadata(book_id, index_is_id=True)
@ -108,6 +109,7 @@ class MetadataWidget(Widget, Ui_Form):
all_authors.sort(key=lambda x : sort_key(x[1])) all_authors.sort(key=lambda x : sort_key(x[1]))
self.author.set_separator('&') self.author.set_separator('&')
self.author.set_space_before_sep(True) self.author.set_space_before_sep(True)
self.author.set_add_separator(tweaks['authors_completer_append_separator'])
self.author.update_items_cache(self.db.all_author_names()) self.author.update_items_cache(self.db.all_author_names())
for i in all_authors: for i in all_authors:

View File

@ -8,8 +8,6 @@ __docformat__ = 'restructuredtext en'
from calibre.gui2.convert.txt_output_ui import Ui_Form from calibre.gui2.convert.txt_output_ui import Ui_Form
from calibre.gui2.convert import Widget from calibre.gui2.convert import Widget
newline_model = None
class PluginWidget(Widget, Ui_Form): class PluginWidget(Widget, Ui_Form):
TITLE = _('TXT Output') TITLE = _('TXT Output')

View File

@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
__license__ = 'GPL 3'
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en'
from calibre.gui2.convert.txt_output import PluginWidget as TXTPluginWidget
class PluginWidget(TXTPluginWidget):
TITLE = _('TXTZ Output')
HELP = _('Options specific to')+' TXTZ '+_('output')
COMMIT_NAME = 'txtz_output'

View File

@ -1026,6 +1026,20 @@ class DeviceMixin(object): # {{{
self.location_manager.free[1] : 'carda', self.location_manager.free[1] : 'carda',
self.location_manager.free[2] : 'cardb' } self.location_manager.free[2] : 'cardb' }
on_card = space.get(sorted(space.keys(), reverse=True)[0], None) on_card = space.get(sorted(space.keys(), reverse=True)[0], None)
try:
total_size = sum([os.stat(f).st_size for f in files])
except:
try:
import traceback
traceback.print_exc()
except:
pass
total_size = self.location_manager.free[0]
if self.location_manager.free[0] > total_size + (1024**2):
# Send news to main memory if enough space available
# as some devices like the Nook Color cannot handle
# periodicals on SD cards properly
on_card = None
self.upload_books(files, names, metadata, self.upload_books(files, names, metadata,
on_card=on_card, on_card=on_card,
memory=[files, remove]) memory=[files, remove])

View File

@ -9,6 +9,7 @@ from PyQt4.Qt import QDialog, QGridLayout, QLabel, QDialogButtonBox, \
from calibre.ebooks.metadata import authors_to_string, string_to_authors from calibre.ebooks.metadata import authors_to_string, string_to_authors
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
from calibre.gui2.complete import MultiCompleteComboBox from calibre.gui2.complete import MultiCompleteComboBox
from calibre.utils.config import tweaks
class AddEmptyBookDialog(QDialog): class AddEmptyBookDialog(QDialog):
@ -69,6 +70,7 @@ class AddEmptyBookDialog(QDialog):
self.authors_combo.set_separator('&') self.authors_combo.set_separator('&')
self.authors_combo.set_space_before_sep(True) self.authors_combo.set_space_before_sep(True)
self.authors_combo.set_add_separator(tweaks['authors_completer_append_separator'])
self.authors_combo.update_items_cache(db.all_author_names()) self.authors_combo.update_items_cache(db.all_author_names())
@property @property

View File

@ -781,6 +781,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
self.authors.set_separator('&') self.authors.set_separator('&')
self.authors.set_space_before_sep(True) self.authors.set_space_before_sep(True)
self.authors.set_add_separator(tweaks['authors_completer_append_separator'])
self.authors.update_items_cache(self.db.all_author_names()) self.authors.update_items_cache(self.db.all_author_names())
def initialize_series(self): def initialize_series(self):

View File

@ -735,6 +735,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.authors.set_separator('&') self.authors.set_separator('&')
self.authors.set_space_before_sep(True) self.authors.set_space_before_sep(True)
self.authors.set_add_separator(tweaks['authors_completer_append_separator'])
self.authors.update_items_cache(self.db.all_author_names()) self.authors.update_items_cache(self.db.all_author_names())
def initialize_series(self): def initialize_series(self):

View File

@ -9,6 +9,7 @@ from calibre.gui2.dialogs.search_ui import Ui_Dialog
from calibre.library.caches import CONTAINS_MATCH, EQUALS_MATCH from calibre.library.caches import CONTAINS_MATCH, EQUALS_MATCH
from calibre.gui2 import gprefs from calibre.gui2 import gprefs
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
from calibre.utils.config import tweaks
box_values = {} box_values = {}
@ -31,6 +32,7 @@ class SearchDialog(QDialog, Ui_Dialog):
self.authors_box.setEditText('') self.authors_box.setEditText('')
self.authors_box.set_separator('&') self.authors_box.set_separator('&')
self.authors_box.set_space_before_sep(True) self.authors_box.set_space_before_sep(True)
self.authors_box.set_add_separator(tweaks['authors_completer_append_separator'])
self.authors_box.update_items_cache(db.all_author_names()) self.authors_box.update_items_cache(db.all_author_names())
all_series = db.all_series() all_series = db.all_series()

View File

@ -177,6 +177,8 @@ class CompleteDelegate(QStyledItemDelegate): # {{{
editor = MultiCompleteLineEdit(parent) editor = MultiCompleteLineEdit(parent)
editor.set_separator(self.sep) editor.set_separator(self.sep)
editor.set_space_before_sep(self.space_before_sep) editor.set_space_before_sep(self.space_before_sep)
if self.sep == '&':
editor.set_add_separator(tweaks['authors_completer_append_separator'])
if not index.model().is_custom_column(col): if not index.model().is_custom_column(col):
all_items = getattr(self.db, self.items_func_name)() all_items = getattr(self.db, self.items_func_name)()
else: else:

View File

@ -177,6 +177,7 @@ class AuthorsEdit(MultiCompleteComboBox):
self.set_separator('&') self.set_separator('&')
self.set_space_before_sep(True) self.set_space_before_sep(True)
self.set_add_separator(tweaks['authors_completer_append_separator'])
self.update_items_cache(db.all_author_names()) self.update_items_cache(db.all_author_names())
au = db.authors(id_, index_is_id=True) au = db.authors(id_, index_is_id=True)

View File

@ -109,7 +109,7 @@ class PluginModel(QAbstractItemModel, SearchQueryParser): # {{{
return self.index(ans[0], 0, QModelIndex()) if ans[1] < 0 else \ return self.index(ans[0], 0, QModelIndex()) if ans[1] < 0 else \
self.index(ans[1], 0, self.index(ans[0], 0, QModelIndex())) self.index(ans[1], 0, self.index(ans[0], 0, QModelIndex()))
def index(self, row, column, parent): def index(self, row, column, parent=QModelIndex()):
if not self.hasIndex(row, column, parent): if not self.hasIndex(row, column, parent):
return QModelIndex() return QModelIndex()
@ -165,8 +165,6 @@ class PluginModel(QAbstractItemModel, SearchQueryParser): # {{{
def flags(self, index): def flags(self, index):
if not index.isValid(): if not index.isValid():
return 0 return 0
if index.internalId() == 0:
return Qt.ItemIsEnabled
flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
return flags return flags

View File

@ -182,11 +182,6 @@ If you don't want to uninstall it altogether, there are a couple of tricks you c
simplest is to simply re-name the executable file that launches the library program. More detail simplest is to simply re-name the executable file that launches the library program. More detail
`in the forums <http://www.mobileread.com/forums/showthread.php?t=65809>`_. `in the forums <http://www.mobileread.com/forums/showthread.php?t=65809>`_.
Can I use the collections feature of the SONY reader?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|app| has full support for collections. When you add tags to a book's metadata, those tags are turned into collections when you upload the book to the SONY reader. Also, the series information is automatically
turned into a collection on the reader. Note that the PRS-500 does not support collections for books stored on the SD card. The PRS-505 does.
How do I use |app| with my iPad/iPhone/iTouch? How do I use |app| with my iPad/iPhone/iTouch?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -375,13 +370,6 @@ Content From The Web
:depth: 1 :depth: 1
:local: :local:
My downloaded news content causes the reader to reset.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is a bug in the SONY firmware. The problem can be mitigated by switching the output format to EPUB
in the configuration dialog. Alternatively, you can use the LRF output format and use the SONY software
to transfer the files to the reader. The SONY software pre-paginates the LRF file,
thereby reducing the number of resets.
I obtained a recipe for a news site as a .py file from somewhere, how do I use it? I obtained a recipe for a news site as a .py file from somewhere, how do I use it?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Start the :guilabel:`Add custom news sources` dialog (from the :guilabel:`Fetch news` menu) and click the :guilabel:`Switch to advanced mode` button. Delete everything in the box with the recipe source code and copy paste the contents of your .py file into the box. Click :guilabel:`Add/update recipe`. Start the :guilabel:`Add custom news sources` dialog (from the :guilabel:`Fetch news` menu) and click the :guilabel:`Switch to advanced mode` button. Delete everything in the box with the recipe source code and copy paste the contents of your .py file into the box. Click :guilabel:`Add/update recipe`.
@ -391,7 +379,7 @@ I want |app| to download news from my favorite news website.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are reasonably proficient with computers, you can teach |app| to download news from any website of your choosing. To learn how to do this see :ref:`news`. If you are reasonably proficient with computers, you can teach |app| to download news from any website of your choosing. To learn how to do this see :ref:`news`.
Otherwise, you can register a request for a particular news site by adding a comment `to this ticket <http://bugs.calibre-ebook.com/ticket/405>`_. Otherwise, you can request a particular news site by posting in the `calibre Recipes forum <http://www.mobileread.com/forums/forumdisplay.php?f=228>`_.
Can I use web2disk to download an arbitrary website? Can I use web2disk to download an arbitrary website?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -480,7 +468,7 @@ How do I backup |app|?
The most important thing to backup is the |app| library folder, that contains all your books and metadata. This is the folder you chose for your |app| library when you ran |app| for the first time. You can get the path to the library folder by clicking the |app| icon on the main toolbar. You must backup this complete folder with all its files and sub-folders. The most important thing to backup is the |app| library folder, that contains all your books and metadata. This is the folder you chose for your |app| library when you ran |app| for the first time. You can get the path to the library folder by clicking the |app| icon on the main toolbar. You must backup this complete folder with all its files and sub-folders.
You can switch |app| to using a backed up library folder by simply clicking the |app| icon on the toolbar and choosing your backup library folder. You can switch |app| to using a backed up library folder by simply clicking the |app| icon on the toolbar and choosing your backup library folder. A backed up library folder backs up your custom columns and saved searches as well as all your books and metadata.
If you want to backup the |app| configuration/plugins, you have to backup the config directory. You can find this config directory via :guilabel:`Preferences->Miscellaneous`. Note that restoring configuration directories is not officially supported, but should work in most cases. Just copy the contents of the backup directory into the current configuration directory to restore. If you want to backup the |app| configuration/plugins, you have to backup the config directory. You can find this config directory via :guilabel:`Preferences->Miscellaneous`. Note that restoring configuration directories is not officially supported, but should work in most cases. Just copy the contents of the backup directory into the current configuration directory to restore.
@ -491,7 +479,7 @@ Most purchased EPUB books have `DRM <http://wiki.mobileread.com/wiki/DRM>`_. Thi
I am getting a "Permission Denied" error? I am getting a "Permission Denied" error?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A permission denied error can occur because of many possible reasons, none of them having anything to do with |app|. You can get permission denied errors if you are using an SD card with write protect enabled. Or if you, or some program you used changed the file permissions of the files in question to read only. Or if there is a filesystem error on the device which caused your operating system to mount the filesystem in read only mode or mark a particular file as read only pending recovery. Or if the files have their owner set to a user other than you. You will need to fix the underlying cause of the permissions error before resuming to use |app|. Read the error message carefully, see what file it points to and fix the permissions on that file. A permission denied error can occur because of many possible reasons, none of them having anything to do with |app|. You can get permission denied errors if you are using an SD card with write protect enabled. Or if you, or some program you used changed the file permissions of the files in question to read only. Or if there is a filesystem error on the device which caused your operating system to mount the filesystem in read only mode or mark a particular file as read only pending recovery. Or if the files have their owner set to a user other than you. Or if your file is open in another program. You will need to fix the underlying cause of the permissions error before resuming to use |app|. Read the error message carefully, see what file it points to and fix the permissions on that file.
Can I have the comment metadata show up on my reader? Can I have the comment metadata show up on my reader?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -504,7 +492,7 @@ I want some feature added to |app|. What can I do?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You have two choices: You have two choices:
1. Create a patch by hacking on |app| and send it to me for review and inclusion. See `Development <http://calibre-ebook.com/get-involved>`_. 1. Create a patch by hacking on |app| and send it to me for review and inclusion. See `Development <http://calibre-ebook.com/get-involved>`_.
2. `Open a ticket <http://bugs.calibre-ebook.com/newticket>`_ (you have to register and login first) and hopefully I will find the time to implement your feature. 2. `Open a ticket <http://bugs.calibre-ebook.com/newticket>`_ (you have to register and login first). Remember that |app| development is done by volunteers, so if you get no response to your feature request, it means no one feels like implementing it.
Can I include |app| on a CD to be distributed with my product/magazine? Can I include |app| on a CD to be distributed with my product/magazine?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -522,7 +510,7 @@ Why are there so many calibre-parallel processes on my system?
In addition to this some conversion plugins run tasks in their own pool of processes, so for example if you bulk convert comics, each comic conversion will use three separate processes to render the images. The job manager knows this so it will run only a single comic conversion simultaneously. In addition to this some conversion plugins run tasks in their own pool of processes, so for example if you bulk convert comics, each comic conversion will use three separate processes to render the images. The job manager knows this so it will run only a single comic conversion simultaneously.
And since I'm sure someone will ask: The reason adding/saving books are in separate processes is because of PDF. PDF processing libraries can crash on reading PDFs and I dont want the crash to take down all of calibre. Also when adding EPUB books, in order to extract the cover you have to sometimes render the HTML of the first page, which means that it either has to run the GUI thread of the main process or in a separate process. And since I'm sure someone will ask: The reason adding/saving books are in separate processes is because of PDF. PDF processing libraries can crash on reading PDFs and I dont want the crash to take down all of calibre. Also when adding EPUB books, in order to extract the cover you have to sometimes render the HTML of the first page, which means that it either has to run in the GUI thread of the main process or in a separate process.
Finally, the reason calibre keep workers alive and idle instead of launching on demand is to workaround the slow startup time of python processes. Finally, the reason calibre keep workers alive and idle instead of launching on demand is to workaround the slow startup time of python processes.

View File

@ -77,7 +77,7 @@ class EchoTarget:
new_tag = '~' new_tag = '~'
newline = '' newline = ''
elif tag == 'span': elif tag == 'span':
new_tag = '%' new_tag = ''
newline = '' newline = ''
elif tag == 'a': elif tag == 'a':
self.block = True self.block = True
@ -147,7 +147,7 @@ class EchoTarget:
elif tag == 'sub': elif tag == 'sub':
self.final_output.append('~') self.final_output.append('~')
elif tag == 'span': elif tag == 'span':
self.final_output.append('%') self.final_output.append('')
elif tag == 'a': elif tag == 'a':
if self.a_part['title']: if self.a_part['title']:
textilized = ' "%s (%s)":%s ' % ( textilized = ' "%s (%s)":%s ' % (