mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Make icon rules composable.
This commit is contained in:
parent
9c3e61cee2
commit
2fe01db004
@ -7,7 +7,7 @@ import json, os, traceback
|
|||||||
|
|
||||||
from PyQt4.Qt import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont,
|
from PyQt4.Qt import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont,
|
||||||
QRegExp, QApplication, QTextCharFormat, QColor, QCursor,
|
QRegExp, QApplication, QTextCharFormat, QColor, QCursor,
|
||||||
QIcon, QSize)
|
QIcon, QSize, QVariant)
|
||||||
|
|
||||||
from calibre import sanitize_file_name_unicode
|
from calibre import sanitize_file_name_unicode
|
||||||
from calibre.constants import config_dir
|
from calibre.constants import config_dir
|
||||||
@ -19,7 +19,6 @@ from calibre.ebooks.metadata.book.formatter import SafeFormat
|
|||||||
from calibre.library.coloring import (displayable_columns, color_row_key)
|
from calibre.library.coloring import (displayable_columns, color_row_key)
|
||||||
from calibre.gui2 import error_dialog, choose_files, pixmap_to_data
|
from calibre.gui2 import error_dialog, choose_files, pixmap_to_data
|
||||||
|
|
||||||
|
|
||||||
class ParenPosition:
|
class ParenPosition:
|
||||||
|
|
||||||
def __init__(self, block, pos, paren):
|
def __init__(self, block, pos, paren):
|
||||||
@ -247,9 +246,15 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
|||||||
self.icon_file_names.append(icon_file)
|
self.icon_file_names.append(icon_file)
|
||||||
self.icon_file_names.sort(key=sort_key)
|
self.icon_file_names.sort(key=sort_key)
|
||||||
self.update_filename_box()
|
self.update_filename_box()
|
||||||
self.icon_with_text.setChecked(True)
|
|
||||||
if icon_rule_kind == 'icon_only':
|
dex = 0
|
||||||
self.icon_without_text.setChecked(True)
|
from calibre.gui2.preferences.coloring import icon_rule_kinds
|
||||||
|
for i,tup in enumerate(icon_rule_kinds):
|
||||||
|
txt,val = tup
|
||||||
|
self.icon_kind.addItem(txt, userData=QVariant(val))
|
||||||
|
if val == icon_rule_kind:
|
||||||
|
dex = i
|
||||||
|
self.icon_kind.setCurrentIndex(dex)
|
||||||
self.icon_field.setCurrentIndex(self.icon_field.findData(icon_field_key))
|
self.icon_field.setCurrentIndex(self.icon_field.findData(icon_field_key))
|
||||||
|
|
||||||
if mi:
|
if mi:
|
||||||
@ -410,7 +415,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
|||||||
self.rule = (unicode(self.colored_field.itemData(
|
self.rule = (unicode(self.colored_field.itemData(
|
||||||
self.colored_field.currentIndex()).toString()), txt)
|
self.colored_field.currentIndex()).toString()), txt)
|
||||||
elif self.iconing:
|
elif self.iconing:
|
||||||
rt = 'icon' if self.icon_with_text.isChecked() else 'icon_only'
|
rt = unicode(self.icon_kind.itemData(self.icon_kind.currentIndex()).toString())
|
||||||
self.rule = (rt,
|
self.rule = (rt,
|
||||||
unicode(self.icon_field.itemData(
|
unicode(self.icon_field.itemData(
|
||||||
self.icon_field.currentIndex()).toString()),
|
self.icon_field.currentIndex()).toString()),
|
||||||
|
@ -69,33 +69,19 @@
|
|||||||
<widget class="QWidget" name="icon_layout">
|
<widget class="QWidget" name="icon_layout">
|
||||||
<layout class="QGridLayout">
|
<layout class="QGridLayout">
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QGroupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Kind</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="icon_without_text">
|
<widget class="QLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>icon with no text</string>
|
<string>Kind:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="icon_with_text">
|
<widget class="QComboBox" name="icon_kind">
|
||||||
<property name="text">
|
|
||||||
<string>icon with text</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>100</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="icon_chooser_label">
|
<widget class="QLabel" name="icon_chooser_label">
|
||||||
|
@ -81,38 +81,49 @@ class ColumnIcon(object): # {{{
|
|||||||
self.formatter = formatter
|
self.formatter = formatter
|
||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
def __call__(self, id_, key, fmt, kind, db, icon_cache, icon_bitmap_cache):
|
def __call__(self, id_, key, fmts, cache_index, db, icon_cache, icon_bitmap_cache):
|
||||||
dex = key+kind
|
if id_ in icon_cache and cache_index in icon_cache[id_]:
|
||||||
if id_ in icon_cache and dex in icon_cache[id_]:
|
|
||||||
self.mi = None
|
self.mi = None
|
||||||
return icon_cache[id_][dex]
|
return icon_cache[id_][cache_index]
|
||||||
try:
|
try:
|
||||||
if self.mi is None:
|
if self.mi is None:
|
||||||
self.mi = db.get_metadata(id_, index_is_id=True)
|
self.mi = db.get_metadata(id_, index_is_id=True)
|
||||||
icons = self.formatter.safe_format(fmt, self.mi, '', self.mi)
|
icons = []
|
||||||
|
for kind,fmt in fmts:
|
||||||
|
rule_icons = self.formatter.safe_format(fmt, self.mi, '', self.mi)
|
||||||
|
if not rule_icons:
|
||||||
|
continue
|
||||||
|
icon_list = [ic.strip() for ic in rule_icons.split(':')]
|
||||||
|
if icon_list and not kind.endswith('_composed'):
|
||||||
|
icons = icon_list
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
icons.extend(icon_list)
|
||||||
|
|
||||||
if icons:
|
if icons:
|
||||||
if icons in icon_bitmap_cache:
|
icon_string = ':'.join(icons)
|
||||||
icon_bitmap = icon_bitmap_cache[icons]
|
if icon_string in icon_bitmap_cache:
|
||||||
icon_cache[id_][dex] = icon_bitmap
|
icon_bitmap = icon_bitmap_cache[icon_string]
|
||||||
|
icon_cache[id_][cache_index] = icon_bitmap
|
||||||
return icon_bitmap
|
return icon_bitmap
|
||||||
|
|
||||||
icon_list = [ic.strip() for ic in icons.split(':')]
|
|
||||||
icon_bitmaps = []
|
icon_bitmaps = []
|
||||||
total_width = 0
|
total_width = 0
|
||||||
for icon in icon_list:
|
for icon in icons:
|
||||||
d = os.path.join(config_dir, 'cc_icons', icon)
|
d = os.path.join(config_dir, 'cc_icons', icon)
|
||||||
if (os.path.exists(d)):
|
if (os.path.exists(d)):
|
||||||
bm = QPixmap(d)
|
bm = QPixmap(d)
|
||||||
icon_bitmaps.append(bm)
|
icon_bitmaps.append(bm)
|
||||||
total_width += bm.width()
|
total_width += bm.width()
|
||||||
if len(icon_bitmaps) > 1:
|
if len(icon_bitmaps) > 1:
|
||||||
result = QPixmap(len(icon_list)*128, 128)
|
i = len(icon_bitmaps)
|
||||||
|
result = QPixmap((i * 128) + ((i-1)*2), 128)
|
||||||
result.fill(Qt.transparent)
|
result.fill(Qt.transparent)
|
||||||
painter = QPainter(result)
|
painter = QPainter(result)
|
||||||
x = 0
|
x = 0
|
||||||
for bm in icon_bitmaps:
|
for bm in icon_bitmaps:
|
||||||
painter.drawPixmap(x, 0, bm)
|
painter.drawPixmap(x, 0, bm)
|
||||||
x += bm.width()
|
x += bm.width() + 2
|
||||||
painter.end()
|
painter.end()
|
||||||
else:
|
else:
|
||||||
result = icon_bitmaps[0]
|
result = icon_bitmaps[0]
|
||||||
@ -123,8 +134,8 @@ class ColumnIcon(object): # {{{
|
|||||||
rh = max(2, self.model.row_height - 2)
|
rh = max(2, self.model.row_height - 2)
|
||||||
if result.height() > rh:
|
if result.height() > rh:
|
||||||
result = result.scaledToHeight(rh, mode=Qt.SmoothTransformation)
|
result = result.scaledToHeight(rh, mode=Qt.SmoothTransformation)
|
||||||
icon_cache[id_][dex] = result
|
icon_cache[id_][cache_index] = result
|
||||||
icon_bitmap_cache[icons] = result
|
icon_bitmap_cache[icon_string] = result
|
||||||
self.mi = None
|
self.mi = None
|
||||||
return result
|
return result
|
||||||
except:
|
except:
|
||||||
@ -788,16 +799,21 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
if rules:
|
if rules:
|
||||||
key = self.column_map[col]
|
key = self.column_map[col]
|
||||||
id_ = None
|
id_ = None
|
||||||
|
fmts = []
|
||||||
for kind, k, fmt in rules:
|
for kind, k, fmt in rules:
|
||||||
if k == key and kind == 'icon_only':
|
if k == key and kind in ('icon_only', 'icon_only_composed'):
|
||||||
if id_ is None:
|
if id_ is None:
|
||||||
id_ = self.id(index)
|
id_ = self.id(index)
|
||||||
self.column_icon.mi = None
|
self.column_icon.mi = None
|
||||||
ccicon = self.column_icon(id_, key, fmt, 'icon_only', self.db,
|
fmts.append((kind, fmt))
|
||||||
|
|
||||||
|
if fmts:
|
||||||
|
cache_index = key + ':'.join([kind for kind,fmt in fmts])
|
||||||
|
ccicon = self.column_icon(id_, key, fmts, cache_index, self.db,
|
||||||
self.icon_cache, self.icon_bitmap_cache)
|
self.icon_cache, self.icon_bitmap_cache)
|
||||||
if ccicon is not None:
|
if ccicon is not None:
|
||||||
return NONE
|
return NONE
|
||||||
self.icon_cache[id_][key+'icon_only'] = None
|
self.icon_cache[id_][cache_index] = None
|
||||||
return self.column_to_dc_map[col](index.row())
|
return self.column_to_dc_map[col](index.row())
|
||||||
elif role in (Qt.EditRole, Qt.ToolTipRole):
|
elif role in (Qt.EditRole, Qt.ToolTipRole):
|
||||||
return self.column_to_dc_map[col](index.row())
|
return self.column_to_dc_map[col](index.row())
|
||||||
@ -854,21 +870,25 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
key = self.column_map[col]
|
key = self.column_map[col]
|
||||||
id_ = None
|
id_ = None
|
||||||
need_icon_with_text = False
|
need_icon_with_text = False
|
||||||
|
fmts = []
|
||||||
for kind, k, fmt in rules:
|
for kind, k, fmt in rules:
|
||||||
if k == key and kind in ('icon', 'icon_only'):
|
if k == key and kind.startswith('icon'):
|
||||||
if id_ is None:
|
if id_ is None:
|
||||||
id_ = self.id(index)
|
id_ = self.id(index)
|
||||||
self.column_icon.mi = None
|
self.column_icon.mi = None
|
||||||
if kind == 'icon':
|
fmts.append((kind, fmt))
|
||||||
|
if kind in ('icon', 'icon_composed'):
|
||||||
need_icon_with_text = True
|
need_icon_with_text = True
|
||||||
ccicon = self.column_icon(id_, key, fmt, kind, self.db,
|
if fmts:
|
||||||
|
cache_index = key + ':'.join([kind for kind,fmt in fmts])
|
||||||
|
ccicon = self.column_icon(id_, key, fmts, cache_index, self.db,
|
||||||
self.icon_cache, self.icon_bitmap_cache)
|
self.icon_cache, self.icon_bitmap_cache)
|
||||||
if ccicon is not None:
|
if ccicon is not None:
|
||||||
return ccicon
|
return ccicon
|
||||||
if need_icon_with_text:
|
if need_icon_with_text:
|
||||||
self.icon_cache[id_][key+'icon'] = self.bool_blank_icon
|
self.icon_cache[id_][cache_index] = self.bool_blank_icon
|
||||||
return self.bool_blank_icon
|
return self.bool_blank_icon
|
||||||
self.icon_cache[id_][key+'icon'] = None
|
self.icon_cache[id_][cache_index] = None
|
||||||
elif role == Qt.TextAlignmentRole:
|
elif role == Qt.TextAlignmentRole:
|
||||||
cname = self.column_map[index.column()]
|
cname = self.column_map[index.column()]
|
||||||
ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname,
|
ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname,
|
||||||
|
@ -29,7 +29,9 @@ from calibre.utils.icu import lower
|
|||||||
all_columns_string = _('All Columns')
|
all_columns_string = _('All Columns')
|
||||||
|
|
||||||
icon_rule_kinds = [(_('icon with text'), 'icon'),
|
icon_rule_kinds = [(_('icon with text'), 'icon'),
|
||||||
(_('icon with no text'), 'icon_only') ]
|
(_('icon with no text'), 'icon_only'),
|
||||||
|
(_('composed icons w/text'), 'icon_composed'),
|
||||||
|
(_('composed icons w/no text'), 'icon_only_composed'),]
|
||||||
|
|
||||||
class ConditionEditor(QWidget): # {{{
|
class ConditionEditor(QWidget): # {{{
|
||||||
|
|
||||||
@ -526,7 +528,10 @@ class RuleEditor(QDialog): # {{{
|
|||||||
if idx >= 0:
|
if idx >= 0:
|
||||||
self.color_box.setCurrentIndex(idx)
|
self.color_box.setCurrentIndex(idx)
|
||||||
else:
|
else:
|
||||||
self.kind_box.setCurrentIndex(0 if kind == 'icon' else 1)
|
for i,tup in enumerate(icon_rule_kinds):
|
||||||
|
if kind == tup[1]:
|
||||||
|
self.kind_box.setCurrentIndex(i)
|
||||||
|
break
|
||||||
self.rule_icon_files = [ic.strip() for ic in rule.color.split(':')]
|
self.rule_icon_files = [ic.strip() for ic in rule.color.split(':')]
|
||||||
if len(self.rule_icon_files) > 1:
|
if len(self.rule_icon_files) > 1:
|
||||||
self.multiple_icon_cb.setChecked(True)
|
self.multiple_icon_cb.setChecked(True)
|
||||||
@ -691,6 +696,15 @@ class RulesModel(QAbstractListModel): # {{{
|
|||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def rule_to_html(self, kind, col, rule):
|
def rule_to_html(self, kind, col, rule):
|
||||||
|
trans_kind = 'not found'
|
||||||
|
if kind == 'color':
|
||||||
|
trans_kind = _('color')
|
||||||
|
else:
|
||||||
|
for tt, t in icon_rule_kinds:
|
||||||
|
if kind == t:
|
||||||
|
trans_kind = tt
|
||||||
|
break
|
||||||
|
|
||||||
if not isinstance(rule, Rule):
|
if not isinstance(rule, Rule):
|
||||||
if kind == 'color':
|
if kind == 'color':
|
||||||
return _('''
|
return _('''
|
||||||
@ -702,21 +716,11 @@ class RulesModel(QAbstractListModel): # {{{
|
|||||||
<p>Advanced Rule: set <b>%(typ)s</b> for column <b>%(col)s</b>:
|
<p>Advanced Rule: set <b>%(typ)s</b> for column <b>%(col)s</b>:
|
||||||
<pre>%(rule)s</pre>
|
<pre>%(rule)s</pre>
|
||||||
''')%dict(col=col,
|
''')%dict(col=col,
|
||||||
typ=icon_rule_kinds[0][0]
|
typ=trans_kind,
|
||||||
if kind == icon_rule_kinds[0][1] else icon_rule_kinds[1][0],
|
|
||||||
rule=prepare_string_for_xml(rule))
|
rule=prepare_string_for_xml(rule))
|
||||||
|
|
||||||
conditions = [self.condition_to_html(c) for c in rule.conditions]
|
conditions = [self.condition_to_html(c) for c in rule.conditions]
|
||||||
|
|
||||||
trans_kind = 'not found'
|
|
||||||
if kind == 'color':
|
|
||||||
trans_kind = _('color')
|
|
||||||
else:
|
|
||||||
for tt, t in icon_rule_kinds:
|
|
||||||
if kind == t:
|
|
||||||
trans_kind = tt
|
|
||||||
break
|
|
||||||
|
|
||||||
return _('''\
|
return _('''\
|
||||||
<p>Set the <b>%(kind)s</b> of <b>%(col)s</b> to <b>%(color)s</b> if the following
|
<p>Set the <b>%(kind)s</b> of <b>%(col)s</b> to <b>%(color)s</b> if the following
|
||||||
conditions are met:</p>
|
conditions are met:</p>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user