mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
First cut at template-based column coloring
This commit is contained in:
parent
6eec4fa410
commit
c3688278d0
31
src/calibre/gui2/dialogs/template_line_editor.py
Normal file
31
src/calibre/gui2/dialogs/template_line_editor.py
Normal file
@ -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 <kovid@kovidgoyal.net>'
|
||||||
|
__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())
|
||||||
|
|
||||||
|
|
@ -65,6 +65,7 @@ class LibraryViewMixin(object): # {{{
|
|||||||
|
|
||||||
self.build_context_menus()
|
self.build_context_menus()
|
||||||
self.library_view.model().set_highlight_only(config['highlight_search_matches'])
|
self.library_view.model().set_highlight_only(config['highlight_search_matches'])
|
||||||
|
self.library_view.model().set_color_templates()
|
||||||
|
|
||||||
def build_context_menus(self):
|
def build_context_menus(self):
|
||||||
lm = QMenu(self)
|
lm = QMenu(self)
|
||||||
|
@ -7,11 +7,12 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
from math import cos, sin, pi
|
from math import cos, sin, pi
|
||||||
|
|
||||||
from PyQt4.Qt import QColor, Qt, QModelIndex, QSize, \
|
from PyQt4.Qt import QColor, Qt, QModelIndex, QSize, QPalette, \
|
||||||
QPainterPath, QLinearGradient, QBrush, \
|
QPainterPath, QLinearGradient, QBrush, QApplication, \
|
||||||
QPen, QStyle, QPainter, QStyleOptionViewItemV4, \
|
QPen, QStyle, QPainter, QStyleOptionViewItemV4, \
|
||||||
QIcon, QDoubleSpinBox, QVariant, QSpinBox, \
|
QIcon, QDoubleSpinBox, QVariant, QSpinBox, \
|
||||||
QStyledItemDelegate, QComboBox, QTextDocument
|
QStyledItemDelegate, QComboBox, QTextDocument, \
|
||||||
|
QAbstractTextDocumentLayout
|
||||||
|
|
||||||
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
|
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
|
||||||
from calibre.gui2.widgets import EnLineEdit
|
from calibre.gui2.widgets import EnLineEdit
|
||||||
@ -51,9 +52,7 @@ class RatingDelegate(QStyledItemDelegate): # {{{
|
|||||||
return QSize(5*(self.SIZE), self.SIZE+4)
|
return QSize(5*(self.SIZE), self.SIZE+4)
|
||||||
|
|
||||||
def paint(self, painter, option, index):
|
def paint(self, painter, option, index):
|
||||||
style = self._parent.style()
|
self.initStyleOption(option, index)
|
||||||
option = QStyleOptionViewItemV4(option)
|
|
||||||
self.initStyleOption(option, self.dummy)
|
|
||||||
num = index.model().data(index, Qt.DisplayRole).toInt()[0]
|
num = index.model().data(index, Qt.DisplayRole).toInt()[0]
|
||||||
def draw_star():
|
def draw_star():
|
||||||
painter.save()
|
painter.save()
|
||||||
@ -65,18 +64,24 @@ class RatingDelegate(QStyledItemDelegate): # {{{
|
|||||||
painter.restore()
|
painter.restore()
|
||||||
|
|
||||||
painter.save()
|
painter.save()
|
||||||
if hasattr(QStyle, 'CE_ItemViewItem'):
|
if option.state & QStyle.State_Selected:
|
||||||
style.drawControl(QStyle.CE_ItemViewItem, option,
|
|
||||||
painter, self._parent)
|
|
||||||
elif option.state & QStyle.State_Selected:
|
|
||||||
painter.fillRect(option.rect, option.palette.highlight())
|
painter.fillRect(option.rect, option.palette.highlight())
|
||||||
|
else:
|
||||||
|
painter.fillRect(option.rect, option.backgroundBrush)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
painter.setRenderHint(QPainter.Antialiasing)
|
painter.setRenderHint(QPainter.Antialiasing)
|
||||||
painter.setClipRect(option.rect)
|
painter.setClipRect(option.rect)
|
||||||
y = option.rect.center().y()-self.SIZE/2.
|
y = option.rect.center().y()-self.SIZE/2.
|
||||||
x = option.rect.left()
|
x = option.rect.left()
|
||||||
painter.setPen(self.PEN)
|
brush = index.model().data(index, role=Qt.ForegroundRole)
|
||||||
painter.setBrush(self.brush)
|
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)
|
painter.translate(x, y)
|
||||||
i = 0
|
i = 0
|
||||||
while i < num:
|
while i < num:
|
||||||
@ -274,34 +279,6 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{
|
|||||||
Delegate for text/int/float data.
|
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):
|
def createEditor(self, parent, option, index):
|
||||||
m = index.model()
|
m = index.model()
|
||||||
col = m.column_map[index.column()]
|
col = m.column_map[index.column()]
|
||||||
@ -339,17 +316,19 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{
|
|||||||
self.document = QTextDocument()
|
self.document = QTextDocument()
|
||||||
|
|
||||||
def paint(self, painter, option, index):
|
def paint(self, painter, option, index):
|
||||||
style = self.parent().style()
|
self.initStyleOption(option, index)
|
||||||
self.document.setHtml(index.data(Qt.DisplayRole).toString())
|
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()
|
painter.save()
|
||||||
if hasattr(QStyle, 'CE_ItemViewItem'):
|
painter.translate(textRect.topLeft())
|
||||||
style.drawControl(QStyle.CE_ItemViewItem, option,
|
painter.setClipRect(textRect.translated(-textRect.topLeft()))
|
||||||
painter, self.parent())
|
self.document.documentLayout().draw(painter, ctx)
|
||||||
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.restore()
|
painter.restore()
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
|
@ -14,6 +14,7 @@ from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
|
|||||||
from calibre.gui2 import NONE, UNDEFINED_QDATE
|
from calibre.gui2 import NONE, UNDEFINED_QDATE
|
||||||
from calibre.utils.pyparsing import ParseException
|
from calibre.utils.pyparsing import ParseException
|
||||||
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
|
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.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.utils.config import tweaks, prefs
|
from calibre.utils.config import tweaks, prefs
|
||||||
from calibre.utils.date import dt_factory, qt_to_dt
|
from calibre.utils.date import dt_factory, qt_to_dt
|
||||||
@ -96,6 +97,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.ids_to_highlight_set = set()
|
self.ids_to_highlight_set = set()
|
||||||
self.current_highlighted_idx = None
|
self.current_highlighted_idx = None
|
||||||
self.highlight_only = False
|
self.highlight_only = False
|
||||||
|
self.column_color_map = {}
|
||||||
self.read_config()
|
self.read_config()
|
||||||
|
|
||||||
def change_alignment(self, colname, alignment):
|
def change_alignment(self, colname, alignment):
|
||||||
@ -532,6 +534,16 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
img = self.default_image
|
img = self.default_image
|
||||||
return img
|
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 build_data_convertors(self):
|
||||||
def authors(r, idx=-1):
|
def authors(r, idx=-1):
|
||||||
@ -693,9 +705,31 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
return NONE
|
return NONE
|
||||||
if role in (Qt.DisplayRole, Qt.EditRole):
|
if role in (Qt.DisplayRole, Qt.EditRole):
|
||||||
return self.column_to_dc_map[col](index.row())
|
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:
|
if self.id(index) in self.ids_to_highlight_set:
|
||||||
return QColor('lightgreen')
|
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:
|
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())
|
return self.column_to_dc_decorator_map[index.column()](index.row())
|
||||||
|
@ -159,6 +159,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
self.df_up_button.clicked.connect(self.move_df_up)
|
self.df_up_button.clicked.connect(self.move_df_up)
|
||||||
self.df_down_button.clicked.connect(self.move_df_down)
|
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):
|
def initialize(self):
|
||||||
ConfigWidgetBase.initialize(self)
|
ConfigWidgetBase.initialize(self)
|
||||||
font = gprefs['font']
|
font = gprefs['font']
|
||||||
@ -238,6 +245,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
return rr
|
return rr
|
||||||
|
|
||||||
def refresh_gui(self, gui):
|
def refresh_gui(self, gui):
|
||||||
|
gui.library_view.model().set_color_templates()
|
||||||
self.update_font_display()
|
self.update_font_display()
|
||||||
gui.tags_view.reread_collapse_parameters()
|
gui.tags_view.reread_collapse_parameters()
|
||||||
gui.library_view.refresh_book_details()
|
gui.library_view.refresh_book_details()
|
||||||
|
@ -407,6 +407,84 @@ then the tags will be displayed each on their own line.</string>
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_5">
|
||||||
|
<attribute name="icon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/cover_flow.png</normaloff>:/images/cover_flow.png</iconset>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Column Coloring</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="column_color_layout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Column name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Selection template</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QComboBox" name="opt_column_color_name_1">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="LineEditWithTextBox" name="opt_column_color_template_1">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QComboBox" name="opt_column_color_name_2">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="LineEditWithTextBox" name="opt_column_color_template_2">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QComboBox" name="opt_column_color_name_3">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="LineEditWithTextBox" name="opt_column_color_template_3">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QComboBox" name="opt_column_color_name_4">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="LineEditWithTextBox" name="opt_column_color_template_4">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QComboBox" name="opt_column_color_name_5">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="LineEditWithTextBox" name="opt_column_color_template_5">
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0" colspan="2">
|
||||||
|
<spacer name="verticalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>690</width>
|
||||||
|
<height>283</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -417,6 +495,11 @@ then the tags will be displayed each on their own line.</string>
|
|||||||
<extends>QLineEdit</extends>
|
<extends>QLineEdit</extends>
|
||||||
<header>calibre/gui2/complete.h</header>
|
<header>calibre/gui2/complete.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>LineEditWithTextBox</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>calibre/gui2/dialogs/template_line_editor.h</header>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../resources/images.qrc"/>
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
@ -211,6 +211,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
defs = self.prefs.defaults
|
defs = self.prefs.defaults
|
||||||
defs['gui_restriction'] = defs['cs_restriction'] = ''
|
defs['gui_restriction'] = defs['cs_restriction'] = ''
|
||||||
defs['categories_using_hierarchy'] = []
|
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
|
# Migrate the bool tristate tweak
|
||||||
defs['bools_are_tristate'] = \
|
defs['bools_are_tristate'] = \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user