Put column icons into separate rules and a separate preference.

This commit is contained in:
Charles Haley 2013-01-27 22:36:41 +01:00
parent 316a9539d8
commit e758b9fe42
4 changed files with 138 additions and 119 deletions

View File

@ -781,16 +781,18 @@ class BooksModel(QAbstractTableModel): # {{{
if col >= len(self.column_to_dc_map): if col >= len(self.column_to_dc_map):
return NONE return NONE
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
key = self.column_map[col] rules = self.db.prefs['column_icon_rules']
id_ = self.id(index) if rules:
self.column_icon.mi = None key = self.column_map[col]
for kind, k, fmt in self.db.prefs['column_color_rules']: id_ = self.id(index)
if k == key and kind == 'icon_only': self.column_icon.mi = None
ccicon = self.column_icon(id_, key, fmt, 'icon_only', self.db, for kind, k, fmt in rules:
self.formatter, self.icon_cache) if k == key and kind == 'icon_only':
if ccicon is not None: ccicon = self.column_icon(id_, key, fmt, 'icon_only', self.db,
return NONE self.formatter, self.icon_cache)
self.icon_cache[id_][key+'icon_only'] = None if ccicon is not None:
return NONE
self.icon_cache[id_][key+'icon_only'] = 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())
@ -803,12 +805,11 @@ 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 kind, key, fmt in self.color_row_fmt_cache = tuple(fmt for key, fmt in
self.db.prefs['column_color_rules'] if kind == 'color' and self.db.prefs['column_color_rules'] if key == color_row_key)
key == color_row_key)
for kind, k, fmt in self.db.prefs['column_color_rules']: for k, fmt in self.db.prefs['column_color_rules']:
if k == key and kind == 'color': if k == key:
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:
@ -843,22 +844,24 @@ class BooksModel(QAbstractTableModel): # {{{
if ccicon != NONE: if ccicon != NONE:
return ccicon return ccicon
key = self.column_map[col] rules = self.db.prefs['column_icon_rules']
id_ = self.id(index) if rules:
self.column_icon.mi = None key = self.column_map[col]
need_icon_with_text = False id_ = self.id(index)
for kind, k, fmt in self.db.prefs['column_color_rules']: self.column_icon.mi = None
if k == key and kind in ('icon', 'icon_only'): need_icon_with_text = False
if kind == 'icon': for kind, k, fmt in rules:
need_icon_with_text = True if k == key and kind in ('icon', 'icon_only'):
ccicon = self.column_icon(id_, key, fmt, 'icon', self.db, if kind == 'icon':
self.formatter, self.icon_cache) need_icon_with_text = True
if ccicon is not None: ccicon = self.column_icon(id_, key, fmt, 'icon', self.db,
return ccicon self.formatter, self.icon_cache)
if need_icon_with_text: if ccicon is not None:
self.icon_cache[id_][key+'icon'] = self.bool_blank_icon return ccicon
return self.bool_blank_icon if need_icon_with_text:
self.icon_cache[id_][key+'icon'] = None 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: 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

