mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make the book details panel completely user configurable
This commit is contained in:
parent
4dbd7840d6
commit
978e1f826b
@ -266,26 +266,6 @@ max_content_server_tags_shown=5
|
||||
content_server_will_display = ['*']
|
||||
content_server_wont_display = []
|
||||
|
||||
#: Set custom metadata fields that the book details panel will or will not display.
|
||||
# book_details_will_display is a list of custom fields to be displayed.
|
||||
# book_details_wont_display is a list of custom fields not to be displayed.
|
||||
# wont_display has priority over will_display.
|
||||
# The special value '*' means all custom fields. The value [] means no entries.
|
||||
# Defaults:
|
||||
# book_details_will_display = ['*']
|
||||
# book_details_wont_display = []
|
||||
# Examples:
|
||||
# To display only the custom fields #mytags and #genre:
|
||||
# book_details_will_display = ['#mytags', '#genre']
|
||||
# book_details_wont_display = []
|
||||
# To display all fields except #mycomments:
|
||||
# book_details_will_display = ['*']
|
||||
# book_details_wont_display['#mycomments']
|
||||
# As above, this tweak affects only display of custom fields. The standard
|
||||
# fields are not affected
|
||||
book_details_will_display = ['*']
|
||||
book_details_wont_display = []
|
||||
|
||||
#: Set the maximum number of sort 'levels'
|
||||
# Set the maximum number of sort 'levels' that calibre will use to resort the
|
||||
# library after certain operations such as searches or device insertion. Each
|
||||
|
26
resources/templates/book_details.css
Normal file
26
resources/templates/book_details.css
Normal file
@ -0,0 +1,26 @@
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: blue
|
||||
}
|
||||
.comments {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
text-indent: 0
|
||||
}
|
||||
|
||||
table.fields {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
table.fields td {
|
||||
vertical-align: top
|
||||
}
|
||||
|
||||
table.fields td.title {
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.series_name {
|
||||
font-style: italic
|
||||
}
|
@ -19,6 +19,9 @@ from calibre.utils.date import isoformat, format_date
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.formatter import TemplateFormatter
|
||||
|
||||
def human_readable(size, precision=2):
|
||||
""" Convert a size in bytes into megabytes """
|
||||
return ('%.'+str(precision)+'f'+ 'MB') % ((size/(1024.*1024.)),)
|
||||
|
||||
NULL_VALUES = {
|
||||
'user_metadata': {},
|
||||
@ -551,7 +554,8 @@ class Metadata(object):
|
||||
def format_field_extended(self, key, series_with_index=True):
|
||||
from calibre.ebooks.metadata import authors_to_string
|
||||
'''
|
||||
returns the tuple (field_name, formatted_value)
|
||||
returns the tuple (field_name, formatted_value, original_value,
|
||||
field_metadata)
|
||||
'''
|
||||
|
||||
# Handle custom series index
|
||||
@ -627,6 +631,8 @@ class Metadata(object):
|
||||
res = format_date(res, fmeta['display'].get('date_format','dd MMM yyyy'))
|
||||
elif datatype == 'rating':
|
||||
res = res/2.0
|
||||
elif key in ('book_size', 'size'):
|
||||
res = human_readable(res)
|
||||
return (name, unicode(res), orig_res, fmeta)
|
||||
|
||||
return (None, None, None, None)
|
||||
|
@ -80,6 +80,14 @@ gprefs.defaults['font'] = None
|
||||
gprefs.defaults['tags_browser_partition_method'] = 'first letter'
|
||||
gprefs.defaults['tags_browser_collapse_at'] = 100
|
||||
gprefs.defaults['edit_metadata_single_layout'] = 'default'
|
||||
gprefs.defaults['book_display_fields'] = [
|
||||
('title', False), ('authors', False), ('formats', True),
|
||||
('series', True), ('identifiers', True), ('tags', True),
|
||||
('path', True), ('publisher', False), ('rating', False),
|
||||
('author_sort', False), ('sort', False), ('timestamp', False),
|
||||
('uuid', False), ('comments', True), ('id', False), ('pubdate', False),
|
||||
('last_modified', False), ('size', False),
|
||||
]
|
||||
|
||||
# }}}
|
||||
|
||||
@ -89,7 +97,7 @@ UNDEFINED_QDATE = QDate(UNDEFINED_DATE)
|
||||
ALL_COLUMNS = ['title', 'ondevice', 'authors', 'size', 'timestamp', 'rating', 'publisher',
|
||||
'tags', 'series', 'pubdate']
|
||||
|
||||
def _config():
|
||||
def _config(): # {{{
|
||||
c = Config('gui', 'preferences for the calibre GUI')
|
||||
c.add_opt('send_to_storage_card_by_default', default=False,
|
||||
help=_('Send file to storage card instead of main memory by default'))
|
||||
@ -181,6 +189,8 @@ def _config():
|
||||
return ConfigProxy(c)
|
||||
|
||||
config = _config()
|
||||
# }}}
|
||||
|
||||
# Turn off DeprecationWarnings in windows GUI
|
||||
if iswindows:
|
||||
import warnings
|
||||
|
@ -30,5 +30,5 @@ class ShowBookDetailsAction(InterfaceAction):
|
||||
index = self.gui.library_view.currentIndex()
|
||||
if index.isValid():
|
||||
BookInfo(self.gui, self.gui.library_view, index,
|
||||
self.gui.iactions['View'].view_format_by_id).show()
|
||||
self.gui.book_details.handle_click).show()
|
||||
|
||||
|
@ -5,67 +5,151 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import collections, sys
|
||||
from Queue import Queue
|
||||
|
||||
from PyQt4.Qt import QPixmap, QSize, QWidget, Qt, pyqtSignal, QUrl, \
|
||||
QPropertyAnimation, QEasingCurve, QThread, QApplication, QFontInfo, \
|
||||
QSizePolicy, QPainter, QRect, pyqtProperty, QLayout, QPalette, QMenu
|
||||
from PyQt4.Qt import (QPixmap, QSize, QWidget, Qt, pyqtSignal, QUrl,
|
||||
QPropertyAnimation, QEasingCurve, QApplication, QFontInfo,
|
||||
QSizePolicy, QPainter, QRect, pyqtProperty, QLayout, QPalette, QMenu)
|
||||
from PyQt4.QtWebKit import QWebView
|
||||
|
||||
from calibre import fit_image, prepare_string_for_xml
|
||||
from calibre.gui2.dnd import dnd_has_image, dnd_get_image, dnd_get_files, \
|
||||
IMAGE_EXTENSIONS, dnd_has_extension
|
||||
from calibre import fit_image, force_unicode, prepare_string_for_xml
|
||||
from calibre.gui2.dnd import (dnd_has_image, dnd_get_image, dnd_get_files,
|
||||
IMAGE_EXTENSIONS, dnd_has_extension)
|
||||
from calibre.ebooks import BOOK_EXTENSIONS
|
||||
from calibre.constants import preferred_encoding
|
||||
from calibre.ebooks.metadata.book.base import (field_metadata, Metadata)
|
||||
from calibre.ebooks.metadata import fmt_sidx
|
||||
from calibre.constants import filesystem_encoding
|
||||
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)
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
# render_rows(data) {{{
|
||||
WEIGHTS = collections.defaultdict(lambda : 100)
|
||||
WEIGHTS[_('Path')] = 5
|
||||
WEIGHTS[_('Formats')] = 1
|
||||
WEIGHTS[_('Collections')] = 2
|
||||
WEIGHTS[_('Series')] = 3
|
||||
WEIGHTS[_('Tags')] = 4
|
||||
|
||||
def render_rows(data):
|
||||
keys = data.keys()
|
||||
# First sort by name. The WEIGHTS sort will preserve this sub-order
|
||||
keys.sort(key=sort_key)
|
||||
keys.sort(key=lambda x: WEIGHTS[x])
|
||||
rows = []
|
||||
for key in keys:
|
||||
txt = data[key]
|
||||
if key in ('id', _('Comments')) or not hasattr(txt, 'strip') or not txt.strip() or \
|
||||
txt == 'None':
|
||||
def render_html(mi, css, vertical, widget, all_fields=False): # {{{
|
||||
table = render_data(mi, all_fields=all_fields,
|
||||
use_roman_numbers=config['use_roman_numerals_for_series_number'])
|
||||
|
||||
def color_to_string(col):
|
||||
ans = '#000000'
|
||||
if col.isValid():
|
||||
col = col.toRgb()
|
||||
if col.isValid():
|
||||
ans = unicode(col.name())
|
||||
return ans
|
||||
|
||||
f = QFontInfo(QApplication.font(widget)).pixelSize()
|
||||
c = color_to_string(QApplication.palette().color(QPalette.Normal,
|
||||
QPalette.WindowText))
|
||||
templ = u'''\
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
body, td {background-color: transparent; font-size: %dpx; color: %s }
|
||||
</style>
|
||||
<style type="text/css">
|
||||
%s
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
%%s
|
||||
</body>
|
||||
<html>
|
||||
'''%(f, c, css)
|
||||
comments = u''
|
||||
if mi.comments:
|
||||
comments = comments_to_html(force_unicode(mi.comments))
|
||||
right_pane = u'<div id="comments" class="comments">%s</div>'%comments
|
||||
|
||||
if vertical:
|
||||
ans = templ%(table+right_pane)
|
||||
else:
|
||||
ans = templ%(u'<table><tr><td valign="top" '
|
||||
'style="padding-right:2em; width:40%%">%s</td><td valign="top">%s</td></tr></table>'
|
||||
% (table, right_pane))
|
||||
return ans
|
||||
|
||||
def get_field_list(fm):
|
||||
fieldlist = list(gprefs['book_display_fields'])
|
||||
names = frozenset([x[0] for x in fieldlist])
|
||||
for field in fm.displayable_field_keys():
|
||||
if field not in names:
|
||||
fieldlist.append((field, True))
|
||||
return fieldlist
|
||||
|
||||
def render_data(mi, use_roman_numbers=True, all_fields=False):
|
||||
ans = []
|
||||
isdevice = not hasattr(mi, 'id')
|
||||
fm = getattr(mi, 'field_metadata', field_metadata)
|
||||
|
||||
for field, display in get_field_list(fm):
|
||||
metadata = fm.get(field, None)
|
||||
if all_fields:
|
||||
display = True
|
||||
if (not display or not metadata or mi.is_null(field) or
|
||||
field == 'comments'):
|
||||
continue
|
||||
if isinstance(key, str):
|
||||
key = key.decode(preferred_encoding, 'replace')
|
||||
if isinstance(txt, str):
|
||||
txt = txt.decode(preferred_encoding, 'replace')
|
||||
if key.endswith(u':html'):
|
||||
key = key[:-5]
|
||||
txt = comments_to_html(txt)
|
||||
elif '</font>' not in txt:
|
||||
txt = prepare_string_for_xml(txt)
|
||||
if 'id' in data:
|
||||
if key == _('Path'):
|
||||
txt = u'<a href="path:%s" title="%s">%s</a>'%(data['id'],
|
||||
txt, _('Click to open'))
|
||||
if key == _('Formats') and txt and txt != _('None'):
|
||||
fmts = [x.strip() for x in txt.split(',')]
|
||||
fmts = [u'<a href="format:%s:%s">%s</a>' % (data['id'], x, x) for x
|
||||
in fmts]
|
||||
txt = ', '.join(fmts)
|
||||
name = metadata['name']
|
||||
if not name:
|
||||
name = field
|
||||
name += ':'
|
||||
if metadata['datatype'] == 'comments':
|
||||
val = getattr(mi, field)
|
||||
if val:
|
||||
val = force_unicode(val)
|
||||
ans.append((field,
|
||||
u'<td class="comments" colspan="2">%s</td>'%comments_to_html(val)))
|
||||
elif field == 'path':
|
||||
if mi.path:
|
||||
path = force_unicode(mi.path, filesystem_encoding)
|
||||
scheme = u'devpath' if isdevice else u'path'
|
||||
url = prepare_string_for_xml(path if isdevice else
|
||||
unicode(mi.id), True)
|
||||
link = u'<a href="%s:%s" title="%s">%s</a>' % (scheme, url,
|
||||
prepare_string_for_xml(path, True), _('Click to open'))
|
||||
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name, link)))
|
||||
elif field == 'formats':
|
||||
if isdevice: continue
|
||||
fmts = [u'<a href="format:%s:%s">%s</a>' % (mi.id, x, x) for x
|
||||
in mi.formats]
|
||||
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
|
||||
u', '.join(fmts))))
|
||||
elif field == 'identifiers':
|
||||
pass # TODO
|
||||
else:
|
||||
if key == _('Path'):
|
||||
txt = u'<a href="devpath:%s">%s</a>'%(txt,
|
||||
_('Click to open'))
|
||||
val = mi.format_field(field)[-1]
|
||||
if val is None:
|
||||
continue
|
||||
val = prepare_string_for_xml(val)
|
||||
if metadata['datatype'] == 'series':
|
||||
if metadata['is_custom']:
|
||||
sidx = mi.get_extra(field)
|
||||
else:
|
||||
sidx = getattr(mi, field+'_index')
|
||||
if sidx is None:
|
||||
sidx = 1.0
|
||||
val = _('Book %s of <span class="series_name">%s</span>')%(fmt_sidx(sidx,
|
||||
use_roman=use_roman_numbers),
|
||||
prepare_string_for_xml(getattr(mi, field)))
|
||||
|
||||
rows.append((key, txt))
|
||||
return rows
|
||||
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name, val)))
|
||||
|
||||
dc = getattr(mi, 'device_collections', [])
|
||||
if dc:
|
||||
dc = u', '.join(sorted(dc, key=sort_key))
|
||||
ans.append(('device_collections',
|
||||
u'<td class="title">%s</td><td>%s</td>'%(
|
||||
_('Collections')+':', dc)))
|
||||
|
||||
def classname(field):
|
||||
try:
|
||||
dt = fm[field]['datatype']
|
||||
except:
|
||||
dt = 'text'
|
||||
return 'datatype_%s'%dt
|
||||
|
||||
ans = [u'<tr id="%s" class="%s">%s</tr>'%(field.replace('#', '_'),
|
||||
classname(field), html) for field, html in ans]
|
||||
# print '\n'.join(ans)
|
||||
return u'<table class="fields">%s</table>'%(u'\n'.join(ans))
|
||||
|
||||
# }}}
|
||||
|
||||
@ -117,10 +201,10 @@ class CoverView(QWidget): # {{{
|
||||
|
||||
def show_data(self, data):
|
||||
self.animation.stop()
|
||||
same_item = data.get('id', True) == self.data.get('id', False)
|
||||
same_item = getattr(data, 'id', True) == self.data.get('id', False)
|
||||
self.data = {'id':data.get('id', None)}
|
||||
if data.has_key('cover'):
|
||||
self.pixmap = QPixmap.fromImage(data.pop('cover'))
|
||||
if data.cover_data[1]:
|
||||
self.pixmap = QPixmap.fromImage(data.cover_data[1])
|
||||
if self.pixmap.isNull() or self.pixmap.width() < 5 or \
|
||||
self.pixmap.height() < 5:
|
||||
self.pixmap = self.default_pixmap
|
||||
@ -188,32 +272,6 @@ class CoverView(QWidget): # {{{
|
||||
|
||||
# Book Info {{{
|
||||
|
||||
class RenderComments(QThread):
|
||||
|
||||
rdone = pyqtSignal(object, object)
|
||||
|
||||
def __init__(self, parent):
|
||||
QThread.__init__(self, parent)
|
||||
self.queue = Queue()
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
try:
|
||||
rows, comments = self.queue.get()
|
||||
except:
|
||||
break
|
||||
import time
|
||||
time.sleep(0.001)
|
||||
oint = sys.getcheckinterval()
|
||||
sys.setcheckinterval(5)
|
||||
try:
|
||||
self.rdone.emit(rows, comments_to_html(comments))
|
||||
except:
|
||||
pass
|
||||
sys.setcheckinterval(oint)
|
||||
|
||||
|
||||
class BookInfo(QWebView):
|
||||
|
||||
link_clicked = pyqtSignal(object)
|
||||
@ -221,8 +279,6 @@ class BookInfo(QWebView):
|
||||
def __init__(self, vertical, parent=None):
|
||||
QWebView.__init__(self, parent)
|
||||
self.vertical = vertical
|
||||
self.renderer = RenderComments(self)
|
||||
self.renderer.rdone.connect(self._show_data, type=Qt.QueuedConnection)
|
||||
self.page().setLinkDelegationPolicy(self.page().DelegateAllLinks)
|
||||
self.linkClicked.connect(self.link_activated)
|
||||
self._link_clicked = False
|
||||
@ -231,6 +287,7 @@ class BookInfo(QWebView):
|
||||
self.setAcceptDrops(False)
|
||||
palette.setBrush(QPalette.Base, Qt.transparent)
|
||||
self.page().setPalette(palette)
|
||||
self.css = P('templates/book_details.css', data=True).decode('utf-8')
|
||||
|
||||
def link_activated(self, link):
|
||||
self._link_clicked = True
|
||||
@ -240,56 +297,9 @@ class BookInfo(QWebView):
|
||||
def turnoff_scrollbar(self, *args):
|
||||
self.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
|
||||
|
||||
def show_data(self, data):
|
||||
rows = render_rows(data)
|
||||
rows = u'\n'.join([u'<tr><td valign="top"><b>%s:</b></td><td valign="top">%s</td></tr>'%(k,t) for
|
||||
k, t in rows])
|
||||
comments = data.get(_('Comments'), '')
|
||||
if not comments or comments == u'None':
|
||||
comments = ''
|
||||
self.renderer.queue.put((rows, comments))
|
||||
self._show_data(rows, '')
|
||||
|
||||
|
||||
def _show_data(self, rows, comments):
|
||||
|
||||
def color_to_string(col):
|
||||
ans = '#000000'
|
||||
if col.isValid():
|
||||
col = col.toRgb()
|
||||
if col.isValid():
|
||||
ans = unicode(col.name())
|
||||
return ans
|
||||
|
||||
f = QFontInfo(QApplication.font(self.parent())).pixelSize()
|
||||
c = color_to_string(QApplication.palette().color(QPalette.Normal,
|
||||
QPalette.WindowText))
|
||||
templ = u'''\
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
body, td {background-color: transparent; font-size: %dpx; color: %s }
|
||||
a { text-decoration: none; color: blue }
|
||||
div.description { margin-top: 0; padding-top: 0; text-indent: 0 }
|
||||
table { margin-bottom: 0; padding-bottom: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
%%s
|
||||
</body>
|
||||
<html>
|
||||
'''%(f, c)
|
||||
if self.vertical:
|
||||
extra = ''
|
||||
if comments:
|
||||
extra = u'<div class="description">%s</div>'%comments
|
||||
self.setHtml(templ%(u'<table>%s</table>%s'%(rows, extra)))
|
||||
else:
|
||||
left_pane = u'<table>%s</table>'%rows
|
||||
right_pane = u'<div>%s</div>'%comments
|
||||
self.setHtml(templ%(u'<table><tr><td valign="top" '
|
||||
'style="padding-right:2em; width:40%%">%s</td><td valign="top">%s</td></tr></table>'
|
||||
% (left_pane, right_pane)))
|
||||
def show_data(self, mi):
|
||||
html = render_html(mi, self.css, self.vertical, self.parent())
|
||||
self.setHtml(html)
|
||||
|
||||
def mouseDoubleClickEvent(self, ev):
|
||||
swidth = self.page().mainFrame().scrollBarGeometry(Qt.Vertical).width()
|
||||
@ -457,10 +467,10 @@ class BookDetails(QWidget): # {{{
|
||||
self._layout.addWidget(self.cover_view)
|
||||
self.book_info = BookInfo(vertical, self)
|
||||
self._layout.addWidget(self.book_info)
|
||||
self.book_info.link_clicked.connect(self._link_clicked)
|
||||
self.book_info.link_clicked.connect(self.handle_click)
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
|
||||
def _link_clicked(self, link):
|
||||
def handle_click(self, link):
|
||||
typ, _, val = link.partition(':')
|
||||
if typ == 'path':
|
||||
self.open_containing_folder.emit(int(val))
|
||||
@ -484,7 +494,7 @@ class BookDetails(QWidget): # {{{
|
||||
def show_data(self, data):
|
||||
self.book_info.show_data(data)
|
||||
self.cover_view.show_data(data)
|
||||
self.current_path = data.get(_('Path'), '')
|
||||
self.current_path = getattr(data, u'path', u'')
|
||||
self.update_layout()
|
||||
|
||||
def update_layout(self):
|
||||
@ -500,7 +510,7 @@ class BookDetails(QWidget): # {{{
|
||||
)
|
||||
|
||||
def reset_info(self):
|
||||
self.show_data({})
|
||||
self.show_data(Metadata(_('Unknown')))
|
||||
|
||||
# }}}
|
||||
|
||||
|
@ -3,30 +3,33 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import textwrap, os, re
|
||||
|
||||
from PyQt4.Qt import QCoreApplication, SIGNAL, QModelIndex, QTimer, Qt, \
|
||||
QDialog, QPixmap, QIcon, QSize
|
||||
from PyQt4.Qt import (QCoreApplication, SIGNAL, QModelIndex, QTimer, Qt,
|
||||
QDialog, QPixmap, QIcon, QSize, QPalette)
|
||||
|
||||
from calibre.gui2.dialogs.book_info_ui import Ui_BookInfo
|
||||
from calibre.gui2 import dynamic, open_local_file, open_url
|
||||
from calibre.gui2 import dynamic
|
||||
from calibre import fit_image
|
||||
from calibre.library.comments import comments_to_html
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
from calibre.gui2.book_details import render_html
|
||||
|
||||
class BookInfo(QDialog, Ui_BookInfo):
|
||||
|
||||
def __init__(self, parent, view, row, view_func):
|
||||
def __init__(self, parent, view, row, link_delegate):
|
||||
QDialog.__init__(self, parent)
|
||||
Ui_BookInfo.__init__(self)
|
||||
self.setupUi(self)
|
||||
self.gui = parent
|
||||
self.cover_pixmap = None
|
||||
self.comments.sizeHint = self.comments_size_hint
|
||||
self.comments.page().setLinkDelegationPolicy(self.comments.page().DelegateAllLinks)
|
||||
self.comments.linkClicked.connect(self.link_clicked)
|
||||
self.view_func = view_func
|
||||
self.details.sizeHint = self.details_size_hint
|
||||
self.details.page().setLinkDelegationPolicy(self.details.page().DelegateAllLinks)
|
||||
self.details.linkClicked.connect(self.link_clicked)
|
||||
self.css = P('templates/book_details.css', data=True).decode('utf-8')
|
||||
self.link_delegate = link_delegate
|
||||
self.details.setAttribute(Qt.WA_OpaquePaintEvent, False)
|
||||
palette = self.details.palette()
|
||||
self.details.setAcceptDrops(False)
|
||||
palette.setBrush(QPalette.Base, Qt.transparent)
|
||||
self.details.page().setPalette(palette)
|
||||
|
||||
|
||||
self.view = view
|
||||
@ -37,7 +40,6 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
self.connect(self.view.selectionModel(), SIGNAL('currentChanged(QModelIndex,QModelIndex)'), self.slave)
|
||||
self.connect(self.next_button, SIGNAL('clicked()'), self.next)
|
||||
self.connect(self.previous_button, SIGNAL('clicked()'), self.previous)
|
||||
self.connect(self.text, SIGNAL('linkActivated(QString)'), self.open_book_path)
|
||||
self.fit_cover.stateChanged.connect(self.toggle_cover_fit)
|
||||
self.cover.resizeEvent = self.cover_view_resized
|
||||
self.cover.cover_changed.connect(self.cover_changed)
|
||||
@ -46,6 +48,10 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
screen_height = desktop.availableGeometry().height() - 100
|
||||
self.resize(self.size().width(), screen_height)
|
||||
|
||||
def link_clicked(self, qurl):
|
||||
link = unicode(qurl.toString())
|
||||
self.link_delegate(link)
|
||||
|
||||
def cover_changed(self, data):
|
||||
if self.current_row is not None:
|
||||
id_ = self.view.model().id(self.current_row)
|
||||
@ -60,11 +66,8 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
if self.fit_cover.isChecked():
|
||||
self.resize_cover()
|
||||
|
||||
def link_clicked(self, url):
|
||||
open_url(url)
|
||||
|
||||
def comments_size_hint(self):
|
||||
return QSize(350, 250)
|
||||
def details_size_hint(self):
|
||||
return QSize(350, 550)
|
||||
|
||||
def toggle_cover_fit(self, state):
|
||||
dynamic.set('book_info_dialog_fit_cover', self.fit_cover.isChecked())
|
||||
@ -77,13 +80,6 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
row = current.row()
|
||||
self.refresh(row)
|
||||
|
||||
def open_book_path(self, path):
|
||||
path = unicode(path)
|
||||
if os.sep in path:
|
||||
open_local_file(path)
|
||||
else:
|
||||
self.view_func(self.view.model().id(self.current_row), path)
|
||||
|
||||
def next(self):
|
||||
row = self.view.currentIndex().row()
|
||||
ni = self.view.model().index(row+1, 0)
|
||||
@ -117,8 +113,8 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
row = row.row()
|
||||
if row == self.current_row:
|
||||
return
|
||||
info = self.view.model().get_book_info(row)
|
||||
if info is None:
|
||||
mi = self.view.model().get_book_display_info(row)
|
||||
if mi is None:
|
||||
# Indicates books was deleted from library, or row numbers have
|
||||
# changed
|
||||
return
|
||||
@ -126,40 +122,11 @@ class BookInfo(QDialog, Ui_BookInfo):
|
||||
self.previous_button.setEnabled(False if row == 0 else True)
|
||||
self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True)
|
||||
self.current_row = row
|
||||
self.setWindowTitle(info[_('Title')])
|
||||
self.title.setText('<b>'+info.pop(_('Title')))
|
||||
comments = info.pop(_('Comments'), '')
|
||||
if comments:
|
||||
comments = comments_to_html(comments)
|
||||
if re.search(r'<[a-zA-Z]+>', comments) is None:
|
||||
lines = comments.splitlines()
|
||||
lines = [x if x.strip() else '<br><br>' for x in lines]
|
||||
comments = '\n'.join(lines)
|
||||
self.comments.setHtml('<div>%s</div>' % comments)
|
||||
self.comments.page().setLinkDelegationPolicy(self.comments.page().DelegateAllLinks)
|
||||
cdata = info.pop('cover', '')
|
||||
self.cover_pixmap = QPixmap.fromImage(cdata)
|
||||
self.setWindowTitle(mi.title)
|
||||
self.title.setText('<b>'+mi.title)
|
||||
mi.title = _('Unknown')
|
||||
self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1])
|
||||
self.resize_cover()
|
||||
html = render_html(mi, self.css, True, self, all_fields=True)
|
||||
self.details.setHtml(html)
|
||||
|
||||
rows = u''
|
||||
self.text.setText('')
|
||||
self.data = info
|
||||
if _('Path') in info.keys():
|
||||
p = info[_('Path')]
|
||||
info[_('Path')] = '<a href="%s">%s</a>'%(p, p)
|
||||
if _('Formats') in info.keys():
|
||||
formats = info[_('Formats')].split(',')
|
||||
info[_('Formats')] = ''
|
||||
for f in formats:
|
||||
f = f.strip()
|
||||
info[_('Formats')] += '<a href="%s">%s</a>, '%(f,f)
|
||||
for key in sorted(info.keys(), key=sort_key):
|
||||
if key == 'id': continue
|
||||
txt = info[key]
|
||||
if key.endswith(':html'):
|
||||
key = key[:-5]
|
||||
txt = comments_to_html(txt)
|
||||
if key != _('Path'):
|
||||
txt = u'<br />\n'.join(textwrap.wrap(txt, 120))
|
||||
rows += u'<tr><td><b>%s:</b></td><td>%s</td></tr>'%(key, txt)
|
||||
self.text.setText(u'<table>'+rows+'</table>')
|
||||
|
@ -20,6 +20,12 @@
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="title">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -34,82 +40,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" rowspan="3">
|
||||
<item row="2" column="0" rowspan="3">
|
||||
<widget class="CoverView" name="cover"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>435</width>
|
||||
<height>670</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="text">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Comments</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QWebView" name="comments">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>350</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="url">
|
||||
<url>
|
||||
<string>about:blank</string>
|
||||
</url>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="fit_cover">
|
||||
<property name="text">
|
||||
<string>Fit &cover within view</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="previous_button">
|
||||
@ -135,6 +76,15 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QWebView" name="details">
|
||||
<property name="url">
|
||||
<url>
|
||||
<string>about:blank</string>
|
||||
</url>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
@ -8,20 +8,20 @@ __docformat__ = 'restructuredtext en'
|
||||
import shutil, functools, re, os, traceback
|
||||
from contextlib import closing
|
||||
|
||||
from PyQt4.Qt import QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, \
|
||||
QModelIndex, QVariant, QDate, QColor
|
||||
from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
|
||||
QModelIndex, QVariant, QDate, QColor)
|
||||
|
||||
from calibre.gui2 import NONE, config, UNDEFINED_QDATE
|
||||
from calibre.gui2 import NONE, UNDEFINED_QDATE
|
||||
from calibre.utils.pyparsing import ParseException
|
||||
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.utils.config import tweaks, prefs
|
||||
from calibre.utils.date import dt_factory, qt_to_dt, isoformat
|
||||
from calibre.utils.date import dt_factory, qt_to_dt
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.search_query_parser import SearchQueryParser
|
||||
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
|
||||
REGEXP_MATCH, MetadataBackup, force_to_bool
|
||||
from calibre import strftime, isbytestring, prepare_string_for_xml
|
||||
from calibre.library.caches import (_match, CONTAINS_MATCH, EQUALS_MATCH,
|
||||
REGEXP_MATCH, MetadataBackup, force_to_bool)
|
||||
from calibre import strftime, isbytestring
|
||||
from calibre.constants import filesystem_encoding, DEBUG
|
||||
from calibre.gui2.library import DEFAULT_SORT
|
||||
|
||||
@ -114,7 +114,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
return cc_label in self.custom_columns
|
||||
|
||||
def read_config(self):
|
||||
self.use_roman_numbers = config['use_roman_numerals_for_series_number']
|
||||
pass
|
||||
|
||||
def set_device_connected(self, is_connected):
|
||||
self.device_connected = is_connected
|
||||
@ -355,63 +355,13 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
return self.rowCount(None)
|
||||
|
||||
def get_book_display_info(self, idx):
|
||||
def custom_keys_to_display():
|
||||
ans = getattr(self, '_custom_fields_in_book_info', None)
|
||||
if ans is None:
|
||||
cfkeys = set(self.db.custom_field_keys())
|
||||
yes_fields = set(tweaks['book_details_will_display'])
|
||||
no_fields = set(tweaks['book_details_wont_display'])
|
||||
if '*' in yes_fields:
|
||||
yes_fields = cfkeys
|
||||
if '*' in no_fields:
|
||||
no_fields = cfkeys
|
||||
ans = frozenset(yes_fields - no_fields)
|
||||
setattr(self, '_custom_fields_in_book_info', ans)
|
||||
return ans
|
||||
|
||||
data = {}
|
||||
cdata = self.cover(idx)
|
||||
if cdata:
|
||||
data['cover'] = cdata
|
||||
tags = list(self.db.get_tags(self.db.id(idx)))
|
||||
if tags:
|
||||
tags.sort(key=sort_key)
|
||||
tags = ', '.join(tags)
|
||||
else:
|
||||
tags = _('None')
|
||||
data[_('Tags')] = tags
|
||||
formats = self.db.formats(idx)
|
||||
if formats:
|
||||
formats = formats.replace(',', ', ')
|
||||
else:
|
||||
formats = _('None')
|
||||
data[_('Formats')] = formats
|
||||
data[_('Path')] = self.db.abspath(idx)
|
||||
data['id'] = self.id(idx)
|
||||
comments = self.db.comments(idx)
|
||||
if not comments:
|
||||
comments = _('None')
|
||||
data[_('Comments')] = comments
|
||||
series = self.db.series(idx)
|
||||
if series:
|
||||
sidx = self.db.series_index(idx)
|
||||
sidx = fmt_sidx(sidx, use_roman = self.use_roman_numbers)
|
||||
data[_('Series')] = \
|
||||
_('Book %s of %s.')%\
|
||||
(sidx, prepare_string_for_xml(series))
|
||||
mi = self.db.get_metadata(idx)
|
||||
cf_to_display = custom_keys_to_display()
|
||||
for key in mi.custom_field_keys():
|
||||
if key not in cf_to_display:
|
||||
continue
|
||||
name, val = mi.format_field(key)
|
||||
if mi.metadata_for_field(key)['datatype'] == 'comments':
|
||||
name += ':html'
|
||||
if val and name not in data:
|
||||
data[name] = val
|
||||
|
||||
return data
|
||||
|
||||
mi.size = mi.book_size
|
||||
mi.cover_data = ('jpg', self.cover(idx))
|
||||
mi.id = self.db.id(idx)
|
||||
mi.field_metadata = self.db.field_metadata
|
||||
mi.path = self.db.abspath(idx, create_dirs=False)
|
||||
return mi
|
||||
|
||||
def current_changed(self, current, previous, emit_signal=True):
|
||||
if current.isValid():
|
||||
@ -425,16 +375,8 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
def get_book_info(self, index):
|
||||
if isinstance(index, int):
|
||||
index = self.index(index, 0)
|
||||
# If index is not valid returns None
|
||||
data = self.current_changed(index, None, False)
|
||||
if data is None:
|
||||
return data
|
||||
row = index.row()
|
||||
data[_('Title')] = self.db.title(row)
|
||||
au = self.db.authors(row)
|
||||
if not au:
|
||||
au = _('Unknown')
|
||||
au = authors_to_string([a.strip().replace('|', ',') for a in au.split(',')])
|
||||
data[_('Author(s)')] = au
|
||||
return data
|
||||
|
||||
def metadata_for(self, ids):
|
||||
@ -1189,39 +1131,46 @@ class DeviceBooksModel(BooksModel): # {{{
|
||||
img = self.default_image
|
||||
return img
|
||||
|
||||
def current_changed(self, current, previous):
|
||||
data = {}
|
||||
item = self.db[self.map[current.row()]]
|
||||
cover = self.cover(current.row())
|
||||
if cover is not self.default_image:
|
||||
data['cover'] = cover
|
||||
type = _('Unknown')
|
||||
def get_book_display_info(self, idx):
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
item = self.db[self.map[idx]]
|
||||
cover = self.cover(idx)
|
||||
if cover is self.default_image:
|
||||
cover = None
|
||||
title = item.title
|
||||
if not title:
|
||||
title = _('Unknown')
|
||||
au = item.authors
|
||||
if not au:
|
||||
au = [_('Unknown')]
|
||||
mi = Metadata(title, au)
|
||||
mi.cover_data = ('jpg', cover)
|
||||
fmt = _('Unknown')
|
||||
ext = os.path.splitext(item.path)[1]
|
||||
if ext:
|
||||
type = ext[1:].lower()
|
||||
data[_('Format')] = type
|
||||
data[_('Path')] = item.path
|
||||
fmt = ext[1:].lower()
|
||||
mi.formats = [fmt]
|
||||
mi.path = (item.path if item.path else None)
|
||||
dt = dt_factory(item.datetime, assume_utc=True)
|
||||
data[_('Timestamp')] = isoformat(dt, sep=' ', as_utc=False)
|
||||
data[_('Collections')] = ', '.join(item.device_collections)
|
||||
|
||||
tags = getattr(item, 'tags', None)
|
||||
if tags:
|
||||
tags = u', '.join(tags)
|
||||
else:
|
||||
tags = _('None')
|
||||
data[_('Tags')] = tags
|
||||
comments = getattr(item, 'comments', None)
|
||||
if not comments:
|
||||
comments = _('None')
|
||||
data[_('Comments')] = comments
|
||||
mi.timestamp = dt
|
||||
mi.device_collections = list(item.device_collections)
|
||||
mi.tags = list(getattr(item, 'tags', []))
|
||||
mi.comments = getattr(item, 'comments', None)
|
||||
series = getattr(item, 'series', None)
|
||||
if series:
|
||||
sidx = getattr(item, 'series_index', 0)
|
||||
sidx = fmt_sidx(sidx, use_roman = self.use_roman_numbers)
|
||||
data[_('Series')] = _('Book <font face="serif">%s</font> of %s.')%(sidx, series)
|
||||
mi.series = series
|
||||
mi.series_index = sidx
|
||||
return mi
|
||||
|
||||
self.new_bookdisplay_data.emit(data)
|
||||
def current_changed(self, current, previous, emit_signal=True):
|
||||
if current.isValid():
|
||||
idx = current.row()
|
||||
data = self.get_book_display_info(idx)
|
||||
if emit_signal:
|
||||
self.new_bookdisplay_data.emit(data)
|
||||
else:
|
||||
return data
|
||||
|
||||
def paths(self, rows):
|
||||
return [self.db[self.map[r.row()]].path for r in rows ]
|
||||
@ -1281,7 +1230,7 @@ class DeviceBooksModel(BooksModel): # {{{
|
||||
elif cname == 'authors':
|
||||
au = self.db[self.map[row]].authors
|
||||
if not au:
|
||||
au = self.unknown
|
||||
au = [_('Unknown')]
|
||||
return QVariant(authors_to_string(au))
|
||||
elif cname == 'size':
|
||||
size = self.db[self.map[row]].size
|
||||
|
@ -5,16 +5,22 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from PyQt4.Qt import QApplication, QFont, QFontInfo, QFontDialog
|
||||
from PyQt4.Qt import (QApplication, QFont, QFontInfo, QFontDialog,
|
||||
QAbstractListModel)
|
||||
|
||||
from calibre.gui2.preferences import ConfigWidgetBase, test_widget, CommaSeparatedList
|
||||
from calibre.gui2.preferences.look_feel_ui import Ui_Form
|
||||
from calibre.gui2 import config, gprefs, qt_app
|
||||
from calibre.utils.localization import available_translations, \
|
||||
get_language, get_lang
|
||||
from calibre.utils.localization import (available_translations,
|
||||
get_language, get_lang)
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
class DisplayedFields(QAbstractListModel):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QAbstractListModel.__init__(self, parent)
|
||||
|
||||
class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
|
||||
def genesis(self, gui):
|
||||
|
@ -14,280 +14,421 @@
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>User Interface &layout (needs restart):</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_gui_layout</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="opt_gui_layout">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>20</number>
|
||||
</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">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Choose &language (requires restart):</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_language</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="opt_language">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<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="3" column="1">
|
||||
<widget class="QCheckBox" name="opt_disable_animations">
|
||||
<property name="toolTip">
|
||||
<string>Disable all animations. Useful if you have a slow/old computer.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable &animations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" 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="4" column="1">
|
||||
<widget class="QCheckBox" name="opt_show_splash_screen">
|
||||
<property name="text">
|
||||
<string>Show &splash screen at startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" 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="5" 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="6" 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="7" 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
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QToolBox" name="toolBox">
|
||||
<widget class="QWidget" name="page">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>682</width>
|
||||
<height>254</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Main interface</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>User Interface &layout (needs restart):</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_gui_layout</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="opt_gui_layout">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Choose &language (requires restart):</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_language</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="opt_language">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="opt_disable_animations">
|
||||
<property name="toolTip">
|
||||
<string>Disable all animations. Useful if you have a slow/old computer.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable &animations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="opt_show_splash_screen">
|
||||
<property name="text">
|
||||
<string>Show &splash screen at startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>&Toolbar</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="opt_toolbar_icon_size"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>&Icon size:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_toolbar_icon_size</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="opt_toolbar_text"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Show &text under icons:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_toolbar_text</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" 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">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Interface font:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>font_display</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="font_display">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QPushButton" name="change_font_button">
|
||||
<property name="text">
|
||||
<string>Change &font (needs restart)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</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="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>699</width>
|
||||
<height>151</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
|
||||
</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="8" 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="8" column="1">
|
||||
<widget class="MultiCompleteLineEdit" name="opt_categories_using_hierarchy">
|
||||
<property name="toolTip">
|
||||
<string>A comma-separated list of columns in which items containing
|
||||
</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>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<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_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>699</width>
|
||||
<height>306</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Cover Browser</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<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>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<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">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Select displayed metadata</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0" rowspan="3">
|
||||
<widget class="QListView" name="field_display_order">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QToolButton" name="toolButton">
|
||||
<property name="toolTip">
|
||||
<string>Move up</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/arrow-up.png</normaloff>:/images/arrow-up.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QToolButton" name="toolButton_2">
|
||||
<property name="toolTip">
|
||||
<string>Move down</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<normaloff>:/images/arrow-down.png</normaloff>:/images/arrow-down.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer name="verticalSpacer_5">
|
||||
<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>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>&Toolbar</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="opt_toolbar_icon_size"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>&Icon size:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_toolbar_icon_size</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="opt_toolbar_text"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Show &text under icons:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>opt_toolbar_text</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Interface font:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>font_display</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="font_display">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<widget class="QPushButton" name="change_font_button">
|
||||
<property name="text">
|
||||
<string>Change &font (needs restart)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<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>
|
||||
<customwidgets>
|
||||
@ -297,6 +438,8 @@ then the tags will be displayed each on their own line.</string>
|
||||
<header>calibre/gui2/complete.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../../../../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
|
@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
''' Design documentation {{{
|
||||
|
||||
Storage paradigm {{{
|
||||
* Agnostic to storage paradigm (i.e. no book per folder assumptions)
|
||||
* Two separate concepts: A store and collection
|
||||
A store is a backend, like a sqlite database associated with a path on
|
||||
the local filesystem, or a cloud based storage solution.
|
||||
A collection is a user defined group of stores. Most of the logic for
|
||||
data manipulation sorting/searching/restrictions should be in the collection
|
||||
class. The collection class should transparently handle the
|
||||
conversion from store name + id to row number in the collection.
|
||||
* Not sure how feasible it is to allow many-many maps between stores
|
||||
and collections.
|
||||
}}}
|
||||
|
||||
Event system {{{
|
||||
* Comprehensive event system that other components can subscribe to
|
||||
* Subscribers should be able to temporarily block receiving events
|
||||
* Should event dispatch be asynchronous?
|
||||
* Track last modified time for metadata and each format
|
||||
}}}
|
||||
}}}'''
|
||||
|
||||
# Imports {{{
|
||||
# }}}
|
||||
|
||||
|
||||
|
||||
|
@ -188,7 +188,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'name':_('Author Sort'),
|
||||
'search_terms':['author_sort'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@ -238,7 +238,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'datetime',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':_('Date'),
|
||||
'name':_('Modified'),
|
||||
'search_terms':['last_modified'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@ -258,7 +258,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'name':_('Path'),
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@ -308,7 +308,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'float',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':_('Size (MB)'),
|
||||
'name':_('Size'),
|
||||
'search_terms':['size'],
|
||||
'is_custom':False,
|
||||
'is_category':False,
|
||||
@ -399,6 +399,13 @@ class FieldMetadata(dict):
|
||||
if self._tb_cats[k]['kind']=='field' and
|
||||
self._tb_cats[k]['datatype'] is not None]
|
||||
|
||||
def displayable_field_keys(self):
|
||||
return [k for k in self._tb_cats.keys()
|
||||
if self._tb_cats[k]['kind']=='field' and
|
||||
self._tb_cats[k]['datatype'] is not None and
|
||||
k not in ('au_map', 'marked', 'ondevice', 'cover') and
|
||||
not self.is_series_index(k)]
|
||||
|
||||
def standard_field_keys(self):
|
||||
return [k for k in self._tb_cats.keys()
|
||||
if self._tb_cats[k]['kind']=='field' and
|
||||
@ -442,6 +449,11 @@ class FieldMetadata(dict):
|
||||
def is_custom_field(self, key):
|
||||
return key.startswith(self.custom_field_prefix)
|
||||
|
||||
def is_series_index(self, key):
|
||||
m = self[key]
|
||||
return (m['datatype'] == 'float' and key.endswith('_index') and
|
||||
key[:-6] in self)
|
||||
|
||||
def key_to_label(self, key):
|
||||
if 'label' not in self._tb_cats[key]:
|
||||
return key
|
||||
|
Loading…
x
Reference in New Issue
Block a user