This commit is contained in:
GRiker 2012-07-14 03:42:14 -06:00
commit 50659f3287
18 changed files with 119 additions and 65 deletions

View File

@ -24,7 +24,7 @@
new features:
- title: "When searching, allow use of un-accented characters to match accented characters in all fields and all languages (not just authors and English as before)"
description: "The rules for matching un-accented characters are done in a language dependent way. So if your calibre interface language is set to English, n will match both n and ñ, but if it is set to Spanish, it will match only n, as in Spanish ñ is a separate alphabet in Spanish."
description: "The rules for matching un-accented characters are done in a language dependent way. So if your calibre interface language is set to English, n will match both n and ñ, but if it is set to Spanish, it will match only n, as in Spanish ñ is a separate alphabet in Spanish. This makes searching a little slower, so if you have a very large library you can turn it off via Preferences->Searching."
type: major
- title: "Content server: Show a best guess for the IP address the content server is currently listening at in the connect/share menu."

View File

@ -30,6 +30,7 @@ Environment variables
* ``CALIBRE_OVERRIDE_DATABASE_PATH`` - allows you to specify the full path to metadata.db. Using this variable you can have metadata.db be in a location other than the library folder. Useful if your library folder is on a networked drive that does not support file locking.
* ``CALIBRE_DEVELOP_FROM`` - Used to run from a calibre development environment. See :ref:`develop`.
* ``CALIBRE_OVERRIDE_LANG`` - Used to force the language used by the interface (ISO 639 language code)
* ``CALIBRE_NO_NATIVE_FILEDIALOGS`` - Causes calibre to not use native file dialogs for selecting files/directories.
* ``SYSFS_PATH`` - Use if sysfs is mounted somewhere other than /sys
* ``http_proxy`` - Used on linux to specify an HTTP proxy

View File

@ -98,15 +98,6 @@ authors_split_regex = r'(?i),?\s+(and|with)\s+'
# categories_use_field_for_author_name = 'author_sort'
categories_use_field_for_author_name = 'author'
#: Completion sort order: choose when to change from lexicographic to ASCII-like
# Calibre normally uses locale-dependent lexicographic ordering when showing
# completion values. This means that the sort order is correct for the user's
# language. However, this can be slow. Performance is improved by switching to
# ascii ordering. This tweak controls when that switch happens. Set it to zero
# to always use ascii ordering. Set it to something larger than zero to switch
# to ascii ordering for performance reasons.
completion_change_to_ascii_sorting = 2500
#: Control partitioning of Tag Browser
# When partitioning the tags browser, the format of the subcategory label is
# controlled by a template: categories_collapsed_name_template if sorting by
@ -522,6 +513,6 @@ default_tweak_format = None
# consideration when partitioning by first letter.
# Examples:
# enable_multicharacters_in_tag_browser = True
# enable_multicharacters_in_tag_browser = True
# enable_multicharacters_in_tag_browser = False
enable_multicharacters_in_tag_browser = True

View File

