From c3a2c3f458304abaef826e08f61265a235df5d50 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sat, 21 May 2011 19:24:04 +0100
Subject: [PATCH 01/14] Add option to color custom enumeration values in the
library view
---
src/calibre/gui2/library/delegates.py | 25 ++++++++++++++++
.../gui2/preferences/create_custom_column.py | 21 ++++++++++++--
.../gui2/preferences/create_custom_column.ui | 29 ++++++++++++++++---
3 files changed, 68 insertions(+), 7 deletions(-)
diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py
index e2234f6df5..ae01081736 100644
--- a/src/calibre/gui2/library/delegates.py
+++ b/src/calibre/gui2/library/delegates.py
@@ -274,6 +274,31 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{
Delegate for text/int/float data.
'''
+ def __init__(self, parent):
+ QStyledItemDelegate.__init__(self, parent)
+ self.document = QTextDocument()
+
+ def paint(self, painter, option, index):
+ style = self.parent().style()
+ txt = unicode(index.data(Qt.DisplayRole).toString())
+ self.document.setPlainText(txt)
+ painter.save()
+ if hasattr(QStyle, 'CE_ItemViewItem'):
+ style.drawControl(QStyle.CE_ItemViewItem, option,
+ painter, self.parent())
+ elif option.state & QStyle.State_Selected:
+ painter.fillRect(option.rect, option.palette.highlight())
+ m = index.model()
+ col = m.column_map[index.column()]
+ colors = m.custom_columns[col]['display'].get('enum_colors', [])
+ values = m.custom_columns[col]['display']['enum_values']
+ if len(colors) > 0 and txt in values:
+ painter.fillRect(option.rect, QColor(colors[values.index(txt)]))
+ painter.setClipRect(option.rect)
+ painter.translate(option.rect.topLeft())
+ self.document.drawContents(painter)
+ painter.restore()
+
def createEditor(self, parent, option, index):
m = index.model()
col = m.column_map[index.column()]
diff --git a/src/calibre/gui2/preferences/create_custom_column.py b/src/calibre/gui2/preferences/create_custom_column.py
index 7b891b782c..180c3aed7a 100644
--- a/src/calibre/gui2/preferences/create_custom_column.py
+++ b/src/calibre/gui2/preferences/create_custom_column.py
@@ -6,7 +6,7 @@ __copyright__ = '2010, Kovid Goyal '
import re
from functools import partial
-from PyQt4.Qt import QDialog, Qt, QListWidgetItem, QVariant
+from PyQt4.Qt import QDialog, Qt, QListWidgetItem, QVariant, QColor
from calibre.gui2.preferences.create_custom_column_ui import Ui_QCreateCustomColumn
from calibre.gui2 import error_dialog
@@ -126,6 +126,7 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
c['display'].get('make_category', False))
elif ct == 'enumeration':
self.enum_box.setText(','.join(c['display'].get('enum_values', [])))
+ self.enum_colors.setText(','.join(c['display'].get('enum_colors', [])))
self.datatype_changed()
if ct in ['text', 'composite', 'enumeration']:
self.use_decorations.setChecked(c['display'].get('use_decorations', False))
@@ -170,7 +171,7 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
for x in ('box', 'default_label', 'label', 'sort_by', 'sort_by_label',
'make_category'):
getattr(self, 'composite_'+x).setVisible(col_type in ['composite', '*composite'])
- for x in ('box', 'default_label', 'label'):
+ for x in ('box', 'default_label', 'label', 'colors', 'colors_label'):
getattr(self, 'enum_'+x).setVisible(col_type == 'enumeration')
self.use_decorations.setVisible(col_type in ['text', 'composite', 'enumeration'])
self.is_names.setVisible(col_type == '*text')
@@ -247,7 +248,21 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
if l[i] in l[i+1:]:
return self.simple_error('', _('The value "{0}" is in the '
'list more than once').format(l[i]))
- display_dict = {'enum_values': l}
+ c = unicode(self.enum_colors.text())
+ if c:
+ c = [v.strip() for v in unicode(self.enum_colors.text()).split(',')]
+ else:
+ c = []
+ print c, len(c)
+ if len(c) != 0 and len(c) != len(l):
+ return self.simple_error('', _('The colors box must be empty or '
+ 'contain the same number of items as the value box'))
+ for tc in c:
+ if tc not in QColor.colorNames():
+ return self.simple_error('',
+ _('The color {0} is unknown').format(tc))
+
+ display_dict = {'enum_values': l, 'enum_colors': c}
elif col_type == 'text' and is_multiple:
display_dict = {'is_names': self.is_names.isChecked()}
diff --git a/src/calibre/gui2/preferences/create_custom_column.ui b/src/calibre/gui2/preferences/create_custom_column.ui
index 619b0c6212..2bdadd4b9d 100644
--- a/src/calibre/gui2/preferences/create_custom_column.ui
+++ b/src/calibre/gui2/preferences/create_custom_column.ui
@@ -304,8 +304,8 @@ Everything else will show nothing.
-
-
-
-
+
+
-
@@ -320,13 +320,34 @@ four values, the first of them being the empty value.
- -
+
-
The empty string is always the first value
- Default: (nothing)
+ Values
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ A list of color names to use when displaying an item. The
+list must be empty or contain a color for each value.
+
+
+
+ -
+
+
+ Colors
From 994974fb59afea4e781c99b0019c4d425f4ee714 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sat, 21 May 2011 19:34:23 +0100
Subject: [PATCH 02/14] Add tooltip listing all colors available
---
src/calibre/gui2/preferences/create_custom_column.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/calibre/gui2/preferences/create_custom_column.py b/src/calibre/gui2/preferences/create_custom_column.py
index 180c3aed7a..3a245580dd 100644
--- a/src/calibre/gui2/preferences/create_custom_column.py
+++ b/src/calibre/gui2/preferences/create_custom_column.py
@@ -132,6 +132,9 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
self.use_decorations.setChecked(c['display'].get('use_decorations', False))
elif ct == '*text':
self.is_names.setChecked(c['display'].get('is_names', False))
+
+ all_colors = [unicode(s) for s in list(QColor.colorNames())]
+ self.enum_colors_label.setToolTip('' + ', '.join(all_colors) + '
')
self.exec_()
def shortcut_activated(self, url):
@@ -253,7 +256,6 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
c = [v.strip() for v in unicode(self.enum_colors.text()).split(',')]
else:
c = []
- print c, len(c)
if len(c) != 0 and len(c) != len(l):
return self.simple_error('', _('The colors box must be empty or '
'contain the same number of items as the value box'))
From 6eec4fa410eddb376b62d064549460ee754031bb Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sat, 21 May 2011 19:40:27 +0100
Subject: [PATCH 03/14] More robust coloring code in the CC Enum Delegate
---
src/calibre/gui2/library/delegates.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py
index ae01081736..1af0482a31 100644
--- a/src/calibre/gui2/library/delegates.py
+++ b/src/calibre/gui2/library/delegates.py
@@ -289,11 +289,14 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{
elif option.state & QStyle.State_Selected:
painter.fillRect(option.rect, option.palette.highlight())
m = index.model()
- col = m.column_map[index.column()]
- colors = m.custom_columns[col]['display'].get('enum_colors', [])
- values = m.custom_columns[col]['display']['enum_values']
+ cc = m.custom_columns[m.column_map[index.column()]]['display']
+ colors = cc.get('enum_colors', [])
+ values = cc.get('enum_values', [])
if len(colors) > 0 and txt in values:
- painter.fillRect(option.rect, QColor(colors[values.index(txt)]))
+ try:
+ painter.fillRect(option.rect, QColor(colors[values.index(txt)]))
+ except:
+ pass
painter.setClipRect(option.rect)
painter.translate(option.rect.topLeft())
self.document.drawContents(painter)
From c3688278d0ac265fa4d53a084ca1b855300c9dcc Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 13:00:30 +0100
Subject: [PATCH 04/14] First cut at template-based column coloring
---
.../gui2/dialogs/template_line_editor.py | 31 +++++++
src/calibre/gui2/init.py | 1 +
src/calibre/gui2/library/delegates.py | 79 +++++++-----------
src/calibre/gui2/library/models.py | 36 +++++++-
src/calibre/gui2/preferences/look_feel.py | 8 ++
src/calibre/gui2/preferences/look_feel.ui | 83 +++++++++++++++++++
src/calibre/library/database2.py | 4 +
7 files changed, 191 insertions(+), 51 deletions(-)
create mode 100644 src/calibre/gui2/dialogs/template_line_editor.py
diff --git a/src/calibre/gui2/dialogs/template_line_editor.py b/src/calibre/gui2/dialogs/template_line_editor.py
new file mode 100644
index 0000000000..d7ba8e4900
--- /dev/null
+++ b/src/calibre/gui2/dialogs/template_line_editor.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
+
+__license__ = 'GPL v3'
+__copyright__ = '2010, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+from PyQt4.Qt import (SIGNAL, QLineEdit)
+from calibre.gui2.dialogs.template_dialog import TemplateDialog
+
+class LineEditWithTextBox(QLineEdit):
+
+ '''
+ Extend the context menu of a QLineEdit to include more actions.
+ '''
+
+ def contextMenuEvent(self, event):
+ menu = self.createStandardContextMenu()
+ menu.addSeparator()
+
+ action_open_editor = menu.addAction(_('Open Editor'))
+
+ self.connect(action_open_editor, SIGNAL('triggered()'), self.open_editor)
+ menu.exec_(event.globalPos())
+
+ def open_editor(self):
+ t = TemplateDialog(self, self.text())
+ if t.exec_():
+ self.setText(t.textbox.toPlainText())
+
+
diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py
index a75ff01b21..079e1814c3 100644
--- a/src/calibre/gui2/init.py
+++ b/src/calibre/gui2/init.py
@@ -65,6 +65,7 @@ class LibraryViewMixin(object): # {{{
self.build_context_menus()
self.library_view.model().set_highlight_only(config['highlight_search_matches'])
+ self.library_view.model().set_color_templates()
def build_context_menus(self):
lm = QMenu(self)
diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py
index 1af0482a31..042e568d8b 100644
--- a/src/calibre/gui2/library/delegates.py
+++ b/src/calibre/gui2/library/delegates.py
@@ -7,11 +7,12 @@ __docformat__ = 'restructuredtext en'
from math import cos, sin, pi
-from PyQt4.Qt import QColor, Qt, QModelIndex, QSize, \
- QPainterPath, QLinearGradient, QBrush, \
+from PyQt4.Qt import QColor, Qt, QModelIndex, QSize, QPalette, \
+ QPainterPath, QLinearGradient, QBrush, QApplication, \
QPen, QStyle, QPainter, QStyleOptionViewItemV4, \
QIcon, QDoubleSpinBox, QVariant, QSpinBox, \
- QStyledItemDelegate, QComboBox, QTextDocument
+ QStyledItemDelegate, QComboBox, QTextDocument, \
+ QAbstractTextDocumentLayout
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
from calibre.gui2.widgets import EnLineEdit
@@ -51,9 +52,7 @@ class RatingDelegate(QStyledItemDelegate): # {{{
return QSize(5*(self.SIZE), self.SIZE+4)
def paint(self, painter, option, index):
- style = self._parent.style()
- option = QStyleOptionViewItemV4(option)
- self.initStyleOption(option, self.dummy)
+ self.initStyleOption(option, index)
num = index.model().data(index, Qt.DisplayRole).toInt()[0]
def draw_star():
painter.save()
@@ -65,18 +64,24 @@ class RatingDelegate(QStyledItemDelegate): # {{{
painter.restore()
painter.save()
- if hasattr(QStyle, 'CE_ItemViewItem'):
- style.drawControl(QStyle.CE_ItemViewItem, option,
- painter, self._parent)
- elif option.state & QStyle.State_Selected:
+ if option.state & QStyle.State_Selected:
painter.fillRect(option.rect, option.palette.highlight())
+ else:
+ painter.fillRect(option.rect, option.backgroundBrush)
+
try:
painter.setRenderHint(QPainter.Antialiasing)
painter.setClipRect(option.rect)
y = option.rect.center().y()-self.SIZE/2.
x = option.rect.left()
- painter.setPen(self.PEN)
- painter.setBrush(self.brush)
+ brush = index.model().data(index, role=Qt.ForegroundRole)
+ if brush is None:
+ pen = self.PEN
+ painter.setBrush(self.COLOR)
+ else:
+ pen = QPen(brush, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
+ painter.setBrush(brush)
+ painter.setPen(pen)
painter.translate(x, y)
i = 0
while i < num:
@@ -274,34 +279,6 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{
Delegate for text/int/float data.
'''
- def __init__(self, parent):
- QStyledItemDelegate.__init__(self, parent)
- self.document = QTextDocument()
-
- def paint(self, painter, option, index):
- style = self.parent().style()
- txt = unicode(index.data(Qt.DisplayRole).toString())
- self.document.setPlainText(txt)
- painter.save()
- if hasattr(QStyle, 'CE_ItemViewItem'):
- style.drawControl(QStyle.CE_ItemViewItem, option,
- painter, self.parent())
- elif option.state & QStyle.State_Selected:
- painter.fillRect(option.rect, option.palette.highlight())
- m = index.model()
- cc = m.custom_columns[m.column_map[index.column()]]['display']
- colors = cc.get('enum_colors', [])
- values = cc.get('enum_values', [])
- if len(colors) > 0 and txt in values:
- try:
- painter.fillRect(option.rect, QColor(colors[values.index(txt)]))
- except:
- pass
- painter.setClipRect(option.rect)
- painter.translate(option.rect.topLeft())
- self.document.drawContents(painter)
- painter.restore()
-
def createEditor(self, parent, option, index):
m = index.model()
col = m.column_map[index.column()]
@@ -339,17 +316,19 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{
self.document = QTextDocument()
def paint(self, painter, option, index):
- style = self.parent().style()
- self.document.setHtml(index.data(Qt.DisplayRole).toString())
+ self.initStyleOption(option, index)
+ style = QApplication.style() if option.widget is None \
+ else option.widget.style()
+ self.document.setHtml(option.text)
+ option.text = ""
+ style.drawControl(QStyle.CE_ItemViewItem, option, painter);
+ ctx = QAbstractTextDocumentLayout.PaintContext()
+ ctx.palette = option.palette #.setColor(QPalette.Text, QColor("red"));
+ textRect = style.subElementRect(QStyle.SE_ItemViewItemText, option)
painter.save()
- if hasattr(QStyle, 'CE_ItemViewItem'):
- style.drawControl(QStyle.CE_ItemViewItem, option,
- painter, self.parent())
- elif option.state & QStyle.State_Selected:
- painter.fillRect(option.rect, option.palette.highlight())
- painter.setClipRect(option.rect)
- painter.translate(option.rect.topLeft())
- self.document.drawContents(painter)
+ painter.translate(textRect.topLeft())
+ painter.setClipRect(textRect.translated(-textRect.topLeft()))
+ self.document.documentLayout().draw(painter, ctx)
painter.restore()
def createEditor(self, parent, option, index):
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index fc1117167d..7d6cfadacb 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -14,6 +14,7 @@ from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
from calibre.gui2 import NONE, UNDEFINED_QDATE
from calibre.utils.pyparsing import ParseException
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
+from calibre.ebooks.metadata.book.base import composite_formatter
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.config import tweaks, prefs
from calibre.utils.date import dt_factory, qt_to_dt
@@ -96,6 +97,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.ids_to_highlight_set = set()
self.current_highlighted_idx = None
self.highlight_only = False
+ self.column_color_map = {}
self.read_config()
def change_alignment(self, colname, alignment):
@@ -532,6 +534,16 @@ class BooksModel(QAbstractTableModel): # {{{
img = self.default_image
return img
+ def set_color_templates(self):
+ print 'here'
+ self.column_color_map = {}
+ for i in range(1,self.db.column_color_count+1):
+ name = self.db.prefs.get('column_color_name_'+str(i))
+ if name:
+ print name, self.db.prefs.get('column_color_template_'+str(i))
+ self.column_color_map[name] = \
+ self.db.prefs.get('column_color_template_'+str(i))
+ self.refresh()
def build_data_convertors(self):
def authors(r, idx=-1):
@@ -693,9 +705,31 @@ class BooksModel(QAbstractTableModel): # {{{
return NONE
if role in (Qt.DisplayRole, Qt.EditRole):
return self.column_to_dc_map[col](index.row())
- elif role == Qt.BackgroundColorRole:
+ elif role == Qt.BackgroundRole:
if self.id(index) in self.ids_to_highlight_set:
return QColor('lightgreen')
+ elif role == Qt.ForegroundRole:
+ key = self.column_map[col]
+ if key in self.column_color_map:
+ mi = self.db.get_metadata(self.id(index), index_is_id=True)
+ fmt = self.column_color_map[key]
+ try:
+ color = composite_formatter.safe_format(fmt, mi, '', mi)
+ return QColor(color)
+ except:
+ return None
+ elif self.is_custom_column(key) and \
+ self.custom_columns[key]['datatype'] == 'enumeration':
+ cc = self.custom_columns[self.column_map[col]]['display']
+ colors = cc.get('enum_colors', [])
+ values = cc.get('enum_values', [])
+ txt = unicode(index.data(Qt.DisplayRole).toString())
+ if len(colors) > 0 and txt in values:
+ try:
+ return QColor(colors[values.index(txt)])
+ except:
+ pass
+ 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())
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index ee2d7a5428..fc6990fcc9 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -159,6 +159,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.df_up_button.clicked.connect(self.move_df_up)
self.df_down_button.clicked.connect(self.move_df_down)
+ choices = db.field_metadata.displayable_field_keys()
+ choices.sort(key=sort_key)
+ choices.insert(0, '')
+ for i in range(1, db.column_color_count+1):
+ r('column_color_name_'+str(i), db.prefs, choices=choices)
+ r('column_color_template_'+str(i), db.prefs)
+
def initialize(self):
ConfigWidgetBase.initialize(self)
font = gprefs['font']
@@ -238,6 +245,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
return rr
def refresh_gui(self, gui):
+ gui.library_view.model().set_color_templates()
self.update_font_display()
gui.tags_view.reread_collapse_parameters()
gui.library_view.refresh_book_details()
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index 244b811cbd..d7fca70c08 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -407,6 +407,84 @@ then the tags will be displayed each on their own line.
+
+
+
+ :/images/cover_flow.png:/images/cover_flow.png
+
+
+ Column Coloring
+
+
+ -
+
+
+ Column name
+
+
+
+ -
+
+
+ Selection template
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 690
+ 283
+
+
+
+
+
+
@@ -417,6 +495,11 @@ then the tags will be displayed each on their own line.
QLineEdit
+
+ LineEditWithTextBox
+ QLineEdit
+ calibre/gui2/dialogs/template_line_editor.h
+
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index 9a740a08b7..819ac2cd24 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -211,6 +211,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
defs = self.prefs.defaults
defs['gui_restriction'] = defs['cs_restriction'] = ''
defs['categories_using_hierarchy'] = []
+ self.column_color_count = 5
+ for i in range(1,self.column_color_count+1):
+ defs['column_color_name_'+str(i)] = ''
+ defs['column_color_template_'+str(i)] = ''
# Migrate the bool tristate tweak
defs['bools_are_tristate'] = \
From 3c92c4a988eca819c813baf2f306cc0cfbff69c9 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 14:14:23 +0100
Subject: [PATCH 05/14] More work on coloring columns. Refactor the template
editor, add some documentation for the new template function first_non_empty,
add help text to the configuration dialog.
---
.../gui2/dialogs/template_line_editor.py | 2 +-
src/calibre/gui2/library/models.py | 2 -
src/calibre/gui2/preferences/look_feel.py | 26 +++++++-
src/calibre/gui2/preferences/look_feel.ui | 66 +++++++++++--------
src/calibre/gui2/preferences/plugboard.py | 26 +-------
src/calibre/manual/template_lang.rst | 1 +
src/calibre/utils/formatter_functions.py | 19 +++++-
7 files changed, 85 insertions(+), 57 deletions(-)
diff --git a/src/calibre/gui2/dialogs/template_line_editor.py b/src/calibre/gui2/dialogs/template_line_editor.py
index d7ba8e4900..69999f59a0 100644
--- a/src/calibre/gui2/dialogs/template_line_editor.py
+++ b/src/calibre/gui2/dialogs/template_line_editor.py
@@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
from PyQt4.Qt import (SIGNAL, QLineEdit)
from calibre.gui2.dialogs.template_dialog import TemplateDialog
-class LineEditWithTextBox(QLineEdit):
+class TemplateLineEditor(QLineEdit):
'''
Extend the context menu of a QLineEdit to include more actions.
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index 7d6cfadacb..83bf5868ba 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -535,12 +535,10 @@ class BooksModel(QAbstractTableModel): # {{{
return img
def set_color_templates(self):
- print 'here'
self.column_color_map = {}
for i in range(1,self.db.column_color_count+1):
name = self.db.prefs.get('column_color_name_'+str(i))
if name:
- print name, self.db.prefs.get('column_color_template_'+str(i))
self.column_color_map[name] = \
self.db.prefs.get('column_color_template_'+str(i))
self.refresh()
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index fc6990fcc9..97400c45bd 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -6,7 +6,7 @@ __copyright__ = '2010, Kovid Goyal '
__docformat__ = 'restructuredtext en'
from PyQt4.Qt import (QApplication, QFont, QFontInfo, QFontDialog,
- QAbstractListModel, Qt)
+ QAbstractListModel, Qt, QColor)
from calibre.gui2.preferences import ConfigWidgetBase, test_widget, CommaSeparatedList
from calibre.gui2.preferences.look_feel_ui import Ui_Form
@@ -159,12 +159,36 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.df_up_button.clicked.connect(self.move_df_up)
self.df_down_button.clicked.connect(self.move_df_down)
+ self.color_help_text.setWordWrap(True)
+ self.color_help_text.setText('' +
+ _('Here you can specify coloring rules for fields shown in the '
+ 'library view. Choose the field you wish to color, then '
+ 'supply a template that specifies the color to use.') +
+ '
' +
+ _('The template must evaluate to one of the color names shown '
+ 'below. You can use any legal template expression. '
+ 'For example, you can set the title to always display in '
+ 'green using the template "green" (without the quotes). '
+ 'To show the title in blue if the book has the tag "Science '
+ 'Fiction", red if the book has the tag "Mystery", or black if '
+ 'the book has neither tag, use '
+ '"{tags:switch(Science Fiction,blue,Mystery,red,)}" '
+ 'To show the title in green if it has one format, blue if it '
+ 'two formats, and red if more, use '
+ "\"program:cmp(count(field('formats'),','), 2, 'green', 'blue', 'red')\"") +
+ '
' +
+ _('Note: if you want to color a "custom column with a fixed set '
+ 'of values", it is possible and often easier to specify the '
+ 'colors in the column definition dialog. There you can '
+ 'provide a color for each value without using a template.')+ '
')
choices = db.field_metadata.displayable_field_keys()
choices.sort(key=sort_key)
choices.insert(0, '')
for i in range(1, db.column_color_count+1):
r('column_color_name_'+str(i), db.prefs, choices=choices)
r('column_color_template_'+str(i), db.prefs)
+ all_colors = [unicode(s) for s in list(QColor.colorNames())]
+ self.colors_box.setText(', '.join(all_colors))
def initialize(self):
ConfigWidgetBase.initialize(self)
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index d7fca70c08..aa5afe26dd 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -416,72 +416,80 @@ then the tags will be displayed each on their own line.
Column Coloring
- -
+
-
Column name
- -
+
-
+
+
+
+ -
Selection template
- -
+
-
- -
-
-
-
- -
-
-
-
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
- -
-
-
- Qt::Vertical
+
-
+
+
+
+ -
+
+
+
+ -
+
+
+ Color names
-
-
- 690
- 283
-
+
+
+ -
+
+
+
+ 0
+ 1
+
-
+
@@ -496,7 +504,7 @@ then the tags will be displayed each on their own line.
- LineEditWithTextBox
+ TemplateLineEditor
QLineEdit
calibre/gui2/dialogs/template_line_editor.h
diff --git a/src/calibre/gui2/preferences/plugboard.py b/src/calibre/gui2/preferences/plugboard.py
index b4b1d4e08e..cf632c04c0 100644
--- a/src/calibre/gui2/preferences/plugboard.py
+++ b/src/calibre/gui2/preferences/plugboard.py
@@ -7,12 +7,12 @@ __docformat__ = 'restructuredtext en'
import copy
-from PyQt4.Qt import Qt, QLineEdit, QComboBox, SIGNAL, QListWidgetItem
+from PyQt4.Qt import Qt, QComboBox, QListWidgetItem
from calibre.customize.ui import is_disabled
from calibre.gui2 import error_dialog, question_dialog
from calibre.gui2.device import device_name_for_plugboards
-from calibre.gui2.dialogs.template_dialog import TemplateDialog
+from calibre.gui2.dialogs.template_line_editor import TemplateLineEditor
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
from calibre.gui2.preferences.plugboard_ui import Ui_Form
from calibre.customize.ui import metadata_writers, device_plugins
@@ -24,26 +24,6 @@ from calibre.library.server.content import plugboard_content_server_value, \
from calibre.utils.formatter import validation_formatter
-class LineEditWithTextBox(QLineEdit):
-
- '''
- Extend the context menu of a QLineEdit to include more actions.
- '''
-
- def contextMenuEvent(self, event):
- menu = self.createStandardContextMenu()
- menu.addSeparator()
-
- action_open_editor = menu.addAction(_('Open Editor'))
-
- self.connect(action_open_editor, SIGNAL('triggered()'), self.open_editor)
- menu.exec_(event.globalPos())
-
- def open_editor(self):
- t = TemplateDialog(self, self.text())
- if t.exec_():
- self.setText(t.textbox.toPlainText())
-
class ConfigWidget(ConfigWidgetBase, Ui_Form):
def genesis(self, gui):
@@ -107,7 +87,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.source_widgets = []
self.dest_widgets = []
for i in range(0, len(self.dest_fields)-1):
- w = LineEditWithTextBox(self)
+ w = TemplateLineEditor(self)
self.source_widgets.append(w)
self.fields_layout.addWidget(w, 5+i, 0, 1, 1)
w = QComboBox(self)
diff --git a/src/calibre/manual/template_lang.rst b/src/calibre/manual/template_lang.rst
index 0fd396fb64..9b5fe63f25 100644
--- a/src/calibre/manual/template_lang.rst
+++ b/src/calibre/manual/template_lang.rst
@@ -234,6 +234,7 @@ The following functions are available in addition to those described in single-f
* ``cmp(x, y, lt, eq, gt)`` -- compares x and y after converting both to numbers. Returns ``lt`` if x < y. Returns ``eq`` if x == y. Otherwise returns ``gt``.
* ``divide(x, y)`` -- returns x / y. Throws an exception if either x or y are not numbers.
* ``field(name)`` -- returns the metadata field named by ``name``.
+ * ``first_non_empty(value, value, ...) -- returns the first value that is not empty. If all values are empty, then the empty value is returned. You can have as many values as you want.
* ``format_date(x, date_format)`` -- format_date(val, format_string) -- format the value, which must be a date field, using the format_string, returning a string. The formatting codes are::
d : the day as number without a leading zero (1 to 31)
diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py
index aa8e4fb3a3..59a750bcc5 100644
--- a/src/calibre/utils/formatter_functions.py
+++ b/src/calibre/utils/formatter_functions.py
@@ -562,6 +562,22 @@ class BuiltinBooksize(BuiltinFormatterFunction):
pass
return ''
+class BuiltinFirstNonEmpty(BuiltinFormatterFunction):
+ name = 'first_non_empty'
+ arg_count = -1
+ doc = _('first_non_empty(value, value, ...) -- '
+ 'returns the first value that is not empty. If all values are '
+ 'empty, then the empty value is returned.'
+ 'You can have as many values as you want.')
+
+ def evaluate(self, formatter, kwargs, mi, locals, *args):
+ i = 0
+ while i < len(args):
+ if args[i]:
+ return args[i]
+ i += 1
+ return ''
+
builtin_add = BuiltinAdd()
builtin_assign = BuiltinAssign()
builtin_booksize = BuiltinBooksize()
@@ -571,8 +587,9 @@ builtin_contains = BuiltinContains()
builtin_count = BuiltinCount()
builtin_divide = BuiltinDivide()
builtin_eval = BuiltinEval()
-builtin_format_date = BuiltinFormat_date()
+builtin_first_non_empty = BuiltinFirstNonEmpty()
builtin_field = BuiltinField()
+builtin_format_date = BuiltinFormat_date()
builtin_ifempty = BuiltinIfempty()
builtin_list_item = BuiltinListitem()
builtin_lookup = BuiltinLookup()
From 4ddb1e852ba181d6cfd03dcb8bd31aae758475d1 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 15:22:33 +0100
Subject: [PATCH 06/14] Improvements on coloring: add an in_list formatter
function. Add more documentation in the preference screen. Add a scroll bar
to the doc in the preferences screen.
---
src/calibre/gui2/preferences/look_feel.py | 24 ++++++++++++++++-------
src/calibre/gui2/preferences/look_feel.ui | 10 +++++++++-
src/calibre/utils/formatter_functions.py | 17 ++++++++++++++++
3 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index 97400c45bd..c96d980505 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -159,7 +159,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.df_up_button.clicked.connect(self.move_df_up)
self.df_down_button.clicked.connect(self.move_df_down)
- self.color_help_text.setWordWrap(True)
self.color_help_text.setText('' +
_('Here you can specify coloring rules for fields shown in the '
'library view. Choose the field you wish to color, then '
@@ -169,14 +168,25 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
'below. You can use any legal template expression. '
'For example, you can set the title to always display in '
'green using the template "green" (without the quotes). '
- 'To show the title in blue if the book has the tag "Science '
- 'Fiction", red if the book has the tag "Mystery", or black if '
- 'the book has neither tag, use '
- '"{tags:switch(Science Fiction,blue,Mystery,red,)}" '
+ 'To show the title in the color named in the custom column '
+ '#column, use "{#column}". To show the title in blue if the '
+ 'custom column #column contains the value "foo", in red if the '
+ 'column contains the value "bar", otherwise in black, use '
+ '
{#column:switch(foo,blue,bar,red,black)}
'
+ 'To show the title in blue if the book has the exact tag '
+ '"Science Fiction", red if the book has the exact tag '
+ '"Mystery", or black if the book has neither tag, use'
+ "program: \n"
+ " t = field('tags'); \n"
+ " first_non_empty(\n"
+ " in_list(t, ',', '^Science Fiction$', 'blue', ''), \n"
+ " in_list(t, ',', '^Mystery$', 'red', 'black'))
"
'To show the title in green if it has one format, blue if it '
- 'two formats, and red if more, use '
- "\"program:cmp(count(field('formats'),','), 2, 'green', 'blue', 'red')\"") +
+ 'two formats, and red if more, use'
+ "program:cmp(count(field('formats'),','), 2, 'green', 'blue', 'red')
") +
'
' +
+ _('You can access a multi-line template editor from the '
+ 'context menu (right-click).') + '
' +
_('Note: if you want to color a "custom column with a fixed set '
'of values", it is possible and often easier to specify the '
'colors in the column definition dialog. There you can '
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index aa5afe26dd..1194109c6c 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -424,7 +424,12 @@ then the tags will be displayed each on their own line.
-
-
+
+
+ true
+
+
+
-
@@ -483,6 +488,9 @@ then the tags will be displayed each on their own line.
-
+
+ true
+
0
diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py
index 59a750bcc5..c53277f3ce 100644
--- a/src/calibre/utils/formatter_functions.py
+++ b/src/calibre/utils/formatter_functions.py
@@ -327,6 +327,22 @@ class BuiltinSwitch(BuiltinFormatterFunction):
return args[i+1]
i += 2
+class BuiltinInList(BuiltinFormatterFunction):
+ name = 'in_list'
+ arg_count = 5
+ doc = _('in_list(val, separator, pattern, found_val, not_found_val) -- '
+ 'treat val as a list of items separated by separator, '
+ 'comparing the pattern against each value in the list. If the '
+ 'pattern matches a value, return found_val, otherwise return '
+ 'not_found_val.')
+
+ def evaluate(self, formatter, kwargs, mi, locals, val, sep, pat, fv, nfv):
+ l = [v.strip() for v in val.split(sep) if v.strip()]
+ for v in l:
+ if re.search(pat, v):
+ return fv
+ return nfv
+
class BuiltinRe(BuiltinFormatterFunction):
name = 're'
arg_count = 3
@@ -591,6 +607,7 @@ builtin_first_non_empty = BuiltinFirstNonEmpty()
builtin_field = BuiltinField()
builtin_format_date = BuiltinFormat_date()
builtin_ifempty = BuiltinIfempty()
+builtin_in_list = BuiltinInList()
builtin_list_item = BuiltinListitem()
builtin_lookup = BuiltinLookup()
builtin_lowercase = BuiltinLowercase()
From ca5dc817c22e70ada00dd0c9feb7ad8ea0ea0238 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 15:26:32 +0100
Subject: [PATCH 07/14] Add the new in_list function to the documentation
---
src/calibre/manual/template_lang.rst | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/calibre/manual/template_lang.rst b/src/calibre/manual/template_lang.rst
index 9b5fe63f25..69c77e5bfd 100644
--- a/src/calibre/manual/template_lang.rst
+++ b/src/calibre/manual/template_lang.rst
@@ -123,7 +123,8 @@ The functions available are:
* ``contains(pattern, text if match, text if not match`` -- checks if field contains matches for the regular expression `pattern`. Returns `text if match` if matches are found, otherwise it returns `text if no match`.
* ``count(separator)`` -- interprets the value as a list of items separated by `separator`, returning the number of items in the list. Most lists use a comma as the separator, but authors uses an ampersand. Examples: `{tags:count(,)}`, `{authors:count(&)}`
* ``ifempty(text)`` -- if the field is not empty, return the value of the field. Otherwise return `text`.
- * ``list_item(index, separator)`` -- interpret the value as a list of items separated by `separator`, returning the `index`th item. The first item is number zero. The last item can be returned using `list_item(-1,separator)`. If the item is not in the list, then the empty value is returned. The separator has the same meaning as in the `count` function.
+ * ``in_list(separator, pattern, found_val, not_found_val)`` -- interpret the field as a list of items separated by `separator`, comparing the `pattern` against each value in the list. If the pattern matches a value, return `found_val`, otherwise return `not_found_val`.
+ * ``list_item(index, separator)`` -- interpret the field as a list of items separated by `separator`, returning the `index`th item. The first item is number zero. The last item can be returned using `list_item(-1,separator)`. If the item is not in the list, then the empty value is returned. The separator has the same meaning as in the `count` function.
* ``re(pattern, replacement)`` -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of |app|, these are python-compatible regular expressions.
* ``shorten(left chars, middle text, right chars)`` -- Return a shortened version of the field, consisting of `left chars` characters from the beginning of the field, followed by `middle text`, followed by `right chars` characters from the end of the string. `Left chars` and `right chars` must be integers. For example, assume the title of the book is `Ancient English Laws in the Times of Ivanhoe`, and you want it to fit in a space of at most 15 characters. If you use ``{title:shorten(9,-,5)}``, the result will be `Ancient E-nhoe`. If the field's length is less than ``left chars`` + ``right chars`` + the length of ``middle text``, then the field will be used intact. For example, the title `The Dome` would not be changed.
* ``switch(pattern, value, pattern, value, ..., else_value)`` -- for each ``pattern, value`` pair, checks if the field matches the regular expression ``pattern`` and if so, returns that ``value``. If no ``pattern`` matches, then ``else_value`` is returned. You can have as many ``pattern, value`` pairs as you want.
From 1a4768a539bfdf65b2f5a6d68a133730683f9261 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 18:32:03 +0100
Subject: [PATCH 08/14] Make coloring work across change_libraries
---
src/calibre/gui2/init.py | 1 -
src/calibre/gui2/library/models.py | 2 ++
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py
index 079e1814c3..a75ff01b21 100644
--- a/src/calibre/gui2/init.py
+++ b/src/calibre/gui2/init.py
@@ -65,7 +65,6 @@ class LibraryViewMixin(object): # {{{
self.build_context_menus()
self.library_view.model().set_highlight_only(config['highlight_search_matches'])
- self.library_view.model().set_color_templates()
def build_context_menus(self):
lm = QMenu(self)
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index 83bf5868ba..a3e7438908 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -157,6 +157,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.database_changed.emit(db)
self.stop_metadata_backup()
self.start_metadata_backup()
+ self.set_color_templates()
def start_metadata_backup(self):
self.metadata_backup = MetadataBackup(self.db)
@@ -535,6 +536,7 @@ class BooksModel(QAbstractTableModel): # {{{
return img
def set_color_templates(self):
+ print 'here'
self.column_color_map = {}
for i in range(1,self.db.column_color_count+1):
name = self.db.prefs.get('column_color_name_'+str(i))
From 6087a6a6603868fa752b15a30b074ebd7e7e7243 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 18:34:34 +0100
Subject: [PATCH 09/14] Remove print statement
---
src/calibre/gui2/library/models.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index a3e7438908..b378256a42 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -536,7 +536,6 @@ class BooksModel(QAbstractTableModel): # {{{
return img
def set_color_templates(self):
- print 'here'
self.column_color_map = {}
for i in range(1,self.db.column_color_count+1):
name = self.db.prefs.get('column_color_name_'+str(i))
From 3487ed762ea084d6d44d9e3a9446f6e87e87e1a8 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 19:34:03 +0100
Subject: [PATCH 10/14] Switch refresh to reset when loading column color
templates
---
src/calibre/gui2/library/models.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index b378256a42..2576518d92 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -153,11 +153,11 @@ class BooksModel(QAbstractTableModel): # {{{
self.headers[col] = self.custom_columns[col]['name']
self.build_data_convertors()
+ self.set_color_templates(reset=False)
self.reset()
self.database_changed.emit(db)
self.stop_metadata_backup()
self.start_metadata_backup()
- self.set_color_templates()
def start_metadata_backup(self):
self.metadata_backup = MetadataBackup(self.db)
@@ -535,14 +535,15 @@ class BooksModel(QAbstractTableModel): # {{{
img = self.default_image
return img
- def set_color_templates(self):
+ def set_color_templates(self, reset=True):
self.column_color_map = {}
for i in range(1,self.db.column_color_count+1):
name = self.db.prefs.get('column_color_name_'+str(i))
if name:
self.column_color_map[name] = \
self.db.prefs.get('column_color_template_'+str(i))
- self.refresh()
+ if reset:
+ self.reset()
def build_data_convertors(self):
def authors(r, idx=-1):
From 0bd580f572cd5b5a10c9167adc6f8f5c717d0dc3 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 19:53:26 +0100
Subject: [PATCH 11/14] Remove unused PEN declaration
---
src/calibre/gui2/library/delegates.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py
index 6d962c9129..4f002c2c48 100644
--- a/src/calibre/gui2/library/delegates.py
+++ b/src/calibre/gui2/library/delegates.py
@@ -28,7 +28,6 @@ from calibre.gui2.dialogs.template_dialog import TemplateDialog
class RatingDelegate(QStyledItemDelegate): # {{{
COLOR = QColor("blue")
SIZE = 16
- PEN = QPen(COLOR, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
def __init__(self, parent):
QStyledItemDelegate.__init__(self, parent)
From 29b453ba23177adc9cd740cada0f6b7ba08e23f4 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 19:55:46 +0100
Subject: [PATCH 12/14] Check for color valid when using column coloring
---
src/calibre/gui2/library/models.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index 2576518d92..6e8e79d3b3 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -726,7 +726,9 @@ class BooksModel(QAbstractTableModel): # {{{
txt = unicode(index.data(Qt.DisplayRole).toString())
if len(colors) > 0 and txt in values:
try:
- return QColor(colors[values.index(txt)])
+ color = colors[values.index(txt)]
+ if QColor.isValid(color):
+ return QColor(color)
except:
pass
return None
From de969af505aeaf32507c19229081371a850549b9 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 20:12:47 +0100
Subject: [PATCH 13/14] Improve robustness in column coloring.
---
src/calibre/gui2/library/models.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index 6e8e79d3b3..9d90c44f18 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -715,7 +715,8 @@ class BooksModel(QAbstractTableModel): # {{{
fmt = self.column_color_map[key]
try:
color = composite_formatter.safe_format(fmt, mi, '', mi)
- return QColor(color)
+ if QColor.isValid(color):
+ return QColor(color)
except:
return None
elif self.is_custom_column(key) and \
From 478369c7cba88cf04d8778d8d4b2ea14c40872ed Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 22 May 2011 20:47:47 +0100
Subject: [PATCH 14/14] Add colors icon to preferences dialog. Correctly clean
template values when the column is set to empty.
---
src/calibre/gui2/preferences/look_feel.py | 8 +++++++-
src/calibre/gui2/preferences/look_feel.ui | 2 +-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index c96d980505..ffbc82eefd 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -194,7 +194,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
choices = db.field_metadata.displayable_field_keys()
choices.sort(key=sort_key)
choices.insert(0, '')
- for i in range(1, db.column_color_count+1):
+ self.column_color_count = db.column_color_count+1
+ for i in range(1, self.column_color_count):
r('column_color_name_'+str(i), db.prefs, choices=choices)
r('column_color_template_'+str(i), db.prefs)
all_colors = [unicode(s) for s in list(QColor.colorNames())]
@@ -267,6 +268,11 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.changed_signal.emit()
def commit(self, *args):
+ for i in range(1, self.column_color_count):
+ col = getattr(self, 'opt_column_color_name_'+str(i))
+ if not col.currentText():
+ temp = getattr(self, 'opt_column_color_template_'+str(i))
+ temp.setText('')
rr = ConfigWidgetBase.commit(self, *args)
if self.current_font != self.initial_font:
gprefs['font'] = (self.current_font[:4] if self.current_font else
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index 1194109c6c..9dedcf4f8c 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -410,7 +410,7 @@ then the tags will be displayed each on their own line.
- :/images/cover_flow.png:/images/cover_flow.png
+ :/images/format-fill-color.png:/images/format-fill-color.png
Column Coloring