Allow adding user specified icons to the main book list for books whose metadata matches set criteria. Go to Preferences->Look & Feel->Column icons to setup these icons

This commit is contained in:
Kovid Goyal 2013-01-28 15:52:42 +05:30
commit 6801bfb34d
5 changed files with 319 additions and 105 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -24,7 +24,7 @@ from calibre.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
from calibre.library.caches import (MetadataBackup, force_to_bool)
from calibre.library.save_to_disk import find_plugboard
from calibre import strftime, isbytestring
from calibre.constants import filesystem_encoding, DEBUG
from calibre.constants import filesystem_encoding, DEBUG, config_dir
from calibre.gui2.library import DEFAULT_SORT
from calibre.utils.localization import calibre_langcode_to_name
from calibre.library.coloring import color_row_key
@ -48,18 +48,20 @@ def default_image():
class ColumnColor(object):
def __init__(self):
def __init__(self, formatter, colors):
self.mi = None
self.formatter = formatter
self.colors = colors
def __call__(self, id_, key, fmt, db, formatter, color_cache, colors):
def __call__(self, id_, key, fmt, db, color_cache):
if id_ in color_cache and key in color_cache[id_]:
self.mi = None
return color_cache[id_][key]
try:
if self.mi is None:
self.mi = db.get_metadata(id_, index_is_id=True)
color = formatter.safe_format(fmt, self.mi, '', self.mi)
if color in colors:
color = self.formatter.safe_format(fmt, self.mi, '', self.mi)
if color in self.colors:
color = QColor(color)
if color.isValid():
color = QVariant(color)
@ -70,6 +72,36 @@ class ColumnColor(object):
pass
class ColumnIcon(object):
def __init__(self, formatter):
self.mi = None
self.formatter = formatter
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_]:
self.mi = None
return icon_cache[id_][dex]
try:
if self.mi is None:
self.mi = db.get_metadata(id_, index_is_id=True)
icon = self.formatter.safe_format(fmt, self.mi, '', self.mi)
if icon:
if icon in icon_bitmap_cache:
icon_bitmap = icon_bitmap_cache[icon]
icon_cache[id_][dex] = icon_bitmap
return icon_bitmap
d = os.path.join(config_dir, 'cc_icons', icon)
if (os.path.exists(d)):
icon_bitmap = QIcon(d)
icon_cache[id_][dex] = icon_bitmap
icon_bitmap_cache[icon] = icon_bitmap
self.mi = None
return icon
except:
pass
class BooksModel(QAbstractTableModel): # {{{
about_to_be_sorted = pyqtSignal(object, name='aboutToBeSorted')
@ -97,7 +129,13 @@ class BooksModel(QAbstractTableModel): # {{{
def __init__(self, parent=None, buffer=40):
QAbstractTableModel.__init__(self, parent)
self.db = None
self.column_color = ColumnColor()
self.formatter = SafeFormat()
self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
self._clear_caches()
self.column_color = ColumnColor(self.formatter, self.colors)
self.column_icon = ColumnIcon(self.formatter)
self.book_on_device = None
self.editable_cols = ['title', 'authors', 'rating', 'publisher',
'tags', 'series', 'timestamp', 'pubdate',
@ -109,8 +147,6 @@ class BooksModel(QAbstractTableModel): # {{{
self.column_map = []
self.headers = {}
self.alignment_map = {}
self.color_cache = defaultdict(dict)
self.color_row_fmt_cache = None
self.buffer_size = buffer
self.metadata_backup = None
self.bool_yes_icon = QIcon(I('ok.png'))
@ -121,10 +157,14 @@ class BooksModel(QAbstractTableModel): # {{{
self.ids_to_highlight_set = set()
self.current_highlighted_idx = None
self.highlight_only = False
self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
self.formatter = SafeFormat()
self.read_config()
def _clear_caches(self):
self.color_cache = defaultdict(dict)
self.icon_cache = defaultdict(dict)
self.icon_bitmap_cache = {}
self.color_row_fmt_cache = None
def change_alignment(self, colname, alignment):
if colname in self.column_map and alignment in ('left', 'right', 'center'):
old = self.alignment_map.get(colname, 'left')
@ -195,15 +235,13 @@ class BooksModel(QAbstractTableModel): # {{{
def refresh_ids(self, ids, current_row=-1):
self.color_cache = defaultdict(dict)
self.color_row_fmt_cache = None
self._clear_caches()
rows = self.db.refresh_ids(ids)
if rows:
self.refresh_rows(rows, current_row=current_row)
def refresh_rows(self, rows, current_row=-1):
self.color_cache = defaultdict(dict)
self.color_row_fmt_cache = None
self._clear_caches()
for row in rows:
if row == current_row:
self.new_bookdisplay_data.emit(
@ -234,8 +272,7 @@ class BooksModel(QAbstractTableModel): # {{{
return ret
def count_changed(self, *args):
self.color_cache = defaultdict(dict)
self.color_row_fmt_cache = None
self._clear_caches()
self.count_changed_signal.emit(self.db.count())
def row_indices(self, index):
@ -366,8 +403,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.resort(reset=reset)
def reset(self):
self.color_cache = defaultdict(dict)
self.color_row_fmt_cache = None
self._clear_caches()
QAbstractTableModel.reset(self)
def resort(self, reset=True):
@ -750,7 +786,23 @@ class BooksModel(QAbstractTableModel): # {{{
# we will get asked to display columns we don't know about. Must test for this.
if col >= len(self.column_to_dc_map):
return NONE
if role in (Qt.DisplayRole, Qt.EditRole, Qt.ToolTipRole):
if role == Qt.DisplayRole:
rules = self.db.prefs['column_icon_rules']
if rules:
key = self.column_map[col]
id_ = None
for kind, k, fmt in rules:
if k == key and kind == 'icon_only':
if id_ is None:
id_ = self.id(index)
self.column_icon.mi = None
ccicon = self.column_icon(id_, key, fmt, 'icon_only', self.db,
self.icon_cache, self.icon_bitmap_cache)
if ccicon is not None:
return NONE
self.icon_cache[id_][key+'icon_only'] = 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())
elif role == Qt.BackgroundRole:
if self.id(index) in self.ids_to_highlight_set:
@ -767,7 +819,7 @@ class BooksModel(QAbstractTableModel): # {{{
for k, fmt in self.db.prefs['column_color_rules']:
if k == key:
ccol = self.column_color(id_, key, fmt, self.db,
self.formatter, self.color_cache, self.colors)
self.color_cache)
if ccol is not None:
return ccol
@ -788,7 +840,7 @@ class BooksModel(QAbstractTableModel): # {{{
for fmt in self.color_row_fmt_cache:
ccol = self.column_color(id_, color_row_key, fmt, self.db,
self.formatter, self.color_cache, self.colors)
self.color_cache)
if ccol is not None:
return ccol
@ -796,7 +848,30 @@ class BooksModel(QAbstractTableModel): # {{{
return NONE
elif role == Qt.DecorationRole:
if self.column_to_dc_decorator_map[col] is not None:
return self.column_to_dc_decorator_map[index.column()](index.row())
ccicon = self.column_to_dc_decorator_map[index.column()](index.row())
if ccicon != NONE:
return ccicon
rules = self.db.prefs['column_icon_rules']
if rules:
key = self.column_map[col]
id_ = None
need_icon_with_text = False
for kind, k, fmt in rules:
if k == key and kind in ('icon', 'icon_only'):
if id_ is None:
id_ = self.id(index)
self.column_icon.mi = None
if kind == 'icon':
need_icon_with_text = True
ccicon = self.column_icon(id_, key, fmt, kind, 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
return self.bool_blank_icon
self.icon_cache[id_][key+'icon'] = None
elif role == Qt.TextAlignmentRole:
cname = self.column_map[index.column()]
ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname,

View File

@ -7,15 +7,18 @@ __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os
from PyQt4.Qt import (QWidget, QDialog, QLabel, QGridLayout, QComboBox, QSize,
QLineEdit, QIntValidator, QDoubleValidator, QFrame, QColor, Qt, QIcon,
QScrollArea, QPushButton, QVBoxLayout, QDialogButtonBox, QToolButton,
QListView, QAbstractListModel, pyqtSignal, QSizePolicy, QSpacerItem,
QApplication)
from calibre import prepare_string_for_xml
from calibre import prepare_string_for_xml, sanitize_file_name_unicode
from calibre.constants import config_dir
from calibre.utils.icu import sort_key
from calibre.gui2 import error_dialog
from calibre.gui2 import error_dialog, choose_files, pixmap_to_data
from calibre.gui2.dialogs.template_dialog import TemplateDialog
from calibre.gui2.metadata.single_download import RichTextDelegate
from calibre.library.coloring import (Rule, conditionable_columns,
@ -25,6 +28,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') ]
class ConditionEditor(QWidget): # {{{
ACTION_MAP = {
@ -207,8 +213,6 @@ class ConditionEditor(QWidget): # {{{
col = self.current_col
if not col:
return
m = self.fm[col]
dt = m['datatype']
action = self.current_action
if not action:
return
@ -245,64 +249,89 @@ class ConditionEditor(QWidget): # {{{
class RuleEditor(QDialog): # {{{
def __init__(self, fm, parent=None):
def __init__(self, fm, pref_name, parent=None):
QDialog.__init__(self, parent)
self.fm = fm
if pref_name == 'column_color_rules':
self.rule_kind = 'color'
rule_text = _('coloring')
else:
self.rule_kind = 'icon'
rule_text = _('icon')
self.setWindowIcon(QIcon(I('format-fill-color.png')))
self.setWindowTitle(_('Create/edit a column coloring rule'))
self.setWindowTitle(_('Create/edit a column {0} rule').format(rule_text))
self.l = l = QGridLayout(self)
self.setLayout(l)
self.l1 = l1 = QLabel(_('Create a coloring rule by'
' filling in the boxes below'))
l.addWidget(l1, 0, 0, 1, 5)
self.l1 = l1 = QLabel(_('Create a column {0} rule by'
' filling in the boxes below'.format(rule_text)))
l.addWidget(l1, 0, 0, 1, 8)
self.f1 = QFrame(self)
self.f1.setFrameShape(QFrame.HLine)
l.addWidget(self.f1, 1, 0, 1, 5)
l.addWidget(self.f1, 1, 0, 1, 8)
self.l2 = l2 = QLabel(_('Set the color of the column:'))
self.l2 = l2 = QLabel(_('Set the'))
l.addWidget(l2, 2, 0)
self.column_box = QComboBox(self)
l.addWidget(self.column_box, 2, 1)
if self.rule_kind == 'color':
l.addWidget(QLabel(_('color')))
else:
self.kind_box = QComboBox(self)
for tt, t in icon_rule_kinds:
self.kind_box.addItem(tt, t)
l.addWidget(self.kind_box, 2, 1)
self.l3 = l3 = QLabel(_('to'))
self.l3 = l3 = QLabel(_('of the column:'))
l.addWidget(l3, 2, 2)
self.color_box = QComboBox(self)
self.color_label = QLabel('Sample text Sample text')
self.color_label.setTextFormat(Qt.RichText)
l.addWidget(self.color_box, 2, 3)
l.addWidget(self.color_label, 2, 4)
l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 5)
self.column_box = QComboBox(self)
l.addWidget(self.column_box, 2, 3)
self.l4 = l4 = QLabel(
self.l4 = l4 = QLabel(_('to'))
l.addWidget(l4, 2, 4)
if self.rule_kind == 'color':
self.color_box = QComboBox(self)
self.color_label = QLabel('Sample text Sample text')
self.color_label.setTextFormat(Qt.RichText)
l.addWidget(self.color_box, 2, 5)
l.addWidget(self.color_label, 2, 6)
else:
self.filename_box = QLabel()
l.addWidget(self.filename_box, 2, 5)
self.filename_button = QPushButton(_('Choose icon'))
l.addWidget(self.filename_button, 2, 6)
l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 7)
self.l5 = l5 = QLabel(
_('Only if the following conditions are all satisfied:'))
l.addWidget(l4, 3, 0, 1, 6)
l.addWidget(l5, 3, 0, 1, 7)
self.scroll_area = sa = QScrollArea(self)
sa.setMinimumHeight(300)
sa.setMinimumWidth(950)
sa.setWidgetResizable(True)
l.addWidget(sa, 4, 0, 1, 6)
l.addWidget(sa, 4, 0, 1, 8)
self.add_button = b = QPushButton(QIcon(I('plus.png')),
_('Add another condition'))
l.addWidget(b, 5, 0, 1, 6)
l.addWidget(b, 5, 0, 1, 8)
b.clicked.connect(self.add_blank_condition)
self.l5 = l5 = QLabel(_('You can disable a condition by'
self.l6 = l6 = QLabel(_('You can disable a condition by'
' blanking all of its boxes'))
l.addWidget(l5, 6, 0, 1, 6)
l.addWidget(l6, 6, 0, 1, 8)
self.bb = bb = QDialogButtonBox(
QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
bb.accepted.connect(self.accept)
bb.rejected.connect(self.reject)
l.addWidget(bb, 7, 0, 1, 6)
l.addWidget(bb, 7, 0, 1, 8)
self.conditions_widget = QWidget(self)
sa.setWidget(self.conditions_widget)
@ -310,24 +339,32 @@ class RuleEditor(QDialog): # {{{
self.conditions_widget.layout().setAlignment(Qt.AlignTop)
self.conditions = []
for b in (self.column_box, self.color_box):
b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon)
b.setMinimumContentsLength(15)
if self.rule_kind == 'color':
for b in (self.column_box, self.color_box):
b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon)
b.setMinimumContentsLength(15)
for key in sorted(displayable_columns(fm),
key=lambda(k): sort_key(fm[k]['name']) if k != color_row_key else 0):
if key == color_row_key and self.rule_kind != 'color':
continue
name = all_columns_string if key == color_row_key else fm[key]['name']
if name:
self.column_box.addItem(name, key)
self.column_box.setCurrentIndex(0)
self.color_box.addItems(QColor.colorNames())
self.color_box.setCurrentIndex(0)
if self.rule_kind == 'color':
self.color_box.addItems(QColor.colorNames())
self.color_box.setCurrentIndex(0)
self.update_color_label()
self.color_box.currentIndexChanged.connect(self.update_color_label)
else:
self.filename_button.clicked.connect(self.filename_button_clicked)
self.update_color_label()
self.color_box.currentIndexChanged.connect(self.update_color_label)
self.resize(self.sizeHint())
self.icon_path = None
def update_color_label(self):
pal = QApplication.palette()
bg1 = unicode(pal.color(pal.Base).name())
@ -338,22 +375,54 @@ class RuleEditor(QDialog): # {{{
<span style="color: {c}; background-color: {bg2}">&nbsp;{st}&nbsp;</span>
'''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text')))
def filename_button_clicked(self):
try:
path = choose_files(self, 'choose_category_icon',
_('Select Icon'), filters=[
('Images', ['png', 'gif', 'jpg', 'jpeg'])],
all_files=False, select_only_single_file=True)
if path:
self.icon_path = path[0]
self.filename_box.setText(
sanitize_file_name_unicode(
os.path.splitext(
os.path.basename(self.icon_path))[0]+'.png'))
self.filename_box.adjustSize()
else:
self.icon_path = ''
except:
import traceback
traceback.print_exc()
return
def add_blank_condition(self):
c = ConditionEditor(self.fm, parent=self.conditions_widget)
self.conditions.append(c)
self.conditions_widget.layout().addWidget(c)
def apply_rule(self, col, rule):
def apply_rule(self, kind, col, rule):
if kind == 'color':
if rule.color:
idx = self.color_box.findText(rule.color)
if idx >= 0:
self.color_box.setCurrentIndex(idx)
else:
self.kind_box.setCurrentIndex(0 if kind == 'icon' else 1)
self.filename_box.setText(rule.color)
for i in range(self.column_box.count()):
c = unicode(self.column_box.itemData(i).toString())
if col == c:
self.column_box.setCurrentIndex(i)
break
if rule.color:
idx = self.color_box.findText(rule.color)
if idx >= 0:
self.color_box.setCurrentIndex(idx)
if kind == 'color':
idx = self.color_box.findText(rule.color)
if idx >= 0:
self.color_box.setCurrentIndex(idx)
else:
self.filename_box.setText(rule.color)
for c in rule.conditions:
ce = ConditionEditor(self.fm, parent=self.conditions_widget)
self.conditions.append(ce)
@ -366,6 +435,20 @@ class RuleEditor(QDialog): # {{{
def accept(self):
if self.rule_kind != 'color':
path = self.icon_path
if path:
try:
fname = unicode(self.filename_box.text())
p = QIcon(path).pixmap(QSize(128, 128))
d = os.path.join(config_dir, 'cc_icons')
if not os.path.exists(d):
os.makedirs(d)
with open(os.path.join(d, fname), 'wb') as f:
f.write(pixmap_to_data(p, format='PNG'))
except:
import traceback
traceback.print_exc()
if self.validate():
QDialog.accept(self)
@ -393,32 +476,54 @@ class RuleEditor(QDialog): # {{{
@property
def rule(self):
r = Rule(self.fm)
r.color = unicode(self.color_box.currentText())
if self.rule_kind != 'color':
r.color = unicode(self.filename_box.text())
else:
r.color = unicode(self.color_box.currentText())
idx = self.column_box.currentIndex()
col = unicode(self.column_box.itemData(idx).toString())
for c in self.conditions:
condition = c.condition
if condition is not None:
r.add_condition(*condition)
if self.rule_kind == 'icon':
kind = unicode(self.kind_box.itemData(
self.kind_box.currentIndex()).toString())
else:
kind = 'color'
return col, r
return kind, col, r
# }}}
class RulesModel(QAbstractListModel): # {{{
def __init__(self, prefs, fm, parent=None):
def __init__(self, prefs, fm, pref_name, parent=None):
QAbstractListModel.__init__(self, parent)
self.fm = fm
rules = list(prefs['column_color_rules'])
self.rules = []
for col, template in rules:
if col not in self.fm: continue
try:
rule = rule_from_template(self.fm, template)
except:
rule = template
self.rules.append((col, rule))
self.pref_name = pref_name
if pref_name == 'column_color_rules':
self.rule_kind = 'color'
rules = list(prefs[pref_name])
self.rules = []
for col, template in rules:
if col not in self.fm and col != color_row_key: continue
try:
rule = rule_from_template(self.fm, template)
except:
rule = template
self.rules.append(('color', col, rule))
else:
self.rule_kind = 'icon'
rules = list(prefs[pref_name])
self.rules = []
for kind, col, template in rules:
if col not in self.fm and col != color_row_key: continue
try:
rule = rule_from_template(self.fm, template)
except:
rule = template
self.rules.append((kind, col, rule))
def rowCount(self, *args):
return len(self.rules)
@ -426,7 +531,7 @@ class RulesModel(QAbstractListModel): # {{{
def data(self, index, role):
row = index.row()
try:
col, rule = self.rules[row]
kind, col, rule = self.rules[row]
except:
return None
if role == Qt.DisplayRole:
@ -434,17 +539,17 @@ class RulesModel(QAbstractListModel): # {{{
col = all_columns_string
else:
col = self.fm[col]['name']
return self.rule_to_html(col, rule)
return self.rule_to_html(kind, col, rule)
if role == Qt.UserRole:
return (col, rule)
return (kind, col, rule)
def add_rule(self, col, rule):
self.rules.append((col, rule))
def add_rule(self, kind, col, rule):
self.rules.append((kind, col, rule))
self.reset()
return self.index(len(self.rules)-1)
def replace_rule(self, index, col, r):
self.rules[index.row()] = (col, r)
def replace_rule(self, index, kind, col, r):
self.rules[index.row()] = (kind, col, r)
self.dataChanged.emit(index, index)
def remove_rule(self, index):
@ -453,12 +558,15 @@ class RulesModel(QAbstractListModel): # {{{
def commit(self, prefs):
rules = []
for col, r in self.rules:
for kind, col, r in self.rules:
if isinstance(r, Rule):
r = r.template
if r is not None:
rules.append((col, r))
prefs['column_color_rules'] = rules
if kind == 'color':
rules.append((col, r))
else:
rules.append((kind, col, r))
prefs[self.pref_name] = rules
def move(self, idx, delta):
row = idx.row() + delta
@ -475,18 +583,28 @@ class RulesModel(QAbstractListModel): # {{{
self.rules = []
self.reset()
def rule_to_html(self, col, rule):
def rule_to_html(self, kind, col, rule):
if not isinstance(rule, Rule):
return _('''
<p>Advanced Rule for column <b>%(col)s</b>:
<pre>%(rule)s</pre>
''')%dict(col=col, 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 color 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>
<ul>%(rule)s</ul>
''') % dict(col=col, color=rule.color, rule=''.join(conditions))
''') % dict(kind=trans_kind, col=col, color=rule.color, rule=''.join(conditions))
def condition_to_html(self, condition):
c, a, v = condition
@ -513,12 +631,7 @@ class EditRules(QWidget): # {{{
self.l = l = QGridLayout(self)
self.setLayout(l)
self.l1 = l1 = QLabel('<p>'+_(
'You can control the color of columns in the'
' book list by creating "rules" that tell calibre'
' what color to use. Click the Add Rule button below'
' to get started.<p>You can <b>change an existing rule</b> by double'
' clicking it.'))
self.l1 = l1 = QLabel('')
l1.setWordWrap(True)
l.addWidget(l1, 0, 0, 1, 2)
@ -559,22 +672,38 @@ class EditRules(QWidget): # {{{
b.clicked.connect(self.add_advanced)
l.addWidget(b, 3, 0, 1, 2)
def initialize(self, fm, prefs, mi):
self.model = RulesModel(prefs, fm)
def initialize(self, fm, prefs, mi, pref_name):
self.pref_name = pref_name
self.model = RulesModel(prefs, fm, self.pref_name)
self.rules_view.setModel(self.model)
self.fm = fm
self.mi = mi
if pref_name == 'column_color_rules':
self.l1.setText('<p>'+_(
'You can control the color of columns in the'
' book list by creating "rules" that tell calibre'
' what color to use. Click the Add Rule button below'
' to get started.<p>You can <b>change an existing rule</b> by'
' double clicking it.'))
else:
self.l1.setText('<p>'+_(
'You can add icons to columns in the'
' book list by creating "rules" that tell calibre'
' what icon to use. Click the Add Rule button below'
' to get started.<p>You can <b>change an existing rule</b> by'
' double clicking it.'))
self.add_advanced_button.setVisible(False)
def _add_rule(self, dlg):
if dlg.exec_() == dlg.Accepted:
col, r = dlg.rule
if r and col:
idx = self.model.add_rule(col, r)
kind, col, r = dlg.rule
if kind and r and col:
idx = self.model.add_rule(kind, col, r)
self.rules_view.scrollTo(idx)
self.changed.emit()
def add_rule(self):
d = RuleEditor(self.model.fm)
d = RuleEditor(self.model.fm, self.pref_name)
d.add_blank_condition()
self._add_rule(d)
@ -584,18 +713,18 @@ class EditRules(QWidget): # {{{
def edit_rule(self, index):
try:
col, rule = self.model.data(index, Qt.UserRole)
kind, col, rule = self.model.data(index, Qt.UserRole)
except:
return
if isinstance(rule, Rule):
d = RuleEditor(self.model.fm)
d.apply_rule(col, rule)
d = RuleEditor(self.model.fm, self.pref_name)
d.apply_rule(kind, col, rule)
else:
d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, color_field=col)
if d.exec_() == d.Accepted:
col, r = d.rule
if r is not None and col:
self.model.replace_rule(index, col, r)
kind, col, r = d.rule
if kind and r is not None and col:
self.model.replace_rule(index, kind, col, r)
self.rules_view.scrollTo(index)
self.changed.emit()
@ -651,7 +780,7 @@ if __name__ == '__main__':
db = db()
if True:
d = RuleEditor(db.field_metadata)
d = RuleEditor(db.field_metadata, 'column_color_rules')
d.add_blank_condition()
d.exec_()

View File

@ -181,6 +181,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.edit_rules.changed.connect(self.changed_signal)
self.tabWidget.addTab(self.edit_rules,
QIcon(I('format-fill-color.png')), _('Column coloring'))
self.icon_rules = EditRules(self.tabWidget)
self.icon_rules.changed.connect(self.changed_signal)
self.tabWidget.addTab(self.icon_rules,
QIcon(I('icon_choose.png')), _('Column icons'))
self.tabWidget.setCurrentIndex(0)
keys = [QKeySequence('F11', QKeySequence.PortableText), QKeySequence(
'Ctrl+Shift+F', QKeySequence.PortableText)]
@ -203,7 +209,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
mi = db.get_metadata(idx, index_is_id=False)
except:
mi=None
self.edit_rules.initialize(db.field_metadata, db.prefs, mi)
self.edit_rules.initialize(db.field_metadata, db.prefs, mi, 'column_color_rules')
self.icon_rules.initialize(db.field_metadata, db.prefs, mi, 'column_icon_rules')
def restore_defaults(self):
ConfigWidgetBase.restore_defaults(self)
@ -214,6 +221,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.update_font_display()
self.display_model.restore_defaults()
self.edit_rules.clear()
self.icon_rules.clear()
self.changed_signal.emit()
def build_font_obj(self):
@ -273,6 +281,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
rr = True
self.display_model.commit()
self.edit_rules.commit(self.gui.current_db.prefs)
self.icon_rules.commit(self.gui.current_db.prefs)
return rr
def refresh_gui(self, gui):

View File

@ -211,6 +211,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
defs['gui_restriction'] = defs['cs_restriction'] = ''
defs['categories_using_hierarchy'] = []
defs['column_color_rules'] = []
defs['column_icon_rules'] = []
defs['grouped_search_make_user_categories'] = []
defs['similar_authors_search_key'] = 'authors'
defs['similar_authors_match_kind'] = 'match_any'