@ -423,7 +423,7 @@ class KOBO(USBMS):
def delete_books(self, paths, end_session=True):
if self.modify_database_check("delete_books") == False:
return
return
for i, path in enumerate(paths):
self.report_progress((i+1) / float(len(paths)), _('Removing books from device...'))
@ -462,7 +462,7 @@ class KOBO(USBMS):
def remove_books_from_metadata(self, paths, booklists):
if self.modify_datbase_check("remove_books_from_metatata") == False:
return
return
for i, path in enumerate(paths):
self.report_progress((i+1) / float(len(paths)), _('Removing books from device metadata listing...'))
@ -598,7 +598,7 @@ class KOBO(USBMS):
# Checks to see whether the database version is supported
# and whether the user has chosen to support the firmware version
if self.dbversion > self.supported_dbversion:
# Unsupported database
# Unsupported database
opts = self.settings()
if not opts.extra_customization[self.OPT_SUPPORT_NEWER_FIRMWARE]:
debug_print('The database has been upgraded past supported version')
@ -606,11 +606,11 @@ class KOBO(USBMS):
self.report_progress(1.0, _('Removing books from device...'))
from calibre.devices.errors import UserFeedback
raise UserFeedback(_("Kobo database version unsupported - See details"),
_('Your Kobo is running an updated firmware/database version '
_('Your Kobo is running an updated firmware/database version. '
'As Calibre has not been updated, database editing is disabled. '
'You can enable support for your Kobo in plugin preferences. '
'Doing so may require you to perform a factory reset. '
'before selecting the "Attempt to support newer firmware" option '
'Before selecting the "Attempt to support newer firmware" option '
'you should be familiar with restoring your Kobo to factory defaults.'),
UserFeedback.WARN)
@ -741,7 +741,7 @@ class KOBO(USBMS):
def update_device_database_collections(self, booklists, collections_attributes, oncard):
if self.modify_database_check("update_device_database_collections") == False:
return
return
# Only process categories in this list
supportedcategories = {

View File

@ -144,9 +144,9 @@ class EXTHRecord(object):
118 : 'retailprice',
119 : 'retailpricecurrency',
121 : 'KF8 header section index',
125 : 'KF8 resources (images/fonts) count',
129 : 'KF8 cover URI',
131 : 'KF8 unknown count',
125 : 'KF8 unknown count',
129 : 'KF8 thumbnail URI',
131 : 'KF8 resources (images/fonts) count',
201 : 'coveroffset',
202 : 'thumboffset',
203 : 'hasfakecover',
@ -163,6 +163,7 @@ class EXTHRecord(object):
501 : 'cdetype', # 4 chars (PDOC or EBOK)
502 : 'lastupdatetime',
503 : 'updatedtitle',
524 : 'language',
}.get(self.type, repr(self.type))
if (self.name in {'coveroffset', 'thumboffset', 'hasfakecover',

View File

@ -13,6 +13,7 @@ from calibre.utils.date import parse_date
from calibre.ebooks.mobi import MobiError
from calibre.ebooks.metadata import MetaInformation, check_isbn
from calibre.ebooks.mobi.langcodes import main_language, sub_language, mobi2iana
from calibre.utils.localization import canonicalize_lang
NULL_INDEX = 0xffffffff
@ -68,6 +69,14 @@ class EXTHHeader(object): # {{{
title = content.decode(codec)
except:
pass
elif idx == 524: # Lang code
try:
lang = content.decode(codec)
lang = canonicalize_lang(lang)
if lang:
self.mi.language = lang
except:
pass
#else:
# print 'unknown record', idx, repr(content)
if title:
@ -201,10 +210,11 @@ class BookHeader(object):
self.exth = EXTHHeader(raw[16 + self.length:], self.codec,
self.title)
self.exth.mi.uid = self.unique_id
try:
self.exth.mi.language = mobi2iana(langid, sublangid)
except:
self.log.exception('Unknown language code')
if self.exth.mi.is_null('language'):
try:
self.exth.mi.language = mobi2iana(langid, sublangid)
except:
self.log.exception('Unknown language code')
except:
self.log.exception('Invalid EXTH header')
self.exth_flag = 0

View File

@ -297,10 +297,13 @@ class MobiWriter(object):
# 0x70 - 0x73 : EXTH flags
# Bit 6 (0b1000000) being set indicates the presence of an EXTH header
# Bit 12 being set indicates the presence of embedded fonts
# The purpose of the other bits is unknown
exth_flags = 0b1010000
if self.is_periodical:
exth_flags |= 0b1000
if self.resources.has_fonts:
exth_flags |= 0b1000000000000
record0.write(pack(b'>I', exth_flags))
# 0x74 - 0x93 : Unknown
@ -406,7 +409,10 @@ class MobiWriter(object):
# Now change the header fields that need to be different in the MOBI 6
# header
header_fields['first_resource_record'] = first_image_record
header_fields['exth_flags'] = 0b100001010000 # Kinglegen uses this
ef = 0b100001010000 # Kinglegen uses this
if self.resources.has_fonts:
ef |= 0b1000000000000
header_fields['exth_flags'] = ef
header_fields['fdst_record'] = pack(b'>HH', 1, last_content_record)
header_fields['fdst_count'] = 1 # Why not 0? Kindlegen uses 1
header_fields['flis_record'] = flis_number

View File

@ -32,6 +32,7 @@ class Resources(object):
self.used_image_indices = set()
self.image_indices = set()
self.cover_offset = self.thumbnail_offset = None
self.has_fonts = False
self.add_resources(add_fonts)
@ -109,6 +110,7 @@ class Resources(object):
'ttf', 'otf'} and isinstance(item.data, bytes):
self.records.append(write_font_record(item.data))
self.item_map[item.href] = len(self.records)
self.has_fonts = True
def add_extra_images(self):
'''

View File

@ -12,6 +12,7 @@ from struct import pack
from io import BytesIO
from calibre.ebooks.mobi.utils import utf8_text
from calibre.utils.localization import lang_as_iso639_1
EXTH_CODES = {
'creator': 100,
@ -28,13 +29,15 @@ EXTH_CODES = {
'versionnumber': 114,
'startreading': 116,
'kf8_header_index': 121,
'num_of_resources': 125,
'kf8_unknown_count': 131,
'kf8_unknown_count': 125,
'kf8_thumbnail_uri': 129,
'num_of_resources': 131,
'coveroffset': 201,
'thumboffset': 202,
'hasfakecover': 203,
'lastupdatetime': 502,
'title': 503,
'language': 524,
}
COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+')
@ -57,6 +60,16 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
else:
creators = [unicode(c) for c in items]
items = creators
elif term == 'rights':
try:
rights = utf8_text(unicode(metadata.rights[0]))
except:
rights = b'Unknown'
exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
exth.write(rights)
nrecs += 1
continue
for item in items:
data = unicode(item)
if term != 'description':
@ -68,18 +81,14 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
pass
else:
continue
if term == 'language':
d2 = lang_as_iso639_1(data)
if d2:
data = d2
data = utf8_text(data)
exth.write(pack(b'>II', code, len(data) + 8))
exth.write(data)
nrecs += 1
if term == 'rights' :
try:
rights = utf8_text(unicode(metadata.rights[0]))
except:
rights = b'Unknown'
exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
exth.write(rights)
nrecs += 1
# Write UUID as ASIN
uuid = None
@ -132,7 +141,7 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
nrecs += 1
if be_kindlegen2:
vals = {204:201, 205:2, 206:2, 207:35621}
vals = {204:201, 205:2, 206:5, 207:0}
elif is_periodical:
# Pretend to be amazon's super secret periodical generator
vals = {204:201, 205:2, 206:0, 207:101}
@ -151,7 +160,10 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
if thumbnail_offset is not None:
exth.write(pack(b'>III', EXTH_CODES['thumboffset'], 12,
thumbnail_offset))
nrecs += 1
cover_uri_str = bytes('kindle:embed:%04X' %(thumbnail_offset))
exth.write(pack(b'>II', EXTH_CODES['kf8_thumbnail_uri'], len(cover_uri_str) + 8))
exth.write(cover_uri_str)
nrecs += 2
if start_offset is not None:
try:

View File

@ -277,6 +277,8 @@ class KF8Book(object):
self.exth_flags = 0b1010000
if writer.opts.mobi_periodical:
self.exth_flags |= 0b1000
if resources.has_fonts:
self.exth_flags |= 0b1000000000000
self.opts = writer.opts
self.start_offset = writer.start_offset

View File

@ -573,17 +573,24 @@ class FileDialog(QObject):
if not isinstance(initial_dir, basestring):
initial_dir = os.path.expanduser(default_dir)
self.selected_files = []
use_native_dialog = not os.environ.has_key('CALIBRE_NO_NATIVE_FILEDIALOGS')
with SanitizeLibraryPath():
opts = QFileDialog.Option()
if not use_native_dialog:
opts |= QFileDialog.DontUseNativeDialog
if mode == QFileDialog.AnyFile:
f = unicode(QFileDialog.getSaveFileName(parent, title, initial_dir, ftext, ""))
f = unicode(QFileDialog.getSaveFileName(parent, title,
initial_dir, ftext, "", opts))
if f:
self.selected_files.append(f)
elif mode == QFileDialog.ExistingFile:
f = unicode(QFileDialog.getOpenFileName(parent, title, initial_dir, ftext, ""))
f = unicode(QFileDialog.getOpenFileName(parent, title,
initial_dir, ftext, "", opts))
if f and os.path.exists(f):
self.selected_files.append(f)
elif mode == QFileDialog.ExistingFiles:
fs = QFileDialog.getOpenFileNames(parent, title, initial_dir, ftext, "")
fs = QFileDialog.getOpenFileNames(parent, title, initial_dir,
ftext, "", opts)
for f in fs:
f = unicode(f)
if not f: continue
@ -594,7 +601,8 @@ class FileDialog(QObject):
if f and os.path.exists(f):
self.selected_files.append(f)
else:
opts = QFileDialog.ShowDirsOnly if mode == QFileDialog.Directory else QFileDialog.Option()
if mode == QFileDialog.Directory:
opts |= QFileDialog.ShowDirsOnly
f = unicode(QFileDialog.getExistingDirectory(parent, title, initial_dir, opts))
if os.path.exists(f):
self.selected_files.append(f)

View File

@ -16,7 +16,6 @@ from PyQt4.Qt import (QLineEdit, QAbstractListModel, Qt,
from calibre.utils.icu import sort_key
from calibre.gui2 import NONE
from calibre.gui2.widgets import EnComboBox, LineEditECM
from calibre.utils.config_base import tweaks
class CompleteModel(QAbstractListModel):
@ -27,7 +26,7 @@ class CompleteModel(QAbstractListModel):
def set_items(self, items):
items = [unicode(x.strip()) for x in items]
if len(items) < tweaks['completion_change_to_ascii_sorting']:
if len(items) < 2500:
self.items = sorted(items, key=sort_key)
self.sorting = QCompleter.UnsortedModel
else:

View File

@ -284,6 +284,8 @@ class LineEdit(QLineEdit, LineEditECM):
if self.no_popup: return
self.update_completions()
select_first = len(self.mcompleter.model().current_prefix) > 0
if not select_first:
self.mcompleter.setCurrentIndex(QModelIndex())
self.complete(select_first=select_first)
def update_completions(self):
@ -357,9 +359,8 @@ class EditWithComplete(EnComboBox):
def show_initial_value(self, what):
what = unicode(what) if what else u''
le = self.lineEdit()
self.setEditText(what)
le.selectAll()
self.setText(what)
self.lineEdit().selectAll()
@dynamic_property
def all_items(self):
@ -373,6 +374,9 @@ class EditWithComplete(EnComboBox):
def text(self):
return unicode(self.lineEdit().text())
def selectAll(self):
self.lineEdit().selectAll()
def setText(self, val):
le = self.lineEdit()
le.no_popup = True

View File

@ -125,12 +125,15 @@ class TextDelegate(QStyledItemDelegate): # {{{
editor.set_separator(None)
complete_items = [i[1] for i in self.auto_complete_function()]
editor.update_items_cache(complete_items)
ct = index.data(Qt.DisplayRole).toString()
editor.show_initial_value(ct)
else:
editor = EnLineEdit(parent)
return editor
def setEditorData(self, editor, index):
ct = unicode(index.data(Qt.DisplayRole).toString())
editor.setText(ct)
editor.selectAll()
def setModelData(self, editor, model, index):
if isinstance(editor, EditWithComplete):
val = editor.lineEdit().text()
@ -164,12 +167,15 @@ class CompleteDelegate(QStyledItemDelegate): # {{{
all_items = list(self.db.all_custom(
label=self.db.field_metadata.key_to_label(col)))
editor.update_items_cache(all_items)
ct = index.data(Qt.DisplayRole).toString()
editor.show_initial_value(ct)
else:
editor = EnLineEdit(parent)
return editor
def setEditorData(self, editor, index):
ct = unicode(index.data(Qt.DisplayRole).toString())
editor.setText(ct)
editor.selectAll()
def setModelData(self, editor, model, index):
if isinstance(editor, EditWithComplete):
val = editor.lineEdit().text()
@ -183,10 +189,12 @@ class LanguagesDelegate(QStyledItemDelegate): # {{{
def createEditor(self, parent, option, index):
editor = LanguagesEdit(parent=parent)
editor.init_langs(index.model().db)
ct = index.data(Qt.DisplayRole).toString()
editor.show_initial_value(ct)
return editor
def setEditorData(self, editor, index):
ct = unicode(index.data(Qt.DisplayRole).toString())
editor.show_initial_value(ct)
def setModelData(self, editor, model, index):
val = ','.join(editor.lang_codes)
model.setData(index, QVariant(val), Qt.EditRole)
@ -251,6 +259,14 @@ class CcTextDelegate(QStyledItemDelegate): # {{{
editor.update_items_cache(complete_items)
return editor
def setEditorData(self, editor, index):
ct = unicode(index.data(Qt.DisplayRole).toString())
editor.setText(ct)
editor.selectAll()
def setModelData(self, editor, model, index):
val = editor.text()
model.setData(index, QVariant(val), Qt.EditRole)
# }}}
class CcNumberDelegate(QStyledItemDelegate): # {{{

View File

@ -184,7 +184,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.opt_grouped_search_make_user_categories.update_items_cache(terms)
self.gst_names.blockSignals(True)
self.gst_names.clear()
print (1111, self.gst_names)
self.gst_names.addItem('', '')
for t in terms:
self.gst_names.addItem(t, t)

View File

@ -156,12 +156,14 @@ def _match(query, value, matchkind):
elif query == t:
return True
elif matchkind == REGEXP_MATCH:
return re.search(query, t, re.I|re.UNICODE)
if re.search(query, t, re.I|re.UNICODE):
return True
elif matchkind == CONTAINS_MATCH:
if pref_use_primary_find_in_search:
return primary_find(query, t)[0] != -1
else:
return query in t
if primary_find(query, t)[0] != -1:
return True
elif query in t:
return True
except re.error:
pass
return False

View File

@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: calibre 0.8.60\n"
"POT-Creation-Date: 2012-07-13 10:25+IST\n"
"PO-Revision-Date: 2012-07-13 10:25+IST\n"
"POT-Creation-Date: 2012-07-13 16:26+IST\n"
"PO-Revision-Date: 2012-07-13 16:26+IST\n"
"Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n"
@ -1459,7 +1459,7 @@ msgid "Kobo database version unsupported - See details"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:609
msgid "Your Kobo is running an updated firmware/database version As Calibre has not been updated, database editing is disabled. You can enable support for your Kobo in plugin preferences. Doing so may require you to perform a factory reset. before selecting the \"Attempt to support newer firmware\" option you should be familiar with restoring your Kobo to factory defaults."
msgid "Your Kobo is running an updated firmware/database version. As Calibre has not been updated, database editing is disabled. You can enable support for your Kobo in plugin preferences. Doing so may require you to perform a factory reset. Before selecting the \"Attempt to support newer firmware\" option you should be familiar with restoring your Kobo to factory defaults."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:630
@ -16981,7 +16981,8 @@ msgid "Choose columns to be searched when not using prefixes, as for example, wh
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config_base.py:426
msgid "Characters typed in the search box will match their accented versions, based on the language you have chosen for the calibre interface. For example, in English, searching for n will match and n, but if your language is Spanish it will only match n. Note that this is much slower than a simple search on very large libraries."
#, python-format
msgid "Characters typed in the search box will match their accented versions, based on the language you have chosen for the calibre interface. For example, in English, searching for n will match %s and n, but if your language is Spanish it will only match n. Note that this is much slower than a simple search on very large libraries."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:31
@ -18179,5 +18180,5 @@ msgid "Enable multi-character first-letters in the tag browser"
msgstr ""
#: /home/kovid/work/calibre/resources/default_tweaks.py:518
msgid "Some languages have letters that can be represented by multiple characters.\nFor example, Czech has a 'character' \"ch\" that sorts between \"h\" and \"i\".\nIf this tweak is True, then the tag browser will take these characters into\nconsideration when partitioning by first letter.\nExamples:\nenable_multicharacters_in_tag_browser = True\nenable_multicharacters_in_tag_browser = True"
msgid "Some languages have letters that can be represented by multiple characters.\nFor example, Czech has a 'character' \"ch\" that sorts between \"h\" and \"i\".\nIf this tweak is True, then the tag browser will take these characters into\nconsideration when partitioning by first letter.\nExamples:\nenable_multicharacters_in_tag_browser = True\nenable_multicharacters_in_tag_browser = False"
msgstr ""

View File

@ -423,13 +423,13 @@ def _prefs():
'separated by commas. Only takes effect if you set the option '
'to limit search columns above.'))
c.add_opt('use_primary_find_in_search', default=True,
help=_('Characters typed in the search box will match their '
help=_(u'Characters typed in the search box will match their '
'accented versions, based on the language you have chosen '
'for the calibre interface. For example, in '
u' English, searching for n will match ñ and n, but if '
u' English, searching for n will match %s and n, but if '
'your language is Spanish it will only match n. Note that '
'this is much slower than a simple search on very large '
'libraries.'))
'libraries.')%u'\xf1')
c.add_opt('migrated', default=False, help='For Internal use. Don\'t modify.')
return c