mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-31 14:33:54 -04:00
Use coloring rules to change cells from text to icons
This commit is contained in:
parent
f606af13a1
commit
845b90e865
@ -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,
|
||||||
|
@ -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}"> {st} </span>
|
<span style="color: {c}; background-color: {bg2}"> {st} </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,7 +476,11 @@ class RuleEditor(QDialog): # {{{
|
|||||||
@property
|
@property
|
||||||
def rule(self):
|
def rule(self):
|
||||||
r = Rule(self.fm)
|
r = Rule(self.fm)
|
||||||
r.color = unicode(self.color_box.currentText())
|
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())
|
||||||
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())
|
||||||
for c in self.conditions:
|
for c in self.conditions:
|
||||||
@ -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()
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user