@ -13,7 +13,7 @@ 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, QHBoxLayout) QApplication)
from calibre import prepare_string_for_xml, sanitize_file_name_unicode from calibre import prepare_string_for_xml, sanitize_file_name_unicode
from calibre.constants import config_dir from calibre.constants import config_dir
@ -28,9 +28,8 @@ from calibre.utils.icu import lower
all_columns_string = _('All Columns') all_columns_string = _('All Columns')
rule_kinds = [(_('color'), 'color'), icon_rule_kinds = [(_('icon with text'), 'icon'),
(_('icon with text'), 'icon'), (_('icon with no text'), 'icon_only') ]
(_('icon with no text'), 'icon_only') ]
class ConditionEditor(QWidget): # {{{ class ConditionEditor(QWidget): # {{{
@ -214,8 +213,6 @@ class ConditionEditor(QWidget): # {{{
col = self.current_col col = self.current_col
if not col: if not col:
return return
m = self.fm[col]
dt = m['datatype']
action = self.current_action action = self.current_action
if not action: if not action:
return return
@ -252,7 +249,7 @@ class ConditionEditor(QWidget): # {{{
class RuleEditor(QDialog): # {{{ class RuleEditor(QDialog): # {{{
def __init__(self, fm, parent=None): def __init__(self, fm, pref_name, parent=None):
QDialog.__init__(self, parent) QDialog.__init__(self, parent)
self.fm = fm self.fm = fm
@ -273,10 +270,15 @@ class RuleEditor(QDialog): # {{{
self.l2 = l2 = QLabel(_('Set the')) self.l2 = l2 = QLabel(_('Set the'))
l.addWidget(l2, 2, 0) l.addWidget(l2, 2, 0)
self.kind_box = QComboBox(self) if pref_name == 'column_color_rules':
for tt, t in rule_kinds: self.rule_kind = 'color'
self.kind_box.addItem(tt, t) l.addWidget(QLabel(_('color')))
l.addWidget(self.kind_box, 2, 1) else:
self.rule_kind = 'icon'
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(_('of the column:')) self.l3 = l3 = QLabel(_('of the column:'))
l.addWidget(l3, 2, 2) l.addWidget(l3, 2, 2)
@ -287,16 +289,17 @@ class RuleEditor(QDialog): # {{{
self.l4 = l4 = QLabel(_('to')) self.l4 = l4 = QLabel(_('to'))
l.addWidget(l4, 2, 4) l.addWidget(l4, 2, 4)
self.color_box = QComboBox(self) if self.rule_kind == 'color':
self.color_label = QLabel('Sample text Sample text') self.color_box = QComboBox(self)
self.color_label.setTextFormat(Qt.RichText) self.color_label = QLabel('Sample text Sample text')
l.addWidget(self.color_box, 2, 5) self.color_label.setTextFormat(Qt.RichText)
l.addWidget(self.color_label, 2, 6) l.addWidget(self.color_box, 2, 5)
l.addWidget(self.color_label, 2, 6)
self.filename_box = QLabel() else:
l.addWidget(self.filename_box, 2, 5) self.filename_box = QLabel()
self.filename_button = QPushButton(_('Choose icon')) l.addWidget(self.filename_box, 2, 5)
l.addWidget(self.filename_button, 2, 6) self.filename_button = QPushButton(_('Choose icon'))
l.addWidget(self.filename_button, 2, 6)
l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 7) l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 7)
@ -331,24 +334,28 @@ class RuleEditor(QDialog): # {{{
self.conditions_widget.layout().setAlignment(Qt.AlignTop) self.conditions_widget.layout().setAlignment(Qt.AlignTop)
self.conditions = [] self.conditions = []
for b in (self.column_box, self.color_box): if self.rule_kind == 'color':
b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon) for b in (self.column_box, self.color_box):
b.setMinimumContentsLength(15) b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon)
b.setMinimumContentsLength(15)
for key in sorted(displayable_columns(fm), for key in sorted(displayable_columns(fm),
key=lambda(k): sort_key(fm[k]['name']) if k != color_row_key else 0): 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'] name = all_columns_string if key == color_row_key else fm[key]['name']
if name: if name:
self.column_box.addItem(name, key) self.column_box.addItem(name, key)
self.column_box.setCurrentIndex(0) self.column_box.setCurrentIndex(0)
self.color_box.addItems(QColor.colorNames()) if self.rule_kind == 'color':
self.color_box.setCurrentIndex(0) 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.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 self.icon_path = None
@ -363,18 +370,6 @@ 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): def filename_button_clicked(self):
try: try:
path = choose_files(self, 'choose_category_icon', path = choose_files(self, 'choose_category_icon',
@ -402,17 +397,12 @@ class RuleEditor(QDialog): # {{{
def apply_rule(self, kind, col, rule): def apply_rule(self, kind, col, rule):
if kind == 'color': if kind == 'color':
self.kind_box.setCurrentIndex(0)
self.filename_box.setVisible(False)
self.filename_button.setVisible(False)
if rule.color: if rule.color:
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)
else: else:
self.kind_box.setCurrentIndex(1 if kind == 'icon' else 2) self.kind_box.setCurrentIndex(0 if kind == 'icon' else 1)
self.color_box.setVisible(False)
self.color_label.setVisible(False)
self.filename_box.setText(rule.color) self.filename_box.setText(rule.color)
for i in range(self.column_box.count()): for i in range(self.column_box.count()):
@ -421,10 +411,12 @@ class RuleEditor(QDialog): # {{{
self.column_box.setCurrentIndex(i) self.column_box.setCurrentIndex(i)
break break
if rule.color: if rule.color:
idx = self.color_box.findText(rule.color) if kind == 'color':
if idx >= 0: idx = self.color_box.findText(rule.color)
self.color_box.setCurrentIndex(idx) if idx >= 0:
self.filename_box.setText(rule.color) self.color_box.setCurrentIndex(idx)
else:
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)
@ -438,7 +430,7 @@ class RuleEditor(QDialog): # {{{
def accept(self): def accept(self):
if self.kind_box.currentIndex() != 0: if self.rule_kind != 'color':
path = self.icon_path path = self.icon_path
if path: if path:
try: try:
@ -479,8 +471,7 @@ 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 self.rule_kind != 'color':
if kind != 'color':
r.color = unicode(self.filename_box.text()) r.color = unicode(self.filename_box.text())
else: else:
r.color = unicode(self.color_box.currentText()) r.color = unicode(self.color_box.currentText())
@ -490,25 +481,44 @@ class RuleEditor(QDialog): # {{{
condition = c.condition condition = c.condition
if condition is not None: if condition is not None:
r.add_condition(*condition) r.add_condition(*condition)
if self.rule_kind == 'icon':
kind = unicode(self.kind_box.itemData(
self.kind_box.currentIndex()).toString())
else:
kind = 'color'
return kind, col, r return kind, col, r
# }}} # }}}
class RulesModel(QAbstractListModel): # {{{ class RulesModel(QAbstractListModel): # {{{
def __init__(self, prefs, fm, parent=None): def __init__(self, prefs, fm, pref_name, parent=None):
QAbstractListModel.__init__(self, parent) QAbstractListModel.__init__(self, parent)
self.fm = fm self.fm = fm
rules = list(prefs['column_color_rules']) self.pref_name = pref_name
self.rules = [] if pref_name == 'column_color_rules':
for kind, col, template in rules: self.rule_kind = 'color'
if col not in self.fm: continue rules = list(prefs[pref_name])
try: self.rules = []
rule = rule_from_template(self.fm, template) for col, template in rules:
except: if col not in self.fm and col != color_row_key: continue
rule = template try:
self.rules.append((kind, col, rule)) 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): def rowCount(self, *args):
return len(self.rules) return len(self.rules)
@ -547,8 +557,11 @@ class RulesModel(QAbstractListModel): # {{{
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((kind, col, r)) if kind == 'color':
prefs['column_color_rules'] = rules rules.append((col, r))
else:
rules.append((kind, col, r))
prefs[self.pref_name] = rules
def move(self, idx, delta): def move(self, idx, delta):
row = idx.row() + delta row = idx.row() + delta
@ -574,10 +587,13 @@ class RulesModel(QAbstractListModel): # {{{
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' trans_kind = 'not found'
for tt, t in rule_kinds: if kind == 'color':
if kind == t: trans_kind = _('color')
trans_kind = tt else:
break 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
@ -656,8 +672,9 @@ class EditRules(QWidget): # {{{
b.clicked.connect(self.add_advanced) b.clicked.connect(self.add_advanced)
l.addWidget(b, 3, 0, 1, 2) l.addWidget(b, 3, 0, 1, 2)
def initialize(self, fm, prefs, mi): def initialize(self, fm, prefs, mi, pref_name):
self.model = RulesModel(prefs, fm) self.pref_name = pref_name
self.model = RulesModel(prefs, fm, self.pref_name)
self.rules_view.setModel(self.model) self.rules_view.setModel(self.model)
self.fm = fm self.fm = fm
self.mi = mi self.mi = mi
@ -671,7 +688,7 @@ class EditRules(QWidget): # {{{
self.changed.emit() self.changed.emit()
def add_rule(self): def add_rule(self):
d = RuleEditor(self.model.fm) d = RuleEditor(self.model.fm, self.pref_name)
d.add_blank_condition() d.add_blank_condition()
self._add_rule(d) self._add_rule(d)
@ -685,7 +702,7 @@ class EditRules(QWidget): # {{{
except: except:
return return
if isinstance(rule, Rule): if isinstance(rule, Rule):
d = RuleEditor(self.model.fm) d = RuleEditor(self.model.fm, self.pref_name)
d.apply_rule(kind, 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)
@ -748,7 +765,7 @@ if __name__ == '__main__':
db = db() db = db()
if True: if True:
d = RuleEditor(db.field_metadata) d = RuleEditor(db.field_metadata, 'column_color_rules')
d.add_blank_condition() d.add_blank_condition()
d.exec_() d.exec_()

View File

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

View File

@ -211,6 +211,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
defs['gui_restriction'] = defs['cs_restriction'] = '' defs['gui_restriction'] = defs['cs_restriction'] = ''
defs['categories_using_hierarchy'] = [] defs['categories_using_hierarchy'] = []
defs['column_color_rules'] = [] defs['column_color_rules'] = []
defs['column_icon_rules'] = []
defs['grouped_search_make_user_categories'] = [] defs['grouped_search_make_user_categories'] = []
defs['similar_authors_search_key'] = 'authors' defs['similar_authors_search_key'] = 'authors'
defs['similar_authors_match_kind'] = 'match_any' defs['similar_authors_match_kind'] = 'match_any'
@ -253,17 +254,6 @@ 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]