Make icon rules composable.

This commit is contained in:
Charles Haley 2013-09-17 14:29:08 +02:00
parent 9c3e61cee2
commit 2fe01db004
4 changed files with 91 additions and 76 deletions

View File

@ -7,7 +7,7 @@ import json, os, traceback
from PyQt4.Qt import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont,
QRegExp, QApplication, QTextCharFormat, QColor, QCursor,
QIcon, QSize)
QIcon, QSize, QVariant)
from calibre import sanitize_file_name_unicode
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.gui2 import error_dialog, choose_files, pixmap_to_data
class ParenPosition:
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.sort(key=sort_key)
self.update_filename_box()
self.icon_with_text.setChecked(True)
if icon_rule_kind == 'icon_only':
self.icon_without_text.setChecked(True)
dex = 0
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))
if mi:
@ -410,7 +415,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
self.rule = (unicode(self.colored_field.itemData(
self.colored_field.currentIndex()).toString()), txt)
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,
unicode(self.icon_field.itemData(
self.icon_field.currentIndex()).toString()),

View File

@ -69,33 +69,19 @@
<widget class="QWidget" name="icon_layout">
<layout class="QGridLayout">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox">
<property name="title">
<string>Kind</string>
</property>
<layout class="QHBoxLayout">
<item>
<widget class="QRadioButton" name="icon_without_text">
<widget class="QLabel">
<property name="text">
<string>icon with no text</string>
<string>Kind:</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="icon_with_text">
<property name="text">
<string>icon with text</string>
</property>
<widget class="QComboBox" name="icon_kind">
</widget>
</item>
</layout>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>100</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="icon_chooser_label">

View File

@ -81,38 +81,49 @@ class ColumnIcon(object): # {{{
self.formatter = formatter
self.model = model
def __call__(self, id_, key, fmt, kind, db, icon_cache, icon_bitmap_cache):
dex = key+kind
if id_ in icon_cache and dex in icon_cache[id_]:
def __call__(self, id_, key, fmts, cache_index, db, icon_cache, icon_bitmap_cache):
if id_ in icon_cache and cache_index in icon_cache[id_]:
self.mi = None
return icon_cache[id_][dex]
return icon_cache[id_][cache_index]
try:
if self.mi is None:
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 in icon_bitmap_cache:
icon_bitmap = icon_bitmap_cache[icons]
icon_cache[id_][dex] = icon_bitmap
icon_string = ':'.join(icons)
if icon_string in icon_bitmap_cache:
icon_bitmap = icon_bitmap_cache[icon_string]
icon_cache[id_][cache_index] = icon_bitmap
return icon_bitmap
icon_list = [ic.strip() for ic in icons.split(':')]
icon_bitmaps = []
total_width = 0
for icon in icon_list:
for icon in icons:
d = os.path.join(config_dir, 'cc_icons', icon)
if (os.path.exists(d)):
bm = QPixmap(d)
icon_bitmaps.append(bm)
total_width += bm.width()
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)
painter = QPainter(result)
x = 0
for bm in icon_bitmaps:
painter.drawPixmap(x, 0, bm)
x += bm.width()
x += bm.width() + 2
painter.end()
else:
result = icon_bitmaps[0]
@ -123,8 +134,8 @@ class ColumnIcon(object): # {{{
rh = max(2, self.model.row_height - 2)
if result.height() > rh:
result = result.scaledToHeight(rh, mode=Qt.SmoothTransformation)
icon_cache[id_][dex] = result
icon_bitmap_cache[icons] = result
icon_cache[id_][cache_index] = result
icon_bitmap_cache[icon_string] = result
self.mi = None
return result
except:
@ -788,16 +799,21 @@ class BooksModel(QAbstractTableModel): # {{{
if rules:
key = self.column_map[col]
id_ = None
fmts = []
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:
id_ = self.id(index)
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)
if ccicon is not 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())
elif role in (Qt.EditRole, Qt.ToolTipRole):
return self.column_to_dc_map[col](index.row())
@ -854,21 +870,25 @@ class BooksModel(QAbstractTableModel): # {{{
key = self.column_map[col]
id_ = None
need_icon_with_text = False
fmts = []
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:
id_ = self.id(index)
self.column_icon.mi = None
if kind == 'icon':
fmts.append((kind, fmt))
if kind in ('icon', 'icon_composed'):
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)
if ccicon is not None:
return ccicon
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
self.icon_cache[id_][key+'icon'] = None
self.icon_cache[id_][cache_index] = None
elif role == Qt.TextAlignmentRole:
cname = self.column_map[index.column()]
ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname,

View File

@ -29,7 +29,9 @@ from calibre.utils.icu import lower
all_columns_string = _('All Columns')
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): # {{{
@ -526,7 +528,10 @@ class RuleEditor(QDialog): # {{{
if idx >= 0:
self.color_box.setCurrentIndex(idx)
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(':')]
if len(self.rule_icon_files) > 1:
self.multiple_icon_cb.setChecked(True)
@ -691,6 +696,15 @@ class RulesModel(QAbstractListModel): # {{{
self.reset()
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 kind == 'color':
return _('''
@ -702,21 +716,11 @@ class RulesModel(QAbstractListModel): # {{{
<p>Advanced Rule: set <b>%(typ)s</b> for column <b>%(col)s</b>:
<pre>%(rule)s</pre>
''')%dict(col=col,
typ=icon_rule_kinds[0][0]
if kind == icon_rule_kinds[0][1] else icon_rule_kinds[1][0],
typ=trans_kind,
rule=prepare_string_for_xml(rule))
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 _('''\
<p>Set the <b>%(kind)s</b> of <b>%(col)s</b> to <b>%(color)s</b> if the following
conditions are met:</p>