Use coloring rules to change cells from text to icons

This commit is contained in:
Charles Haley 2013-01-26 15:25:17 +01:00
parent f606af13a1
commit 845b90e865
3 changed files with 207 additions and 51 deletions

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.caches import (MetadataBackup, force_to_bool)
from calibre.library.save_to_disk import find_plugboard from calibre.library.save_to_disk import find_plugboard
from calibre import strftime, isbytestring 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.gui2.library import DEFAULT_SORT
from calibre.utils.localization import calibre_langcode_to_name from calibre.utils.localization import calibre_langcode_to_name
from calibre.library.coloring import color_row_key from calibre.library.coloring import color_row_key
@ -70,6 +70,30 @@ class ColumnColor(object):
pass pass
class ColumnIcon(object):
def __init__(self):
self.mi = None
def __call__(self, id_, key, fmt, kind, db, formatter, icon_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 = formatter.safe_format(fmt, self.mi, '', self.mi)
if icon:
d = os.path.join(config_dir, 'cc_icons', icon)
if (os.path.exists(d)):
icon = QIcon(d)
icon_cache[id_][dex] = icon
self.mi = None
return icon
except:
pass
class BooksModel(QAbstractTableModel): # {{{ class BooksModel(QAbstractTableModel): # {{{
about_to_be_sorted = pyqtSignal(object, name='aboutToBeSorted') about_to_be_sorted = pyqtSignal(object, name='aboutToBeSorted')
@ -98,6 +122,7 @@ class BooksModel(QAbstractTableModel): # {{{
QAbstractTableModel.__init__(self, parent) QAbstractTableModel.__init__(self, parent)
self.db = None self.db = None
self.column_color = ColumnColor() self.column_color = ColumnColor()
self.column_icon = ColumnIcon()
self.book_on_device = None self.book_on_device = None
self.editable_cols = ['title', 'authors', 'rating', 'publisher', self.editable_cols = ['title', 'authors', 'rating', 'publisher',
'tags', 'series', 'timestamp', 'pubdate', 'tags', 'series', 'timestamp', 'pubdate',
@ -110,6 +135,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.headers = {} self.headers = {}
self.alignment_map = {} self.alignment_map = {}
self.color_cache = defaultdict(dict) self.color_cache = defaultdict(dict)
self.icon_cache = defaultdict(dict)
self.color_row_fmt_cache = None self.color_row_fmt_cache = None
self.buffer_size = buffer self.buffer_size = buffer
self.metadata_backup = None self.metadata_backup = None
@ -196,6 +222,7 @@ class BooksModel(QAbstractTableModel): # {{{
def refresh_ids(self, ids, current_row=-1): def refresh_ids(self, ids, current_row=-1):
self.color_cache = defaultdict(dict) self.color_cache = defaultdict(dict)
self.icon_cache = defaultdict(dict)
self.color_row_fmt_cache = None self.color_row_fmt_cache = None
rows = self.db.refresh_ids(ids) rows = self.db.refresh_ids(ids)
if rows: if rows:
@ -203,6 +230,7 @@ class BooksModel(QAbstractTableModel): # {{{
def refresh_rows(self, rows, current_row=-1): def refresh_rows(self, rows, current_row=-1):
self.color_cache = defaultdict(dict) self.color_cache = defaultdict(dict)
self.icon_cache = defaultdict(dict)
self.color_row_fmt_cache = None self.color_row_fmt_cache = None
for row in rows: for row in rows:
if row == current_row: if row == current_row:
@ -235,6 +263,7 @@ class BooksModel(QAbstractTableModel): # {{{
def count_changed(self, *args): def count_changed(self, *args):
self.color_cache = defaultdict(dict) self.color_cache = defaultdict(dict)
self.icon_cache = defaultdict(dict)
self.color_row_fmt_cache = None self.color_row_fmt_cache = None
self.count_changed_signal.emit(self.db.count()) self.count_changed_signal.emit(self.db.count())
@ -367,6 +396,7 @@ class BooksModel(QAbstractTableModel): # {{{
def reset(self): def reset(self):
self.color_cache = defaultdict(dict) self.color_cache = defaultdict(dict)
self.icon_cache = defaultdict(dict)
self.color_row_fmt_cache = None self.color_row_fmt_cache = None
QAbstractTableModel.reset(self) QAbstractTableModel.reset(self)
@ -750,7 +780,18 @@ class BooksModel(QAbstractTableModel): # {{{
# we will get asked to display columns we don't know about. Must test for this. # we will get asked to display columns we don't know about. Must test for this.
if col >= len(self.column_to_dc_map): if col >= len(self.column_to_dc_map):
return NONE return NONE
if role in (Qt.DisplayRole, Qt.EditRole, Qt.ToolTipRole): if role == Qt.DisplayRole:
key = self.column_map[col]
id_ = self.id(index)
self.column_icon.mi = None
for kind, k, fmt in self.db.prefs['column_color_rules']:
if k == key and kind == 'icon_only':
ccicon = self.column_icon(id_, key, fmt, kind, self.db,
self.formatter, self.icon_cache)
if ccicon is not None:
return 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()) return self.column_to_dc_map[col](index.row())
elif role == Qt.BackgroundRole: elif role == Qt.BackgroundRole:
if self.id(index) in self.ids_to_highlight_set: if self.id(index) in self.ids_to_highlight_set:
@ -761,11 +802,12 @@ class BooksModel(QAbstractTableModel): # {{{
self.column_color.mi = None self.column_color.mi = None
if self.color_row_fmt_cache is None: if self.color_row_fmt_cache is None:
self.color_row_fmt_cache = tuple(fmt for key, fmt in self.color_row_fmt_cache = tuple(fmt for kind, key, fmt in
self.db.prefs['column_color_rules'] if key == color_row_key) self.db.prefs['column_color_rules'] if kind == 'color' and
key == color_row_key)
for k, fmt in self.db.prefs['column_color_rules']: for kind, k, fmt in self.db.prefs['column_color_rules']:
if k == key: if k == key and kind == 'color':
ccol = self.column_color(id_, key, fmt, self.db, ccol = self.column_color(id_, key, fmt, self.db,
self.formatter, self.color_cache, self.colors) self.formatter, self.color_cache, self.colors)
if ccol is not None: if ccol is not None:
@ -796,7 +838,23 @@ class BooksModel(QAbstractTableModel): # {{{
return NONE return NONE
elif role == Qt.DecorationRole: elif role == Qt.DecorationRole:
if self.column_to_dc_decorator_map[col] is not None: 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
key = self.column_map[col]
id_ = self.id(index)
self.column_icon.mi = None
need_icon_with_text = False
for kind, k, fmt in self.db.prefs['column_color_rules']:
if k == key and kind in ('icon', 'icon_only'):
need_icon_with_text = True
ccicon = self.column_icon(id_, key, fmt, kind, self.db,
self.formatter, self.icon_cache)
if ccicon is not None:
return ccicon
if need_icon_with_text:
return self.bool_blank_icon
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,

View File

@ -7,15 +7,18 @@ __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os
from PyQt4.Qt import (QWidget, QDialog, QLabel, QGridLayout, QComboBox, QSize, from PyQt4.Qt import (QWidget, QDialog, QLabel, QGridLayout, QComboBox, QSize,
QLineEdit, QIntValidator, QDoubleValidator, QFrame, QColor, Qt, QIcon, QLineEdit, QIntValidator, QDoubleValidator, QFrame, QColor, Qt, QIcon,
QScrollArea, QPushButton, QVBoxLayout, QDialogButtonBox, QToolButton, QScrollArea, QPushButton, QVBoxLayout, QDialogButtonBox, QToolButton,
QListView, QAbstractListModel, pyqtSignal, QSizePolicy, QSpacerItem, QListView, QAbstractListModel, pyqtSignal, QSizePolicy, QSpacerItem,
QApplication) QApplication, QHBoxLayout)
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.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.dialogs.template_dialog import TemplateDialog
from calibre.gui2.metadata.single_download import RichTextDelegate from calibre.gui2.metadata.single_download import RichTextDelegate
from calibre.library.coloring import (Rule, conditionable_columns, from calibre.library.coloring import (Rule, conditionable_columns,
@ -257,52 +260,67 @@ class RuleEditor(QDialog): # {{{
self.l1 = l1 = QLabel(_('Create a coloring rule by' self.l1 = l1 = QLabel(_('Create a coloring rule by'
' filling in the boxes below')) ' filling in the boxes below'))
l.addWidget(l1, 0, 0, 1, 5) l.addWidget(l1, 0, 0, 1, 8)
self.f1 = QFrame(self) self.f1 = QFrame(self)
self.f1.setFrameShape(QFrame.HLine) 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) l.addWidget(l2, 2, 0)
self.column_box = QComboBox(self) self.kind_box = QComboBox(self)
l.addWidget(self.column_box, 2, 1) self.kind_box.addItem(_('color'), 'color')
self.kind_box.addItem(_('icon'), 'icon')
self.kind_box.addItem(_('icon with no text'), 'icon_only')
l.addWidget(self.kind_box, 2, 1)
self.l3 = l3 = QLabel(_('to')) self.l3 = l3 = QLabel(_('of the column:'))
l.addWidget(l3, 2, 2) l.addWidget(l3, 2, 2)
self.column_box = QComboBox(self)
l.addWidget(self.column_box, 2, 3)
self.l4 = l4 = QLabel(_('to'))
l.addWidget(l4, 2, 4)
self.color_box = QComboBox(self) self.color_box = QComboBox(self)
self.color_label = QLabel('Sample text Sample text') self.color_label = QLabel('Sample text Sample text')
self.color_label.setTextFormat(Qt.RichText) self.color_label.setTextFormat(Qt.RichText)
l.addWidget(self.color_box, 2, 3) l.addWidget(self.color_box, 2, 5)
l.addWidget(self.color_label, 2, 4) l.addWidget(self.color_label, 2, 6)
l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 5)
self.l4 = l4 = QLabel( 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:')) _('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) self.scroll_area = sa = QScrollArea(self)
sa.setMinimumHeight(300) sa.setMinimumHeight(300)
sa.setMinimumWidth(950) sa.setMinimumWidth(950)
sa.setWidgetResizable(True) 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')), self.add_button = b = QPushButton(QIcon(I('plus.png')),
_('Add another condition')) _('Add another condition'))
l.addWidget(b, 5, 0, 1, 6) l.addWidget(b, 5, 0, 1, 8)
b.clicked.connect(self.add_blank_condition) 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')) ' blanking all of its boxes'))
l.addWidget(l5, 6, 0, 1, 6) l.addWidget(l6, 6, 0, 1, 8)
self.bb = bb = QDialogButtonBox( self.bb = bb = QDialogButtonBox(
QDialogButtonBox.Ok|QDialogButtonBox.Cancel) QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
bb.accepted.connect(self.accept) bb.accepted.connect(self.accept)
bb.rejected.connect(self.reject) bb.rejected.connect(self.reject)
l.addWidget(bb, 7, 0, 1, 6) l.addWidget(bb, 7, 0, 1, 8)
self.conditions_widget = QWidget(self) self.conditions_widget = QWidget(self)
sa.setWidget(self.conditions_widget) sa.setWidget(self.conditions_widget)
@ -326,8 +344,12 @@ class RuleEditor(QDialog): # {{{
self.update_color_label() self.update_color_label()
self.color_box.currentIndexChanged.connect(self.update_color_label) self.color_box.currentIndexChanged.connect(self.update_color_label)
self.kind_box.currentIndexChanged[int].connect(self.kind_index_changed)
self.filename_button.clicked.connect(self.filename_button_clicked)
self.resize(self.sizeHint()) self.resize(self.sizeHint())
self.icon_path = None
def update_color_label(self): def update_color_label(self):
pal = QApplication.palette() pal = QApplication.palette()
bg1 = unicode(pal.color(pal.Base).name()) bg1 = unicode(pal.color(pal.Base).name())
@ -338,13 +360,58 @@ class RuleEditor(QDialog): # {{{
<span style="color: {c}; background-color: {bg2}">&nbsp;{st}&nbsp;</span> <span style="color: {c}; background-color: {bg2}">&nbsp;{st}&nbsp;</span>
'''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text'))) '''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text')))
def kind_index_changed(self, dex):
if dex != 0:
self.color_label.setVisible(False)
self.color_box.setVisible(False)
self.filename_box.setVisible(True)
self.filename_button.setVisible(True)
else:
self.color_label.setVisible(True)
self.color_box.setVisible(True)
self.filename_box.setVisible(False)
self.filename_button.setVisible(False)
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): def add_blank_condition(self):
c = ConditionEditor(self.fm, parent=self.conditions_widget) c = ConditionEditor(self.fm, parent=self.conditions_widget)
self.conditions.append(c) self.conditions.append(c)
self.conditions_widget.layout().addWidget(c) self.conditions_widget.layout().addWidget(c)
def apply_rule(self, col, rule): def apply_rule(self, kind, col, rule):
if kind == 'color':
self.kind_box.setCurrentIndex(0)
self.filename_box.setVisible(False)
self.filename_button.setVisible(False)
if rule.color:
idx = self.color_box.findText(rule.color)
if idx >= 0:
self.color_box.setCurrentIndex(idx)
else:
self.kind_box.setCurrentIndex(1 if kind == 'icon' else 2)
self.color_box.setVisible(False)
self.color_label.setVisible(False)
self.filename_box.setText(rule.color)
for i in range(self.column_box.count()): for i in range(self.column_box.count()):
c = unicode(self.column_box.itemData(i).toString()) c = unicode(self.column_box.itemData(i).toString())
if col == c: if col == c:
@ -354,6 +421,8 @@ class RuleEditor(QDialog): # {{{
idx = self.color_box.findText(rule.color) idx = self.color_box.findText(rule.color)
if idx >= 0: if idx >= 0:
self.color_box.setCurrentIndex(idx) self.color_box.setCurrentIndex(idx)
self.filename_box.setText(rule.color)
for c in rule.conditions: for c in rule.conditions:
ce = ConditionEditor(self.fm, parent=self.conditions_widget) ce = ConditionEditor(self.fm, parent=self.conditions_widget)
self.conditions.append(ce) self.conditions.append(ce)
@ -366,6 +435,20 @@ class RuleEditor(QDialog): # {{{
def accept(self): def accept(self):
if self.kind_box.currentIndex() != 0:
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(): if self.validate():
QDialog.accept(self) QDialog.accept(self)
@ -393,6 +476,10 @@ class RuleEditor(QDialog): # {{{
@property @property
def rule(self): def rule(self):
r = Rule(self.fm) r = Rule(self.fm)
kind = unicode(self.kind_box.itemData(self.kind_box.currentIndex()).toString())
if kind != 'color':
r.color = unicode(self.filename_box.text())
else:
r.color = unicode(self.color_box.currentText()) r.color = unicode(self.color_box.currentText())
idx = self.column_box.currentIndex() idx = self.column_box.currentIndex()
col = unicode(self.column_box.itemData(idx).toString()) col = unicode(self.column_box.itemData(idx).toString())
@ -401,7 +488,7 @@ class RuleEditor(QDialog): # {{{
if condition is not None: if condition is not None:
r.add_condition(*condition) r.add_condition(*condition)
return col, r return kind, col, r
# }}} # }}}
class RulesModel(QAbstractListModel): # {{{ class RulesModel(QAbstractListModel): # {{{
@ -412,13 +499,13 @@ class RulesModel(QAbstractListModel): # {{{
self.fm = fm self.fm = fm
rules = list(prefs['column_color_rules']) rules = list(prefs['column_color_rules'])
self.rules = [] self.rules = []
for col, template in rules: for kind, col, template in rules:
if col not in self.fm: continue if col not in self.fm: continue
try: try:
rule = rule_from_template(self.fm, template) rule = rule_from_template(self.fm, template)
except: except:
rule = template rule = template
self.rules.append((col, rule)) self.rules.append((kind, col, rule))
def rowCount(self, *args): def rowCount(self, *args):
return len(self.rules) return len(self.rules)
@ -426,7 +513,7 @@ class RulesModel(QAbstractListModel): # {{{
def data(self, index, role): def data(self, index, role):
row = index.row() row = index.row()
try: try:
col, rule = self.rules[row] kind, col, rule = self.rules[row]
except: except:
return None return None
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
@ -434,17 +521,17 @@ class RulesModel(QAbstractListModel): # {{{
col = all_columns_string col = all_columns_string
else: else:
col = self.fm[col]['name'] col = self.fm[col]['name']
return self.rule_to_html(col, rule) return self.rule_to_html(kind, col, rule)
if role == Qt.UserRole: if role == Qt.UserRole:
return (col, rule) return (kind, col, rule)
def add_rule(self, col, rule): def add_rule(self, kind, col, rule):
self.rules.append((col, rule)) self.rules.append((kind, col, rule))
self.reset() self.reset()
return self.index(len(self.rules)-1) return self.index(len(self.rules)-1)
def replace_rule(self, index, col, r): def replace_rule(self, index, kind, col, r):
self.rules[index.row()] = (col, r) self.rules[index.row()] = (kind, col, r)
self.dataChanged.emit(index, index) self.dataChanged.emit(index, index)
def remove_rule(self, index): def remove_rule(self, index):
@ -453,11 +540,11 @@ class RulesModel(QAbstractListModel): # {{{
def commit(self, prefs): def commit(self, prefs):
rules = [] rules = []
for col, r in self.rules: for kind, col, r in self.rules:
if isinstance(r, Rule): if isinstance(r, Rule):
r = r.template r = r.template
if r is not None: if r is not None:
rules.append((col, r)) rules.append((kind, col, r))
prefs['column_color_rules'] = rules prefs['column_color_rules'] = rules
def move(self, idx, delta): def move(self, idx, delta):
@ -475,7 +562,7 @@ class RulesModel(QAbstractListModel): # {{{
self.rules = [] self.rules = []
self.reset() self.reset()
def rule_to_html(self, col, rule): def rule_to_html(self, kind, col, rule):
if not isinstance(rule, Rule): if not isinstance(rule, Rule):
return _(''' return _('''
<p>Advanced Rule for column <b>%(col)s</b>: <p>Advanced Rule for column <b>%(col)s</b>:
@ -483,10 +570,10 @@ class RulesModel(QAbstractListModel): # {{{
''')%dict(col=col, rule=prepare_string_for_xml(rule)) ''')%dict(col=col, 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]
return _('''\ 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> conditions are met:</p>
<ul>%(rule)s</ul> <ul>%(rule)s</ul>
''') % dict(col=col, color=rule.color, rule=''.join(conditions)) ''') % dict(kind=kind, col=col, color=rule.color, rule=''.join(conditions))
def condition_to_html(self, condition): def condition_to_html(self, condition):
c, a, v = condition c, a, v = condition
@ -567,9 +654,9 @@ class EditRules(QWidget): # {{{
def _add_rule(self, dlg): def _add_rule(self, dlg):
if dlg.exec_() == dlg.Accepted: if dlg.exec_() == dlg.Accepted:
col, r = dlg.rule kind, col, r = dlg.rule
if r and col: if kind and r and col:
idx = self.model.add_rule(col, r) idx = self.model.add_rule(kind, col, r)
self.rules_view.scrollTo(idx) self.rules_view.scrollTo(idx)
self.changed.emit() self.changed.emit()
@ -584,18 +671,18 @@ class EditRules(QWidget): # {{{
def edit_rule(self, index): def edit_rule(self, index):
try: try:
col, rule = self.model.data(index, Qt.UserRole) kind, col, rule = self.model.data(index, Qt.UserRole)
except: except:
return return
if isinstance(rule, Rule): if isinstance(rule, Rule):
d = RuleEditor(self.model.fm) d = RuleEditor(self.model.fm)
d.apply_rule(col, rule) d.apply_rule(kind, col, rule)
else: else:
d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, color_field=col) d = TemplateDialog(self, rule, mi=self.mi, fm=self.fm, color_field=col)
if d.exec_() == d.Accepted: if d.exec_() == d.Accepted:
col, r = d.rule kind, col, r = d.rule
if r is not None and col: if kind and r is not None and col:
self.model.replace_rule(index, col, r) self.model.replace_rule(index, kind, col, r)
self.rules_view.scrollTo(index) self.rules_view.scrollTo(index)
self.changed.emit() self.changed.emit()

View File

@ -253,6 +253,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if old_rules: if old_rules:
self.prefs['column_color_rules'] += old_rules self.prefs['column_color_rules'] += old_rules
new_rules = []
must_save_new_rules = False
for tup in self.prefs['column_color_rules']:
if len(tup) == 2:
must_save_new_rules = True;
new_rules.append( ('color', tup[0], tup[1]) )
else:
new_rules.append(tup)
if must_save_new_rules:
self.prefs['column_color_rules'] = new_rules
# Migrate saved search and user categories to db preference scheme # Migrate saved search and user categories to db preference scheme
def migrate_preference(key, default): def migrate_preference(key, default):
oldval = prefs[key] oldval = prefs[key]