mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
merge from trunk
This commit is contained in:
commit
052b0044e2
@ -48,7 +48,7 @@ class LeMonde(BasicNewsRecipe):
|
|||||||
if alink.string is not None:
|
if alink.string is not None:
|
||||||
tstr = alink.string
|
tstr = alink.string
|
||||||
alink.replaceWith(tstr)
|
alink.replaceWith(tstr)
|
||||||
return soup
|
return self.adeify_images(soup)
|
||||||
|
|
||||||
preprocess_regexps = [
|
preprocess_regexps = [
|
||||||
(re.compile(r'([0-9])%'), lambda m: m.group(1) + ' %'),
|
(re.compile(r'([0-9])%'), lambda m: m.group(1) + ' %'),
|
||||||
|
@ -118,6 +118,7 @@ sort_columns_at_startup = None
|
|||||||
# timestamp default if not set: dd MMM yyyy
|
# timestamp default if not set: dd MMM yyyy
|
||||||
gui_pubdate_display_format = 'MMM yyyy'
|
gui_pubdate_display_format = 'MMM yyyy'
|
||||||
gui_timestamp_display_format = 'dd MMM yyyy'
|
gui_timestamp_display_format = 'dd MMM yyyy'
|
||||||
|
gui_last_modified_display_format = 'dd MMM yyyy'
|
||||||
|
|
||||||
#: Control sorting of titles and series in the library display
|
#: Control sorting of titles and series in the library display
|
||||||
# Control title and series sorting in the library view. If set to
|
# Control title and series sorting in the library view. If set to
|
||||||
|
@ -69,7 +69,24 @@ nmake -f ms\ntdll.mak install
|
|||||||
Qt
|
Qt
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Extract Qt sourcecode to C:\Qt\4.x.x. Run configure and make::
|
Extract Qt sourcecode to C:\Qt\4.x.x.
|
||||||
|
|
||||||
|
Qt uses its own routine to locate and load "system libraries" including the openssl libraries needed for "Get Books". This means that we have to apply the following patch to have Qt load the openssl libraries bundled with calibre:
|
||||||
|
|
||||||
|
|
||||||
|
--- src/corelib/plugin/qsystemlibrary.cpp 2011-02-22 05:04:00.000000000 -0700
|
||||||
|
+++ src/corelib/plugin/qsystemlibrary.cpp 2011-04-25 20:53:13.635247466 -0600
|
||||||
|
@@ -110,7 +110,7 @@ HINSTANCE QSystemLibrary::load(const wch
|
||||||
|
|
||||||
|
#if !defined(QT_BOOTSTRAPPED)
|
||||||
|
if (!onlySystemDirectory)
|
||||||
|
- searchOrder << QFileInfo(qAppFileName()).path();
|
||||||
|
+ searchOrder << (QFileInfo(qAppFileName()).path().replace(QLatin1Char('/'), QLatin1Char('\\')) + QString::fromLatin1("\\DLLs\\"));
|
||||||
|
#endif
|
||||||
|
searchOrder << qSystemDirectory();
|
||||||
|
|
||||||
|
|
||||||
|
Now, run configure and make::
|
||||||
|
|
||||||
configure -opensource -release -qt-zlib -qt-gif -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license -nomake examples -nomake demos -nomake docs -openssl -I Q:\openssl\include -L Q:\openssl\lib && nmake
|
configure -opensource -release -qt-zlib -qt-gif -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license -nomake examples -nomake demos -nomake docs -openssl -I Q:\openssl\include -L Q:\openssl\lib && nmake
|
||||||
|
|
||||||
|
@ -11,7 +11,10 @@
|
|||||||
SummaryCodepage='1252' />
|
SummaryCodepage='1252' />
|
||||||
|
|
||||||
<Media Id="1" Cabinet="{app}.cab" CompressionLevel="{compression}" EmbedCab="yes" />
|
<Media Id="1" Cabinet="{app}.cab" CompressionLevel="{compression}" EmbedCab="yes" />
|
||||||
|
<!-- The following line is needed because of the patch to QtCore4.dll. You can remove this line
|
||||||
|
after you update Qt beyond 4.7.2. 'emus' means re-install even if version is the same not just if it is older. -->
|
||||||
|
<Property Id='REINSTALLMODE' Value='emus'/>
|
||||||
|
|
||||||
<Upgrade Id="{upgrade_code}">
|
<Upgrade Id="{upgrade_code}">
|
||||||
<UpgradeVersion Maximum="{version}"
|
<UpgradeVersion Maximum="{version}"
|
||||||
IncludeMaximum="yes"
|
IncludeMaximum="yes"
|
||||||
|
@ -347,9 +347,10 @@ class UploadUserManual(Command): # {{{
|
|||||||
with NamedTemporaryFile(suffix='.zip') as f:
|
with NamedTemporaryFile(suffix='.zip') as f:
|
||||||
os.fchmod(f.fileno(),
|
os.fchmod(f.fileno(),
|
||||||
stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH|stat.S_IWRITE)
|
stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH|stat.S_IWRITE)
|
||||||
with CurrentDir(self.d(path)):
|
with CurrentDir(path):
|
||||||
with ZipFile(f, 'w') as zf:
|
with ZipFile(f, 'w') as zf:
|
||||||
for x in os.listdir('.'):
|
for x in os.listdir('.'):
|
||||||
|
if x.endswith('.swp'): continue
|
||||||
zf.write(x)
|
zf.write(x)
|
||||||
if os.path.isdir(x):
|
if os.path.isdir(x):
|
||||||
for y in os.listdir(x):
|
for y in os.listdir(x):
|
||||||
|
@ -388,7 +388,11 @@ class CurrentDir(object):
|
|||||||
return self.cwd
|
return self.cwd
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
os.chdir(self.cwd)
|
try:
|
||||||
|
os.chdir(self.cwd)
|
||||||
|
except:
|
||||||
|
# The previous CWD no longer exists
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StreamReadWrapper(object):
|
class StreamReadWrapper(object):
|
||||||
|
@ -460,7 +460,7 @@ class ITUNES(DriverBase):
|
|||||||
|
|
||||||
cached_books[this_book.path] = {
|
cached_books[this_book.path] = {
|
||||||
'title':book.Name,
|
'title':book.Name,
|
||||||
'author':book.artist().split(' & '),
|
'author':book.Artist.split(' & '),
|
||||||
'lib_book':library_books[this_book.path] if this_book.path in library_books else None,
|
'lib_book':library_books[this_book.path] if this_book.path in library_books else None,
|
||||||
'uuid': book.Composer,
|
'uuid': book.Composer,
|
||||||
'format': 'pdf' if book.KindAsString.startswith('PDF') else 'epub'
|
'format': 'pdf' if book.KindAsString.startswith('PDF') else 'epub'
|
||||||
|
@ -402,7 +402,7 @@ class HTMLPreProcessor(object):
|
|||||||
(re.compile(r'((?<=</a>)\s*file:/{2,4}[A-Z].*<br>|file:////?[A-Z].*<br>(?=\s*<hr>))', re.IGNORECASE), lambda match: ''),
|
(re.compile(r'((?<=</a>)\s*file:/{2,4}[A-Z].*<br>|file:////?[A-Z].*<br>(?=\s*<hr>))', re.IGNORECASE), lambda match: ''),
|
||||||
|
|
||||||
# Center separator lines
|
# Center separator lines
|
||||||
(re.compile(u'<br>\s*(?P<break>([*#•✦=]+\s*)+)\s*<br>'), lambda match: '<p>\n<p style="text-align:center">' + match.group(1) + '</p>'),
|
(re.compile(u'<br>\s*(?P<break>([*#•✦=] *){3,})\s*<br>'), lambda match: '<p>\n<p style="text-align:center">' + match.group('break') + '</p>'),
|
||||||
|
|
||||||
# Remove page links
|
# Remove page links
|
||||||
(re.compile(r'<a name=\d+></a>', re.IGNORECASE), lambda match: ''),
|
(re.compile(r'<a name=\d+></a>', re.IGNORECASE), lambda match: ''),
|
||||||
|
@ -120,7 +120,11 @@ class Metadata(object):
|
|||||||
_('TEMPLATE ERROR'),
|
_('TEMPLATE ERROR'),
|
||||||
self).strip()
|
self).strip()
|
||||||
return val
|
return val
|
||||||
|
if field.startswith('#') and field.endswith('_index'):
|
||||||
|
try:
|
||||||
|
return self.get_extra(field[:-6])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
'Metadata object has no attribute named: '+ repr(field))
|
'Metadata object has no attribute named: '+ repr(field))
|
||||||
|
|
||||||
@ -170,11 +174,6 @@ class Metadata(object):
|
|||||||
try:
|
try:
|
||||||
return self.__getattribute__(field)
|
return self.__getattribute__(field)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
if field.startswith('#') and field.endswith('_index'):
|
|
||||||
try:
|
|
||||||
return self.get_extra(field[:-6])
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def get_extra(self, field, default=None):
|
def get_extra(self, field, default=None):
|
||||||
@ -631,7 +630,7 @@ class Metadata(object):
|
|||||||
res = format_date(res, fmeta['display'].get('date_format','dd MMM yyyy'))
|
res = format_date(res, fmeta['display'].get('date_format','dd MMM yyyy'))
|
||||||
elif datatype == 'rating':
|
elif datatype == 'rating':
|
||||||
res = res/2.0
|
res = res/2.0
|
||||||
elif key in ('book_size', 'size'):
|
elif key == 'size':
|
||||||
res = human_readable(res)
|
res = human_readable(res)
|
||||||
return (name, unicode(res), orig_res, fmeta)
|
return (name, unicode(res), orig_res, fmeta)
|
||||||
|
|
||||||
|
@ -400,7 +400,8 @@ class MetadataUpdater(object):
|
|||||||
if getattr(self, 'exth', None) is None:
|
if getattr(self, 'exth', None) is None:
|
||||||
raise MobiError('No existing EXTH record. Cannot update metadata.')
|
raise MobiError('No existing EXTH record. Cannot update metadata.')
|
||||||
|
|
||||||
self.record0[92:96] = iana2mobi(mi.language)
|
if not mi.is_null('language'):
|
||||||
|
self.record0[92:96] = iana2mobi(mi.language)
|
||||||
self.create_exth(exth=exth, new_title=mi.title)
|
self.create_exth(exth=exth, new_title=mi.title)
|
||||||
|
|
||||||
# Fetch updated timestamp, cover_record, thumbnail_record
|
# Fetch updated timestamp, cover_record, thumbnail_record
|
||||||
|
@ -301,7 +301,7 @@ class Amazon(Source):
|
|||||||
if asin is None:
|
if asin is None:
|
||||||
asin = identifiers.get('asin', None)
|
asin = identifiers.get('asin', None)
|
||||||
if asin:
|
if asin:
|
||||||
return 'http://amzn.com/%s'%asin
|
return ('amazon', asin, 'http://amzn.com/%s'%asin)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def create_query(self, log, title=None, authors=None, identifiers={}): # {{{
|
def create_query(self, log, title=None, authors=None, identifiers={}): # {{{
|
||||||
|
@ -56,7 +56,8 @@ class InternalMetadataCompareKeyGen(object):
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
Generate a sort key for comparison of the relevance of Metadata objects,
|
Generate a sort key for comparison of the relevance of Metadata objects,
|
||||||
given a search query.
|
given a search query. This is used only to compare results from the same
|
||||||
|
metadata source, not across different sources.
|
||||||
|
|
||||||
The sort key ensures that an ascending order sort is a sort by order of
|
The sort key ensures that an ascending order sort is a sort by order of
|
||||||
decreasing relevance.
|
decreasing relevance.
|
||||||
@ -374,7 +375,11 @@ class Source(Plugin):
|
|||||||
|
|
||||||
def get_book_url(self, identifiers):
|
def get_book_url(self, identifiers):
|
||||||
'''
|
'''
|
||||||
Return the URL for the book identified by identifiers at this source.
|
Return a 3-tuple or None. The 3-tuple is of the form:
|
||||||
|
(identifier_type, identifier_value, URL).
|
||||||
|
The URL is the URL for the book identified by identifiers at this
|
||||||
|
source. identifier_type, identifier_value specify the identifier
|
||||||
|
corresponding to the URL.
|
||||||
This URL must be browseable to by a human using a browser. It is meant
|
This URL must be browseable to by a human using a browser. It is meant
|
||||||
to provide a clickable link for the user to easily visit the books page
|
to provide a clickable link for the user to easily visit the books page
|
||||||
at this source.
|
at this source.
|
||||||
|
@ -173,7 +173,7 @@ class GoogleBooks(Source):
|
|||||||
def get_book_url(self, identifiers): # {{{
|
def get_book_url(self, identifiers): # {{{
|
||||||
goog = identifiers.get('google', None)
|
goog = identifiers.get('google', None)
|
||||||
if goog is not None:
|
if goog is not None:
|
||||||
return 'http://books.google.com/books?id=%s'%goog
|
return ('google', goog, 'http://books.google.com/books?id=%s'%goog)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def create_query(self, log, title=None, authors=None, identifiers={}): # {{{
|
def create_query(self, log, title=None, authors=None, identifiers={}): # {{{
|
||||||
|
@ -435,18 +435,30 @@ def identify(log, abort, # {{{
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def urls_from_identifiers(identifiers): # {{{
|
def urls_from_identifiers(identifiers): # {{{
|
||||||
|
identifiers = dict([(k.lower(), v) for k, v in identifiers.iteritems()])
|
||||||
ans = []
|
ans = []
|
||||||
for plugin in all_metadata_plugins():
|
for plugin in all_metadata_plugins():
|
||||||
try:
|
try:
|
||||||
url = plugin.get_book_url(identifiers)
|
id_type, id_val, url = plugin.get_book_url(identifiers)
|
||||||
if url is not None:
|
ans.append((plugin.name, id_type, id_val, url))
|
||||||
ans.append((plugin.name, url))
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
isbn = identifiers.get('isbn', None)
|
isbn = identifiers.get('isbn', None)
|
||||||
if isbn:
|
if isbn:
|
||||||
ans.append((isbn,
|
ans.append((isbn, 'isbn', isbn,
|
||||||
'http://www.worldcat.org/search?q=bn%%3A%s&qt=advanced'%isbn))
|
'http://www.worldcat.org/isbn/'+isbn))
|
||||||
|
doi = identifiers.get('doi', None)
|
||||||
|
if doi:
|
||||||
|
ans.append(('DOI', 'doi', doi,
|
||||||
|
'http://dx.doi.org/'+doi))
|
||||||
|
arxiv = identifiers.get('arxiv', None)
|
||||||
|
if arxiv:
|
||||||
|
ans.append(('arXiv', 'arxiv', arxiv,
|
||||||
|
'http://arxiv.org/abs/'+arxiv))
|
||||||
|
oclc = identifiers.get('oclc', None)
|
||||||
|
if oclc:
|
||||||
|
ans.append(('OCLC', 'oclc', oclc,
|
||||||
|
'http://www.worldcat.org/oclc/'+oclc))
|
||||||
return ans
|
return ans
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ class OverDrive(Source):
|
|||||||
creators = creators.split(', ')
|
creators = creators.split(', ')
|
||||||
|
|
||||||
# if an exact match in a preferred format occurs
|
# if an exact match in a preferred format occurs
|
||||||
if ((author and creators[0] == author[0]) or (not author and not creators)) and od_title.lower() == title.lower() and int(formatid) in [1, 50, 410, 900] and thumbimage:
|
if ((author and creators and creators[0] == author[0]) or (not author and not creators)) and od_title.lower() == title.lower() and int(formatid) in [1, 50, 410, 900] and thumbimage:
|
||||||
return self.format_results(reserveid, od_title, subtitle, series, publisher,
|
return self.format_results(reserveid, od_title, subtitle, series, publisher,
|
||||||
creators, thumbimage, worldcatlink, formatid)
|
creators, thumbimage, worldcatlink, formatid)
|
||||||
else:
|
else:
|
||||||
@ -298,7 +298,7 @@ class OverDrive(Source):
|
|||||||
close_matches.insert(0, self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid))
|
close_matches.insert(0, self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid))
|
||||||
else:
|
else:
|
||||||
close_matches.append(self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid))
|
close_matches.append(self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid))
|
||||||
|
|
||||||
elif close_title_match and close_author_match and int(formatid) in [1, 50, 410, 900]:
|
elif close_title_match and close_author_match and int(formatid) in [1, 50, 410, 900]:
|
||||||
close_matches.append(self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid))
|
close_matches.append(self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid))
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ class SaveWorker(Thread):
|
|||||||
if isbytestring(fpath):
|
if isbytestring(fpath):
|
||||||
fpath = fpath.decode(filesystem_encoding)
|
fpath = fpath.decode(filesystem_encoding)
|
||||||
formats[fmt.lower()] = fpath
|
formats[fmt.lower()] = fpath
|
||||||
data[i] = [opf, cpath, formats]
|
data[i] = [opf, cpath, formats, mi.last_modified.isoformat()]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -16,6 +16,7 @@ from calibre import CurrentDir
|
|||||||
from calibre.ebooks.pdb.formatreader import FormatReader
|
from calibre.ebooks.pdb.formatreader import FormatReader
|
||||||
from calibre.ptempfile import TemporaryFile
|
from calibre.ptempfile import TemporaryFile
|
||||||
from calibre.utils.magick import Image, create_canvas
|
from calibre.utils.magick import Image, create_canvas
|
||||||
|
from calibre.ebooks.compression.palmdoc import decompress_doc
|
||||||
|
|
||||||
DATATYPE_PHTML = 0
|
DATATYPE_PHTML = 0
|
||||||
DATATYPE_PHTML_COMPRESSED = 1
|
DATATYPE_PHTML_COMPRESSED = 1
|
||||||
|
@ -739,12 +739,6 @@ def build_forms(srcdir, info=None):
|
|||||||
dat = dat.replace('from QtWebKit.QWebView import QWebView',
|
dat = dat.replace('from QtWebKit.QWebView import QWebView',
|
||||||
'from PyQt4 import QtWebKit\nfrom PyQt4.QtWebKit import QWebView')
|
'from PyQt4 import QtWebKit\nfrom PyQt4.QtWebKit import QWebView')
|
||||||
|
|
||||||
if form.endswith('viewer%smain.ui'%os.sep):
|
|
||||||
info('\t\tPromoting WebView')
|
|
||||||
dat = dat.replace('self.view = QtWebKit.QWebView(', 'self.view = DocumentView(')
|
|
||||||
dat = dat.replace('self.view = QWebView(', 'self.view = DocumentView(')
|
|
||||||
dat += '\n\nfrom calibre.gui2.viewer.documentview import DocumentView'
|
|
||||||
|
|
||||||
open(compiled_form, 'wb').write(dat)
|
open(compiled_form, 'wb').write(dat)
|
||||||
|
|
||||||
_df = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
_df = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
||||||
|
@ -17,13 +17,13 @@ from calibre.gui2.dnd import (dnd_has_image, dnd_get_image, dnd_get_files,
|
|||||||
from calibre.ebooks import BOOK_EXTENSIONS
|
from calibre.ebooks import BOOK_EXTENSIONS
|
||||||
from calibre.ebooks.metadata.book.base import (field_metadata, Metadata)
|
from calibre.ebooks.metadata.book.base import (field_metadata, Metadata)
|
||||||
from calibre.ebooks.metadata import fmt_sidx
|
from calibre.ebooks.metadata import fmt_sidx
|
||||||
|
from calibre.ebooks.metadata.sources.identify import urls_from_identifiers
|
||||||
from calibre.constants import filesystem_encoding
|
from calibre.constants import filesystem_encoding
|
||||||
from calibre.library.comments import comments_to_html
|
from calibre.library.comments import comments_to_html
|
||||||
from calibre.gui2 import (config, open_local_file, open_url, pixmap_to_data,
|
from calibre.gui2 import (config, open_local_file, open_url, pixmap_to_data,
|
||||||
gprefs)
|
gprefs)
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
|
|
||||||
def render_html(mi, css, vertical, widget, all_fields=False): # {{{
|
def render_html(mi, css, vertical, widget, all_fields=False): # {{{
|
||||||
table = render_data(mi, all_fields=all_fields,
|
table = render_data(mi, all_fields=all_fields,
|
||||||
use_roman_numbers=config['use_roman_numerals_for_series_number'])
|
use_roman_numbers=config['use_roman_numerals_for_series_number'])
|
||||||
@ -114,17 +114,20 @@ def render_data(mi, use_roman_numbers=True, all_fields=False):
|
|||||||
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
|
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
|
||||||
u', '.join(fmts))))
|
u', '.join(fmts))))
|
||||||
elif field == 'identifiers':
|
elif field == 'identifiers':
|
||||||
pass # TODO
|
urls = urls_from_identifiers(mi.identifiers)
|
||||||
|
links = [u'<a href="%s" title="%s:%s">%s</a>' % (url, id_typ, id_val, name)
|
||||||
|
for name, id_typ, id_val, url in urls]
|
||||||
|
links = u', '.join(links)
|
||||||
|
if links:
|
||||||
|
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(
|
||||||
|
_('Ids')+':', links)))
|
||||||
else:
|
else:
|
||||||
val = mi.format_field(field)[-1]
|
val = mi.format_field(field)[-1]
|
||||||
if val is None:
|
if val is None:
|
||||||
continue
|
continue
|
||||||
val = prepare_string_for_xml(val)
|
val = prepare_string_for_xml(val)
|
||||||
if metadata['datatype'] == 'series':
|
if metadata['datatype'] == 'series':
|
||||||
if metadata['is_custom']:
|
sidx = mi.get(field+'_index')
|
||||||
sidx = mi.get_extra(field)
|
|
||||||
else:
|
|
||||||
sidx = getattr(mi, field+'_index')
|
|
||||||
if sidx is None:
|
if sidx is None:
|
||||||
sidx = 1.0
|
sidx = 1.0
|
||||||
val = _('Book %s of <span class="series_name">%s</span>')%(fmt_sidx(sidx,
|
val = _('Book %s of <span class="series_name">%s</span>')%(fmt_sidx(sidx,
|
||||||
@ -292,6 +295,8 @@ class BookInfo(QWebView):
|
|||||||
|
|
||||||
def link_activated(self, link):
|
def link_activated(self, link):
|
||||||
self._link_clicked = True
|
self._link_clicked = True
|
||||||
|
if unicode(link.scheme()) in ('http', 'https'):
|
||||||
|
return open_url(link)
|
||||||
link = unicode(link.toString())
|
link = unicode(link.toString())
|
||||||
self.link_clicked.emit(link)
|
self.link_clicked.emit(link)
|
||||||
|
|
||||||
|
@ -22,6 +22,12 @@
|
|||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="pixmap">
|
<property name="pixmap">
|
||||||
<pixmap resource="../../../../resources/images.qrc">:/images/dialog_warning.png</pixmap>
|
<pixmap resource="../../../../resources/images.qrc">:/images/dialog_warning.png</pixmap>
|
||||||
</property>
|
</property>
|
||||||
@ -46,6 +52,10 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Library</string>
|
<string>Library</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/library.png</normaloff>:/images/library.png</iconset>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -53,6 +63,10 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Device</string>
|
<string>Device</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/reader.png</normaloff>:/images/reader.png</iconset>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -60,6 +74,10 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Library and Device</string>
|
<string>Library and Device</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/trash.png</normaloff>:/images/trash.png</iconset>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -214,7 +214,6 @@ class SearchBar(QWidget): # {{{
|
|||||||
x.setIcon(QIcon(I("search_add_saved.png")))
|
x.setIcon(QIcon(I("search_add_saved.png")))
|
||||||
x.setObjectName("save_search_button")
|
x.setObjectName("save_search_button")
|
||||||
l.addWidget(x)
|
l.addWidget(x)
|
||||||
x.setToolTip(_("Save current search under the name shown in the box"))
|
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -97,18 +97,25 @@ class RatingDelegate(QStyledItemDelegate): # {{{
|
|||||||
|
|
||||||
class DateDelegate(QStyledItemDelegate): # {{{
|
class DateDelegate(QStyledItemDelegate): # {{{
|
||||||
|
|
||||||
|
def __init__(self, parent, tweak_name='gui_timestamp_display_format',
|
||||||
|
default_format='dd MMM yyyy', editor_format='dd MMM yyyy'):
|
||||||
|
QStyledItemDelegate.__init__(self, parent)
|
||||||
|
self.tweak_name = tweak_name
|
||||||
|
self.default_format = default_format
|
||||||
|
self.editor_format = editor_format
|
||||||
|
|
||||||
def displayText(self, val, locale):
|
def displayText(self, val, locale):
|
||||||
d = val.toDate()
|
d = val.toDate()
|
||||||
if d <= UNDEFINED_QDATE:
|
if d <= UNDEFINED_QDATE:
|
||||||
return ''
|
return ''
|
||||||
format = tweaks['gui_timestamp_display_format']
|
format = tweaks[self.tweak_name]
|
||||||
if format is None:
|
if format is None:
|
||||||
format = 'dd MMM yyyy'
|
format = self.default_format
|
||||||
return format_date(d.toPyDate(), format)
|
return format_date(d.toPyDate(), format)
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
qde = QStyledItemDelegate.createEditor(self, parent, option, index)
|
qde = QStyledItemDelegate.createEditor(self, parent, option, index)
|
||||||
qde.setDisplayFormat('dd MMM yyyy')
|
qde.setDisplayFormat(self.editor_format)
|
||||||
qde.setMinimumDate(UNDEFINED_QDATE)
|
qde.setMinimumDate(UNDEFINED_QDATE)
|
||||||
qde.setSpecialValueText(_('Undefined'))
|
qde.setSpecialValueText(_('Undefined'))
|
||||||
qde.setCalendarPopup(True)
|
qde.setCalendarPopup(True)
|
||||||
|
@ -70,6 +70,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
'publisher' : _("Publisher"),
|
'publisher' : _("Publisher"),
|
||||||
'tags' : _("Tags"),
|
'tags' : _("Tags"),
|
||||||
'series' : _("Series"),
|
'series' : _("Series"),
|
||||||
|
'last_modified' : _('Modified'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, parent=None, buffer=40):
|
def __init__(self, parent=None, buffer=40):
|
||||||
@ -620,6 +621,8 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
idx=self.db.field_metadata['timestamp']['rec_index']),
|
idx=self.db.field_metadata['timestamp']['rec_index']),
|
||||||
'pubdate' : functools.partial(datetime_type,
|
'pubdate' : functools.partial(datetime_type,
|
||||||
idx=self.db.field_metadata['pubdate']['rec_index']),
|
idx=self.db.field_metadata['pubdate']['rec_index']),
|
||||||
|
'last_modified': functools.partial(datetime_type,
|
||||||
|
idx=self.db.field_metadata['last_modified']['rec_index']),
|
||||||
'rating' : functools.partial(rating_type,
|
'rating' : functools.partial(rating_type,
|
||||||
idx=self.db.field_metadata['rating']['rec_index']),
|
idx=self.db.field_metadata['rating']['rec_index']),
|
||||||
'publisher': functools.partial(text_type,
|
'publisher': functools.partial(text_type,
|
||||||
|
@ -76,6 +76,8 @@ class BooksView(QTableView): # {{{
|
|||||||
self.rating_delegate = RatingDelegate(self)
|
self.rating_delegate = RatingDelegate(self)
|
||||||
self.timestamp_delegate = DateDelegate(self)
|
self.timestamp_delegate = DateDelegate(self)
|
||||||
self.pubdate_delegate = PubDateDelegate(self)
|
self.pubdate_delegate = PubDateDelegate(self)
|
||||||
|
self.last_modified_delegate = DateDelegate(self,
|
||||||
|
tweak_name='gui_last_modified_display_format')
|
||||||
self.tags_delegate = CompleteDelegate(self, ',', 'all_tags')
|
self.tags_delegate = CompleteDelegate(self, ',', 'all_tags')
|
||||||
self.authors_delegate = CompleteDelegate(self, '&', 'all_author_names', True)
|
self.authors_delegate = CompleteDelegate(self, '&', 'all_author_names', True)
|
||||||
self.cc_names_delegate = CompleteDelegate(self, '&', 'all_custom', True)
|
self.cc_names_delegate = CompleteDelegate(self, '&', 'all_custom', True)
|
||||||
@ -296,6 +298,7 @@ class BooksView(QTableView): # {{{
|
|||||||
state = {}
|
state = {}
|
||||||
state['hidden_columns'] = [cm[i] for i in range(h.count())
|
state['hidden_columns'] = [cm[i] for i in range(h.count())
|
||||||
if h.isSectionHidden(i) and cm[i] != 'ondevice']
|
if h.isSectionHidden(i) and cm[i] != 'ondevice']
|
||||||
|
state['last_modified_injected'] = True
|
||||||
state['sort_history'] = \
|
state['sort_history'] = \
|
||||||
self.cleanup_sort_history(self.model().sort_history)
|
self.cleanup_sort_history(self.model().sort_history)
|
||||||
state['column_positions'] = {}
|
state['column_positions'] = {}
|
||||||
@ -380,7 +383,7 @@ class BooksView(QTableView): # {{{
|
|||||||
|
|
||||||
def get_default_state(self):
|
def get_default_state(self):
|
||||||
old_state = {
|
old_state = {
|
||||||
'hidden_columns': [],
|
'hidden_columns': ['last_modified'],
|
||||||
'sort_history':[DEFAULT_SORT],
|
'sort_history':[DEFAULT_SORT],
|
||||||
'column_positions': {},
|
'column_positions': {},
|
||||||
'column_sizes': {},
|
'column_sizes': {},
|
||||||
@ -388,6 +391,7 @@ class BooksView(QTableView): # {{{
|
|||||||
'size':'center',
|
'size':'center',
|
||||||
'timestamp':'center',
|
'timestamp':'center',
|
||||||
'pubdate':'center'},
|
'pubdate':'center'},
|
||||||
|
'last_modified_injected': True,
|
||||||
}
|
}
|
||||||
h = self.column_header
|
h = self.column_header
|
||||||
cm = self.column_map
|
cm = self.column_map
|
||||||
@ -398,7 +402,7 @@ class BooksView(QTableView): # {{{
|
|||||||
old_state['column_sizes'][name] = \
|
old_state['column_sizes'][name] = \
|
||||||
min(350, max(self.sizeHintForColumn(i),
|
min(350, max(self.sizeHintForColumn(i),
|
||||||
h.sectionSizeHint(i)))
|
h.sectionSizeHint(i)))
|
||||||
if name == 'timestamp':
|
if name in ('timestamp', 'last_modified'):
|
||||||
old_state['column_sizes'][name] += 12
|
old_state['column_sizes'][name] += 12
|
||||||
return old_state
|
return old_state
|
||||||
|
|
||||||
@ -418,6 +422,13 @@ class BooksView(QTableView): # {{{
|
|||||||
pass
|
pass
|
||||||
if ans is not None:
|
if ans is not None:
|
||||||
db.prefs[name] = ans
|
db.prefs[name] = ans
|
||||||
|
else:
|
||||||
|
if not ans.get('last_modified_injected', False):
|
||||||
|
ans['last_modified_injected'] = True
|
||||||
|
hc = ans.get('hidden_columns', [])
|
||||||
|
if 'last_modified' not in hc:
|
||||||
|
hc.append('last_modified')
|
||||||
|
db.prefs[name] = ans
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
@ -459,7 +470,8 @@ class BooksView(QTableView): # {{{
|
|||||||
def database_changed(self, db):
|
def database_changed(self, db):
|
||||||
for i in range(self.model().columnCount(None)):
|
for i in range(self.model().columnCount(None)):
|
||||||
if self.itemDelegateForColumn(i) in (self.rating_delegate,
|
if self.itemDelegateForColumn(i) in (self.rating_delegate,
|
||||||
self.timestamp_delegate, self.pubdate_delegate):
|
self.timestamp_delegate, self.pubdate_delegate,
|
||||||
|
self.last_modified_delegate):
|
||||||
self.setItemDelegateForColumn(i, self.itemDelegate())
|
self.setItemDelegateForColumn(i, self.itemDelegate())
|
||||||
|
|
||||||
cm = self.column_map
|
cm = self.column_map
|
||||||
|
@ -18,11 +18,11 @@ from calibre.gui2.widgets import EnLineEdit, FormatList, ImageView
|
|||||||
from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox
|
from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.icu import sort_key
|
||||||
from calibre.utils.config import tweaks, prefs
|
from calibre.utils.config import tweaks, prefs
|
||||||
from calibre.ebooks.metadata import title_sort, authors_to_string, \
|
from calibre.ebooks.metadata import (title_sort, authors_to_string,
|
||||||
string_to_authors, check_isbn
|
string_to_authors, check_isbn)
|
||||||
from calibre.ebooks.metadata.meta import get_metadata
|
from calibre.ebooks.metadata.meta import get_metadata
|
||||||
from calibre.gui2 import file_icon_provider, UNDEFINED_QDATE, UNDEFINED_DATE, \
|
from calibre.gui2 import (file_icon_provider, UNDEFINED_QDATE, UNDEFINED_DATE,
|
||||||
choose_files, error_dialog, choose_images, question_dialog
|
choose_files, error_dialog, choose_images, question_dialog)
|
||||||
from calibre.utils.date import local_tz, qt_to_dt
|
from calibre.utils.date import local_tz, qt_to_dt
|
||||||
from calibre import strftime
|
from calibre import strftime
|
||||||
from calibre.ebooks import BOOK_EXTENSIONS
|
from calibre.ebooks import BOOK_EXTENSIONS
|
||||||
@ -280,11 +280,16 @@ class AuthorSortEdit(EnLineEdit):
|
|||||||
aus = self.current_val
|
aus = self.current_val
|
||||||
meth = tweaks['author_sort_copy_method']
|
meth = tweaks['author_sort_copy_method']
|
||||||
if aus:
|
if aus:
|
||||||
ln, _, rest = aus.partition(',')
|
ans = []
|
||||||
if rest:
|
for one in [a.strip() for a in aus.split('&')]:
|
||||||
if meth in ('invert', 'nocomma', 'comma'):
|
if not one:
|
||||||
aus = rest.strip() + ' ' + ln.strip()
|
continue
|
||||||
self.authors_edit.current_val = [aus]
|
ln, _, rest = one.partition(',')
|
||||||
|
if rest:
|
||||||
|
if meth in ('invert', 'nocomma', 'comma'):
|
||||||
|
one = rest.strip() + ' ' + ln.strip()
|
||||||
|
ans.append(one)
|
||||||
|
self.authors_edit.current_val = ans
|
||||||
|
|
||||||
def auto_generate(self, *args):
|
def auto_generate(self, *args):
|
||||||
au = unicode(self.authors_edit.text())
|
au = unicode(self.authors_edit.text())
|
||||||
@ -805,6 +810,7 @@ class CommentsEdit(Editor): # {{{
|
|||||||
else:
|
else:
|
||||||
val = comments_to_html(val)
|
val = comments_to_html(val)
|
||||||
self.html = val
|
self.html = val
|
||||||
|
self.wyswyg_dirtied()
|
||||||
return property(fget=fget, fset=fset)
|
return property(fget=fget, fset=fset)
|
||||||
|
|
||||||
def initialize(self, db, id_):
|
def initialize(self, db, id_):
|
||||||
@ -936,7 +942,11 @@ class IdentifiersEdit(QLineEdit): # {{{
|
|||||||
ans = {}
|
ans = {}
|
||||||
for x in parts:
|
for x in parts:
|
||||||
c = x.split(':')
|
c = x.split(':')
|
||||||
if len(c) == 2:
|
if len(c) > 1:
|
||||||
|
if c[0] == 'isbn':
|
||||||
|
v = check_isbn(c[1])
|
||||||
|
if v is not None:
|
||||||
|
c[1] = v
|
||||||
ans[c[0]] = c[1]
|
ans[c[0]] = c[1]
|
||||||
return ans
|
return ans
|
||||||
def fset(self, val):
|
def fset(self, val):
|
||||||
@ -947,6 +957,11 @@ class IdentifiersEdit(QLineEdit): # {{{
|
|||||||
if x == 'isbn':
|
if x == 'isbn':
|
||||||
x = '00isbn'
|
x = '00isbn'
|
||||||
return x
|
return x
|
||||||
|
for k in list(val):
|
||||||
|
if k == 'isbn':
|
||||||
|
v = check_isbn(k)
|
||||||
|
if v is not None:
|
||||||
|
val[k] = v
|
||||||
ids = sorted(val.iteritems(), key=keygen)
|
ids = sorted(val.iteritems(), key=keygen)
|
||||||
txt = ', '.join(['%s:%s'%(k, v) for k, v in ids])
|
txt = ', '.join(['%s:%s'%(k, v) for k, v in ids])
|
||||||
self.setText(txt.strip())
|
self.setText(txt.strip())
|
||||||
@ -954,8 +969,8 @@ class IdentifiersEdit(QLineEdit): # {{{
|
|||||||
return property(fget=fget, fset=fset)
|
return property(fget=fget, fset=fset)
|
||||||
|
|
||||||
def initialize(self, db, id_):
|
def initialize(self, db, id_):
|
||||||
self.current_val = db.get_identifiers(id_, index_is_id=True)
|
self.original_val = db.get_identifiers(id_, index_is_id=True)
|
||||||
self.original_val = self.current_val
|
self.current_val = self.original_val
|
||||||
|
|
||||||
def commit(self, db, id_):
|
def commit(self, db, id_):
|
||||||
if self.original_val != self.current_val:
|
if self.original_val != self.current_val:
|
||||||
|
@ -41,8 +41,11 @@ class FieldsModel(FM): # {{{
|
|||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
val = [k for k, v in self.overrides.iteritems() if v == Qt.Unchecked]
|
ignored_fields = set([x for x in self.prefs['ignore_fields'] if x not in
|
||||||
self.prefs['ignore_fields'] = val
|
self.overrides])
|
||||||
|
changed = set([k for k, v in self.overrides.iteritems() if v ==
|
||||||
|
Qt.Unchecked])
|
||||||
|
self.prefs['ignore_fields'] = list(ignored_fields.union(changed))
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ class ResultsView(QTableView): # {{{
|
|||||||
parts.append('</center>')
|
parts.append('</center>')
|
||||||
if book.identifiers:
|
if book.identifiers:
|
||||||
urls = urls_from_identifiers(book.identifiers)
|
urls = urls_from_identifiers(book.identifiers)
|
||||||
ids = ['<a href="%s">%s</a>'%(url, name) for name, url in urls]
|
ids = ['<a href="%s">%s</a>'%(url, name) for name, ign, ign, url in urls]
|
||||||
if ids:
|
if ids:
|
||||||
parts.append('<div><b>%s:</b> %s</div><br>'%(_('See at'), ', '.join(ids)))
|
parts.append('<div><b>%s:</b> %s</div><br>'%(_('See at'), ', '.join(ids)))
|
||||||
if book.tags:
|
if book.tags:
|
||||||
|
@ -63,7 +63,7 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
|
|||||||
self.shortcuts.linkActivated.connect(self.shortcut_activated)
|
self.shortcuts.linkActivated.connect(self.shortcut_activated)
|
||||||
text = '<p>'+_('Quick create:')
|
text = '<p>'+_('Quick create:')
|
||||||
for col, name in [('isbn', _('ISBN')), ('formats', _('Formats')),
|
for col, name in [('isbn', _('ISBN')), ('formats', _('Formats')),
|
||||||
('last_modified', _('Modified Date')), ('yesno', _('Yes/No')),
|
('yesno', _('Yes/No')),
|
||||||
('tags', _('Tags')), ('series', _('Series')), ('rating',
|
('tags', _('Tags')), ('series', _('Series')), ('rating',
|
||||||
_('Rating')), ('people', _("People's names"))]:
|
_('Rating')), ('people', _("People's names"))]:
|
||||||
text += ' <a href="col:%s">%s</a>,'%(col, name)
|
text += ' <a href="col:%s">%s</a>,'%(col, name)
|
||||||
@ -150,7 +150,6 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
|
|||||||
'tags': _('My Tags'),
|
'tags': _('My Tags'),
|
||||||
'series': _('My Series'),
|
'series': _('My Series'),
|
||||||
'rating': _('My Rating'),
|
'rating': _('My Rating'),
|
||||||
'last_modified':_('Modified Date'),
|
|
||||||
'people': _('People')}[which])
|
'people': _('People')}[which])
|
||||||
self.is_names.setChecked(which == 'people')
|
self.is_names.setChecked(which == 'people')
|
||||||
if self.composite_box.isVisible():
|
if self.composite_box.isVisible():
|
||||||
@ -158,9 +157,8 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
|
|||||||
{
|
{
|
||||||
'isbn': '{identifiers:select(isbn)}',
|
'isbn': '{identifiers:select(isbn)}',
|
||||||
'formats': '{formats}',
|
'formats': '{formats}',
|
||||||
'last_modified':'''{last_modified:'format_date($, "dd MMM yyyy")'}'''
|
|
||||||
}[which])
|
}[which])
|
||||||
self.composite_sort_by.setCurrentIndex(2 if which == 'last_modified' else 0)
|
self.composite_sort_by.setCurrentIndex(0)
|
||||||
|
|
||||||
def datatype_changed(self, *args):
|
def datatype_changed(self, *args):
|
||||||
try:
|
try:
|
||||||
|
@ -235,6 +235,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
gui.library_view.refresh_book_details()
|
gui.library_view.refresh_book_details()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = QApplication([])
|
from calibre.gui2 import Application
|
||||||
|
app = Application([])
|
||||||
test_widget('Interface', 'Look & Feel')
|
test_widget('Interface', 'Look & Feel')
|
||||||
|
|
||||||
|
@ -7,28 +7,27 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>717</width>
|
<width>717</width>
|
||||||
<height>444</height>
|
<height>390</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="0" column="0">
|
||||||
<widget class="QToolBox" name="toolBox">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<widget class="QWidget" name="page">
|
<property name="currentIndex">
|
||||||
<property name="geometry">
|
<number>0</number>
|
||||||
<rect>
|
</property>
|
||||||
<x>0</x>
|
<widget class="QWidget" name="tab">
|
||||||
<y>0</y>
|
<attribute name="icon">
|
||||||
<width>699</width>
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
<height>306</height>
|
<normaloff>:/images/lt.png</normaloff>:/images/lt.png</iconset>
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<attribute name="label">
|
|
||||||
<string>Main interface</string>
|
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
<attribute name="title">
|
||||||
|
<string>Main Interface</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_9">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_17">
|
<widget class="QLabel" name="label_17">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -75,6 +74,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_systray_icon">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable system &tray icon (needs restart)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QCheckBox" name="opt_disable_animations">
|
<widget class="QCheckBox" name="opt_disable_animations">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
@ -85,6 +91,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_disable_tray_notification">
|
||||||
|
<property name="text">
|
||||||
|
<string>Disable &notifications in system tray</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QCheckBox" name="opt_show_splash_screen">
|
<widget class="QCheckBox" name="opt_show_splash_screen">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -97,12 +110,12 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&Toolbar</string>
|
<string>&Toolbar</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout_8">
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="opt_toolbar_icon_size"/>
|
<widget class="QComboBox" name="opt_toolbar_icon_size"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Icon size:</string>
|
<string>&Icon size:</string>
|
||||||
</property>
|
</property>
|
||||||
@ -115,7 +128,7 @@
|
|||||||
<widget class="QComboBox" name="opt_toolbar_text"/>
|
<widget class="QComboBox" name="opt_toolbar_text"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_8">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show &text under icons:</string>
|
<string>Show &text under icons:</string>
|
||||||
</property>
|
</property>
|
||||||
@ -127,20 +140,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="4" column="0">
|
||||||
<spacer name="verticalSpacer_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="0">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
@ -161,135 +161,15 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QPushButton" name="change_font_button">
|
<widget class="QPushButton" name="change_font_button">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Change &font (needs restart)</string>
|
<string>Change &font (needs restart)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="6" column="0">
|
||||||
<widget class="QCheckBox" name="opt_systray_icon">
|
<spacer name="verticalSpacer_3">
|
||||||
<property name="text">
|
|
||||||
<string>Enable system &tray icon (needs restart)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QCheckBox" name="opt_disable_tray_notification">
|
|
||||||
<property name="text">
|
|
||||||
<string>Disable &notifications in system tray</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="page_2">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>649</width>
|
|
||||||
<height>96</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<attribute name="label">
|
|
||||||
<string>Tag Browser</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_5">
|
|
||||||
<item row="0" column="0" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="opt_show_avg_rating">
|
|
||||||
<property name="text">
|
|
||||||
<string>Show &average ratings in the tags browser</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0" colspan="2">
|
|
||||||
<layout class="QHBoxLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>Tags browser category &partitioning method:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>opt_tags_browser_partition_method</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="opt_tags_browser_partition_method">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Choose how tag browser subcategories are displayed when
|
|
||||||
there are more items than the limit. Select by first
|
|
||||||
letter to see an A, B, C list. Choose partitioned to
|
|
||||||
have a list of fixed-sized groups. Set to disabled
|
|
||||||
if you never want subcategories</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>&Collapse when more items than:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>opt_tags_browser_collapse_at</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QSpinBox" name="opt_tags_browser_collapse_at">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>If a Tag Browser category has more than this number of items, it is divided
|
|
||||||
up into sub-categories. If the partition method is set to disable, this value is ignored.</string>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>10000</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>5</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="label_81">
|
|
||||||
<property name="text">
|
|
||||||
<string>Categories with &hierarchical items:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>opt_categories_using_hierarchy</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="MultiCompleteLineEdit" name="opt_categories_using_hierarchy">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>A comma-separated list of columns in which items containing
|
|
||||||
periods are displayed in the tag browser trees. For example, if
|
|
||||||
this box contains 'tags' then tags of the form 'Mystery.English'
|
|
||||||
and 'Mystery.Thriller' will be displayed with English and Thriller
|
|
||||||
both under 'Mystery'. If 'tags' is not in this box,
|
|
||||||
then the tags will be displayed each on their own line.</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0" colspan="2">
|
|
||||||
<spacer name="verticalSpacer_2">
|
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
@ -303,77 +183,15 @@ then the tags will be displayed each on their own line.</string>
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="page_3">
|
<widget class="QWidget" name="tab_4">
|
||||||
<property name="geometry">
|
<attribute name="icon">
|
||||||
<rect>
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
<x>0</x>
|
<normaloff>:/images/book.png</normaloff>:/images/book.png</iconset>
|
||||||
<y>0</y>
|
|
||||||
<width>429</width>
|
|
||||||
<height>63</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<attribute name="label">
|
|
||||||
<string>Cover Browser</string>
|
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QGridLayout" name="gridLayout_6">
|
<attribute name="title">
|
||||||
<item row="0" column="0" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="opt_separate_cover_flow">
|
|
||||||
<property name="text">
|
|
||||||
<string>Show cover &browser in a separate window (needs restart)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>&Number of covers to show in browse mode (needs restart):</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>opt_cover_flow_queue_length</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QSpinBox" name="opt_cover_flow_queue_length"/>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0" colspan="2">
|
|
||||||
<spacer name="verticalSpacer_4">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="page_4">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>699</width>
|
|
||||||
<height>306</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<attribute name="label">
|
|
||||||
<string>Book Details</string>
|
<string>Book Details</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QGridLayout" name="gridLayout_7">
|
<layout class="QGridLayout" name="gridLayout_12">
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QCheckBox" name="opt_use_roman_numerals_for_series_number">
|
|
||||||
<property name="text">
|
|
||||||
<string>Use &Roman numerals for series</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" rowspan="2">
|
<item row="0" column="0" rowspan="2">
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -425,6 +243,16 @@ then the tags will be displayed each on their own line.</string>
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QCheckBox" name="opt_use_roman_numerals_for_series_number">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use &Roman numerals for series</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -437,6 +265,148 @@ then the tags will be displayed each on their own line.</string>
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/tags.png</normaloff>:/images/tags.png</iconset>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Tag Browser</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_10">
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Tags browser category &partitioning method:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_tags_browser_partition_method</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QComboBox" name="opt_tags_browser_partition_method">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Choose how tag browser subcategories are displayed when
|
||||||
|
there are more items than the limit. Select by first
|
||||||
|
letter to see an A, B, C list. Choose partitioned to
|
||||||
|
have a list of fixed-sized groups. Set to disabled
|
||||||
|
if you never want subcategories</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Collapse when more items than:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_tags_browser_collapse_at</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="4">
|
||||||
|
<widget class="QSpinBox" name="opt_tags_browser_collapse_at">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>If a Tag Browser category has more than this number of items, it is divided
|
||||||
|
up into sub-categories. If the partition method is set to disable, this value is ignored.</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="5">
|
||||||
|
<widget class="QCheckBox" name="opt_show_avg_rating">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show &average ratings in the tags browser</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_81">
|
||||||
|
<property name="text">
|
||||||
|
<string>Categories with &hierarchical items:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_categories_using_hierarchy</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="5">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>690</width>
|
||||||
|
<height>252</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2" colspan="3">
|
||||||
|
<widget class="MultiCompleteLineEdit" name="opt_categories_using_hierarchy">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>A comma-separated list of columns in which items containing
|
||||||
|
periods are displayed in the tag browser trees. For example, if
|
||||||
|
this box contains 'tags' then tags of the form 'Mystery.English'
|
||||||
|
and 'Mystery.Thriller' will be displayed with English and Thriller
|
||||||
|
both under 'Mystery'. If 'tags' is not in this box,
|
||||||
|
then the tags will be displayed each on their own line.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_3">
|
||||||
|
<attribute name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/cover_flow.png</normaloff>:/images/cover_flow.png</iconset>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Cover Browser</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_11">
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_separate_cover_flow">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show cover &browser in a separate window (needs restart)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Number of covers to show in browse mode (needs restart):</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_cover_flow_queue_length</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QSpinBox" name="opt_cover_flow_queue_length"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<spacer name="verticalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>690</width>
|
||||||
|
<height>283</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -89,7 +89,7 @@ class Category(QWidget): # {{{
|
|||||||
self.bar = QToolBar(self)
|
self.bar = QToolBar(self)
|
||||||
self.bar.setStyleSheet(
|
self.bar.setStyleSheet(
|
||||||
'QToolBar { border: none; background: none }')
|
'QToolBar { border: none; background: none }')
|
||||||
self.bar.setIconSize(QSize(48, 48))
|
self.bar.setIconSize(QSize(32, 32))
|
||||||
self.bar.setMovable(False)
|
self.bar.setMovable(False)
|
||||||
self.bar.setFloatable(False)
|
self.bar.setFloatable(False)
|
||||||
self.bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
self.bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||||
|
@ -209,8 +209,11 @@ class FieldsModel(QAbstractListModel): # {{{
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
val = [k for k, v in self.overrides.iteritems() if v == Qt.Unchecked]
|
ignored_fields = set([x for x in msprefs['ignore_fields'] if x not in
|
||||||
msprefs['ignore_fields'] = val
|
self.overrides])
|
||||||
|
changed = set([k for k, v in self.overrides.iteritems() if v ==
|
||||||
|
Qt.Unchecked])
|
||||||
|
msprefs['ignore_fields'] = list(ignored_fields.union(changed))
|
||||||
|
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
@ -7,12 +7,15 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
|
||||||
from PyQt4.Qt import QComboBox, Qt, QLineEdit, QStringList, pyqtSlot, QDialog, \
|
from PyQt4.Qt import QComboBox, Qt, QLineEdit, QStringList, pyqtSlot, QDialog, \
|
||||||
pyqtSignal, QCompleter, QAction, QKeySequence, QTimer, \
|
pyqtSignal, QCompleter, QAction, QKeySequence, QTimer, \
|
||||||
QString, QIcon
|
QString, QIcon, QMenu
|
||||||
|
|
||||||
from calibre.gui2 import config
|
from calibre.gui2 import config, error_dialog
|
||||||
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
from calibre.gui2.dialogs.saved_search_editor import SavedSearchEditor
|
from calibre.gui2.dialogs.saved_search_editor import SavedSearchEditor
|
||||||
from calibre.gui2.dialogs.search import SearchDialog
|
from calibre.gui2.dialogs.search import SearchDialog
|
||||||
from calibre.utils.search_query_parser import saved_searches
|
from calibre.utils.search_query_parser import saved_searches
|
||||||
@ -330,6 +333,24 @@ class SavedSearchBox(QComboBox): # {{{
|
|||||||
self.saved_search_selected (name)
|
self.saved_search_selected (name)
|
||||||
self.changed.emit()
|
self.changed.emit()
|
||||||
|
|
||||||
|
def delete_current_search(self):
|
||||||
|
idx = self.currentIndex()
|
||||||
|
if idx <= 0:
|
||||||
|
error_dialog(self, _('Delete current search'),
|
||||||
|
_('No search is selected'), show=True)
|
||||||
|
return
|
||||||
|
if not confirm('<p>'+_('The selected search will be '
|
||||||
|
'<b>permanently deleted</b>. Are you sure?')
|
||||||
|
+'</p>', 'saved_search_delete', self):
|
||||||
|
return
|
||||||
|
ss = saved_searches().lookup(unicode(self.currentText()))
|
||||||
|
if ss is None:
|
||||||
|
return
|
||||||
|
saved_searches().delete(unicode(self.currentText()))
|
||||||
|
self.clear()
|
||||||
|
self.search_box.clear()
|
||||||
|
self.changed.emit()
|
||||||
|
|
||||||
# SIGNALed from the main UI
|
# SIGNALed from the main UI
|
||||||
def copy_search_button_clicked (self):
|
def copy_search_button_clicked (self):
|
||||||
idx = self.currentIndex();
|
idx = self.currentIndex();
|
||||||
@ -428,6 +449,22 @@ class SavedSearchBoxMixin(object): # {{{
|
|||||||
for x in ('copy', 'save'):
|
for x in ('copy', 'save'):
|
||||||
b = getattr(self, x+'_search_button')
|
b = getattr(self, x+'_search_button')
|
||||||
b.setStatusTip(b.toolTip())
|
b.setStatusTip(b.toolTip())
|
||||||
|
self.save_search_button.setToolTip('<p>' +
|
||||||
|
_("Save current search under the name shown in the box. "
|
||||||
|
"Press and hold for a pop-up options menu.") + '</p>')
|
||||||
|
self.save_search_button.setMenu(QMenu())
|
||||||
|
self.save_search_button.menu().addAction(
|
||||||
|
QIcon(I('plus.png')),
|
||||||
|
_('Create saved search'),
|
||||||
|
self.saved_search.save_search_button_clicked)
|
||||||
|
self.save_search_button.menu().addAction(
|
||||||
|
QIcon(I('trash.png')),
|
||||||
|
_('Delete saved search'),
|
||||||
|
self.saved_search.delete_current_search)
|
||||||
|
self.save_search_button.menu().addAction(
|
||||||
|
QIcon(I('search.png')),
|
||||||
|
_('Manage saved searches'),
|
||||||
|
partial(self.do_saved_search_edit, None))
|
||||||
|
|
||||||
def saved_searches_changed(self, set_restriction=None, recount=True):
|
def saved_searches_changed(self, set_restriction=None, recount=True):
|
||||||
p = sorted(saved_searches().names(), key=sort_key)
|
p = sorted(saved_searches().names(), key=sort_key)
|
||||||
|
@ -33,24 +33,21 @@
|
|||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="1" column="1">
|
||||||
<widget class="QWebView" name="view"/>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QScrollBar" name="vertical_scrollbar">
|
<widget class="QScrollBar" name="vertical_scrollbar">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QScrollBar" name="horizontal_scrollbar">
|
<widget class="QScrollBar" name="horizontal_scrollbar">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="3" column="0" colspan="2">
|
||||||
<widget class="QFrame" name="dictionary_box">
|
<widget class="QFrame" name="dictionary_box">
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
<enum>QFrame::StyledPanel</enum>
|
<enum>QFrame::StyledPanel</enum>
|
||||||
@ -91,6 +88,9 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="DocumentView" name="view" native="true"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
@ -108,7 +108,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="toolBarArea">
|
<attribute name="toolBarArea">
|
||||||
<enum>Qt::LeftToolBarArea</enum>
|
<enum>LeftToolBarArea</enum>
|
||||||
</attribute>
|
</attribute>
|
||||||
<attribute name="toolBarBreak">
|
<attribute name="toolBarBreak">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
@ -136,7 +136,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<widget class="QToolBar" name="tool_bar2">
|
<widget class="QToolBar" name="tool_bar2">
|
||||||
<attribute name="toolBarArea">
|
<attribute name="toolBarArea">
|
||||||
<enum>Qt::TopToolBarArea</enum>
|
<enum>TopToolBarArea</enum>
|
||||||
</attribute>
|
</attribute>
|
||||||
<attribute name="toolBarBreak">
|
<attribute name="toolBarBreak">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
@ -316,6 +316,12 @@
|
|||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
<header>QtWebKit/QWebView</header>
|
<header>QtWebKit/QWebView</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>DocumentView</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>calibre/gui2/viewer/documentview.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../resources/images.qrc"/>
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
@ -406,11 +406,9 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
if val_func is None:
|
if val_func is None:
|
||||||
loc = self.field_metadata[location]['rec_index']
|
loc = self.field_metadata[location]['rec_index']
|
||||||
val_func = lambda item, loc=loc: item[loc]
|
val_func = lambda item, loc=loc: item[loc]
|
||||||
dt = self.field_metadata[location]['datatype']
|
|
||||||
|
|
||||||
q = ''
|
q = ''
|
||||||
val_func = lambda item, loc=loc: item[loc]
|
|
||||||
cast = adjust = lambda x: x
|
cast = adjust = lambda x: x
|
||||||
|
dt = self.field_metadata[location]['datatype']
|
||||||
|
|
||||||
if query == 'false':
|
if query == 'false':
|
||||||
if dt == 'rating' or location == 'cover':
|
if dt == 'rating' or location == 'cover':
|
||||||
|
@ -368,7 +368,8 @@ class FieldMetadata(dict):
|
|||||||
'date_format': tweaks['gui_timestamp_display_format']}
|
'date_format': tweaks['gui_timestamp_display_format']}
|
||||||
self._tb_cats['pubdate']['display'] = {
|
self._tb_cats['pubdate']['display'] = {
|
||||||
'date_format': tweaks['gui_pubdate_display_format']}
|
'date_format': tweaks['gui_pubdate_display_format']}
|
||||||
self._tb_cats['last_modified']['display'] = {'date_format': 'iso'}
|
self._tb_cats['last_modified']['display'] = {
|
||||||
|
'date_format': tweaks['gui_last_modified_display_format']}
|
||||||
self.custom_field_prefix = '#'
|
self.custom_field_prefix = '#'
|
||||||
self.get = self._tb_cats.get
|
self.get = self._tb_cats.get
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ from calibre.ebooks.metadata.opf2 import metadata_to_opf
|
|||||||
from calibre.constants import preferred_encoding
|
from calibre.constants import preferred_encoding
|
||||||
from calibre.ebooks.metadata import fmt_sidx
|
from calibre.ebooks.metadata import fmt_sidx
|
||||||
from calibre.ebooks.metadata import title_sort
|
from calibre.ebooks.metadata import title_sort
|
||||||
|
from calibre.utils.date import parse_date
|
||||||
from calibre import strftime, prints, sanitize_file_name_unicode
|
from calibre import strftime, prints, sanitize_file_name_unicode
|
||||||
|
|
||||||
plugboard_any_device_value = 'any device'
|
plugboard_any_device_value = 'any device'
|
||||||
@ -42,6 +43,8 @@ FORMAT_ARG_DESCS = dict(
|
|||||||
publisher=_('The publisher'),
|
publisher=_('The publisher'),
|
||||||
timestamp=_('The date'),
|
timestamp=_('The date'),
|
||||||
pubdate=_('The published date'),
|
pubdate=_('The published date'),
|
||||||
|
last_modified=_('The date when the metadata for this book record'
|
||||||
|
' was last modified'),
|
||||||
id=_('The calibre internal id')
|
id=_('The calibre internal id')
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -191,6 +194,9 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250,
|
|||||||
format_args['timestamp'] = strftime(timefmt, mi.timestamp.timetuple())
|
format_args['timestamp'] = strftime(timefmt, mi.timestamp.timetuple())
|
||||||
if hasattr(mi.pubdate, 'timetuple'):
|
if hasattr(mi.pubdate, 'timetuple'):
|
||||||
format_args['pubdate'] = strftime(timefmt, mi.pubdate.timetuple())
|
format_args['pubdate'] = strftime(timefmt, mi.pubdate.timetuple())
|
||||||
|
if hasattr(mi, 'last_modified') and hasattr(mi.last_modified, 'timetuple'):
|
||||||
|
format_args['last_modified'] = strftime(timefmt, mi.last_modified.timetuple())
|
||||||
|
|
||||||
format_args['id'] = str(id)
|
format_args['id'] = str(id)
|
||||||
# Now format the custom fields
|
# Now format the custom fields
|
||||||
custom_metadata = mi.get_all_user_metadata(make_copy=False)
|
custom_metadata = mi.get_all_user_metadata(make_copy=False)
|
||||||
@ -373,10 +379,14 @@ def save_serialized_to_disk(ids, data, plugboards, root, opts, callback):
|
|||||||
root, opts, length = _sanitize_args(root, opts)
|
root, opts, length = _sanitize_args(root, opts)
|
||||||
failures = []
|
failures = []
|
||||||
for x in ids:
|
for x in ids:
|
||||||
opf, cover, format_map = data[x]
|
opf, cover, format_map, last_modified = data[x]
|
||||||
if isinstance(opf, unicode):
|
if isinstance(opf, unicode):
|
||||||
opf = opf.encode('utf-8')
|
opf = opf.encode('utf-8')
|
||||||
mi = OPF(cStringIO.StringIO(opf)).to_book_metadata()
|
mi = OPF(cStringIO.StringIO(opf)).to_book_metadata()
|
||||||
|
try:
|
||||||
|
mi.last_modified = parse_date(last_modified)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
tb = ''
|
tb = ''
|
||||||
try:
|
try:
|
||||||
failed, id, title = do_save_book_to_disk(x, mi, cover, plugboards,
|
failed, id, title = do_save_book_to_disk(x, mi, cover, plugboards,
|
||||||
|
@ -20,13 +20,14 @@ What formats does |app| support conversion to/from?
|
|||||||
|app| supports the conversion of many input formats to many output formats.
|
|app| supports the conversion of many input formats to many output formats.
|
||||||
It can convert every input format in the following list, to every output format.
|
It can convert every input format in the following list, to every output format.
|
||||||
|
|
||||||
*Input Formats:* CBZ, CBR, CBC, CHM, EPUB, FB2, HTML, HTMLZ, LIT, LRF, MOBI, ODT, PDF, PRC**, PDB***, PML, RB, RTF, SNB, TCR, TXT, TXTZ
|
*Input Formats:* CBZ, CBR, CBC, CHM, EPUB, FB2, HTML, HTMLZ, LIT, LRF, MOBI, ODT, PDF, PRC, PDB, PML, RB, RTF, SNB, TCR, TXT, TXTZ
|
||||||
|
|
||||||
*Output Formats:* EPUB, FB2, OEB, LIT, LRF, MOBI, HTMLZ, PDB, PML, RB, PDF, SNB, TCR, TXT, TXTZ
|
*Output Formats:* EPUB, FB2, OEB, LIT, LRF, MOBI, HTMLZ, PDB, PML, RB, PDF, SNB, TCR, TXT, TXTZ
|
||||||
|
|
||||||
** PRC is a generic format, |app| supports PRC files with TextRead and MOBIBook headers
|
.. note ::
|
||||||
|
|
||||||
*** PDB is also a generic format. |app| supports eReder, Plucker, PML and zTxt PDB files.
|
PRC is a generic format, |app| supports PRC files with TextRead and MOBIBook headers.
|
||||||
|
PDB is also a generic format. |app| supports eReder, Plucker, PML and zTxt PDB files.
|
||||||
|
|
||||||
.. _best-source-formats:
|
.. _best-source-formats:
|
||||||
|
|
||||||
|
@ -365,6 +365,8 @@ Dates and numeric fields support the relational operators ``=`` (equals), ``>``
|
|||||||
Rating fields are considered to be numeric. For example, the search ``rating:>=3`` will find all books rated 3
|
Rating fields are considered to be numeric. For example, the search ``rating:>=3`` will find all books rated 3
|
||||||
or higher.
|
or higher.
|
||||||
|
|
||||||
|
You can search for the number of items in multiple-valued fields such as tags). These searches begin with the character ``#``, then use the same syntax as numeric fields. For example, to find all books with more than 4 tags, use ``tags:#>4``. To find all books with exactly 10 tags, use ``tags:#=10``.
|
||||||
|
|
||||||
Series indices are searchable. For the standard series, the search name is 'series_index'. For
|
Series indices are searchable. For the standard series, the search name is 'series_index'. For
|
||||||
custom series columns, use the column search name followed by _index. For example, to search the indices for a
|
custom series columns, use the column search name followed by _index. For example, to search the indices for a
|
||||||
custom series column named ``#my_series``, you would use the search name ``#my_series_index``.
|
custom series column named ``#my_series``, you would use the search name ``#my_series_index``.
|
||||||
|
@ -65,17 +65,14 @@ Catalog plugins
|
|||||||
Metadata download plugins
|
Metadata download plugins
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
.. module:: calibre.ebooks.metadata.fetch
|
.. module:: calibre.ebooks.metadata.sources.base
|
||||||
|
|
||||||
.. autoclass:: MetadataSource
|
.. autoclass:: Source
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
:members:
|
:members:
|
||||||
:member-order: bysource
|
:member-order: bysource
|
||||||
|
|
||||||
.. autoclass:: calibre.ebooks.metadata.covers.CoverDownload
|
.. autoclass:: InternalMetadataCompareKeyGen
|
||||||
:show-inheritance:
|
|
||||||
:members:
|
|
||||||
:member-order: bysource
|
|
||||||
|
|
||||||
Conversion plugins
|
Conversion plugins
|
||||||
--------------------
|
--------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user