mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-31 14:33:54 -04:00
Allow multiple icons for column icons
Column icons: Allow the use of multiple icons with column icon rules. You can now have column icon rules display multiple icons in a single column, side by side. There are two ways to do this, either specify multiple icons when creating the rule, or create multiple rules that match the same book and specify the icon type to be 'composed' for every rule. See Preferences->Look & Feel->Column icons for details. Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
455afaa08f
@ -7,7 +7,7 @@ import json, os, traceback
|
|||||||
|
|
||||||
from PyQt4.Qt import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont,
|
from PyQt4.Qt import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont,
|
||||||
QRegExp, QApplication, QTextCharFormat, QColor, QCursor,
|
QRegExp, QApplication, QTextCharFormat, QColor, QCursor,
|
||||||
QIcon, QSize)
|
QIcon, QSize, QVariant)
|
||||||
|
|
||||||
from calibre import sanitize_file_name_unicode
|
from calibre import sanitize_file_name_unicode
|
||||||
from calibre.constants import config_dir
|
from calibre.constants import config_dir
|
||||||
@ -19,7 +19,6 @@ from calibre.ebooks.metadata.book.formatter import SafeFormat
|
|||||||
from calibre.library.coloring import (displayable_columns, color_row_key)
|
from calibre.library.coloring import (displayable_columns, color_row_key)
|
||||||
from calibre.gui2 import error_dialog, choose_files, pixmap_to_data
|
from calibre.gui2 import error_dialog, choose_files, pixmap_to_data
|
||||||
|
|
||||||
|
|
||||||
class ParenPosition:
|
class ParenPosition:
|
||||||
|
|
||||||
def __init__(self, block, pos, paren):
|
def __init__(self, block, pos, paren):
|
||||||
@ -247,9 +246,15 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
|||||||
self.icon_file_names.append(icon_file)
|
self.icon_file_names.append(icon_file)
|
||||||
self.icon_file_names.sort(key=sort_key)
|
self.icon_file_names.sort(key=sort_key)
|
||||||
self.update_filename_box()
|
self.update_filename_box()
|
||||||
self.icon_with_text.setChecked(True)
|
|
||||||
if icon_rule_kind == 'icon_only':
|
dex = 0
|
||||||
self.icon_without_text.setChecked(True)
|
from calibre.gui2.preferences.coloring import icon_rule_kinds
|
||||||
|
for i,tup in enumerate(icon_rule_kinds):
|
||||||
|
txt,val = tup
|
||||||
|
self.icon_kind.addItem(txt, userData=QVariant(val))
|
||||||
|
if val == icon_rule_kind:
|
||||||
|
dex = i
|
||||||
|
self.icon_kind.setCurrentIndex(dex)
|
||||||
self.icon_field.setCurrentIndex(self.icon_field.findData(icon_field_key))
|
self.icon_field.setCurrentIndex(self.icon_field.findData(icon_field_key))
|
||||||
|
|
||||||
if mi:
|
if mi:
|
||||||
@ -410,7 +415,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
|||||||
self.rule = (unicode(self.colored_field.itemData(
|
self.rule = (unicode(self.colored_field.itemData(
|
||||||
self.colored_field.currentIndex()).toString()), txt)
|
self.colored_field.currentIndex()).toString()), txt)
|
||||||
elif self.iconing:
|
elif self.iconing:
|
||||||
rt = 'icon' if self.icon_with_text.isChecked() else 'icon_only'
|
rt = unicode(self.icon_kind.itemData(self.icon_kind.currentIndex()).toString())
|
||||||
self.rule = (rt,
|
self.rule = (rt,
|
||||||
unicode(self.icon_field.itemData(
|
unicode(self.icon_field.itemData(
|
||||||
self.icon_field.currentIndex()).toString()),
|
self.icon_field.currentIndex()).toString()),
|
||||||
|
@ -69,33 +69,19 @@
|
|||||||
<widget class="QWidget" name="icon_layout">
|
<widget class="QWidget" name="icon_layout">
|
||||||
<layout class="QGridLayout">
|
<layout class="QGridLayout">
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QGroupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Kind</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="icon_without_text">
|
<widget class="QLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>icon with no text</string>
|
<string>Kind:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="icon_with_text">
|
<widget class="QComboBox" name="icon_kind">
|
||||||
<property name="text">
|
|
||||||
<string>icon with text</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>100</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="icon_chooser_label">
|
<widget class="QLabel" name="icon_chooser_label">
|
||||||
|
@ -9,7 +9,7 @@ import functools, re, os, traceback, errno, time
|
|||||||
from collections import defaultdict, namedtuple
|
from collections import defaultdict, namedtuple
|
||||||
|
|
||||||
from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
|
from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage,
|
||||||
QModelIndex, QVariant, QDateTime, QColor, QPixmap)
|
QModelIndex, QVariant, QDateTime, QColor, QPixmap, QPainter)
|
||||||
|
|
||||||
from calibre.gui2 import NONE, error_dialog
|
from calibre.gui2 import NONE, error_dialog
|
||||||
from calibre.utils.search_query_parser import ParseException
|
from calibre.utils.search_query_parser import ParseException
|
||||||
@ -61,7 +61,7 @@ class ColumnColor(object): # {{{
|
|||||||
return color_cache[id_][key]
|
return color_cache[id_][key]
|
||||||
try:
|
try:
|
||||||
if self.mi is None:
|
if self.mi is None:
|
||||||
self.mi = db.get_metadata(id_, index_is_id=True)
|
self.mi = db.new_api.get_proxy_metadata(id_)
|
||||||
color = self.formatter.safe_format(fmt, self.mi, '', self.mi)
|
color = self.formatter.safe_format(fmt, self.mi, '', self.mi)
|
||||||
if color in self.colors:
|
if color in self.colors:
|
||||||
color = QColor(color)
|
color = QColor(color)
|
||||||
@ -76,38 +76,68 @@ class ColumnColor(object): # {{{
|
|||||||
|
|
||||||
class ColumnIcon(object): # {{{
|
class ColumnIcon(object): # {{{
|
||||||
|
|
||||||
def __init__(self, formatter):
|
def __init__(self, formatter, model):
|
||||||
self.mi = None
|
self.mi = None
|
||||||
self.formatter = formatter
|
self.formatter = formatter
|
||||||
|
self.model = model
|
||||||
|
|
||||||
def __call__(self, id_, key, fmt, kind, db, icon_cache, icon_bitmap_cache):
|
def __call__(self, id_, key, fmts, cache_index, db, icon_cache, icon_bitmap_cache):
|
||||||
dex = key+kind
|
if id_ in icon_cache and cache_index in icon_cache[id_]:
|
||||||
if id_ in icon_cache and dex in icon_cache[id_]:
|
|
||||||
self.mi = None
|
self.mi = None
|
||||||
return icon_cache[id_][dex]
|
return icon_cache[id_][cache_index]
|
||||||
try:
|
try:
|
||||||
if self.mi is None:
|
if self.mi is None:
|
||||||
self.mi = db.get_metadata(id_, index_is_id=True)
|
self.mi = db.new_api.get_proxy_metadata(id_)
|
||||||
icon = self.formatter.safe_format(fmt, self.mi, '', self.mi)
|
icons = []
|
||||||
if icon:
|
for kind, fmt in fmts:
|
||||||
if icon in icon_bitmap_cache:
|
rule_icons = self.formatter.safe_format(fmt, self.mi, '', self.mi)
|
||||||
icon_bitmap = icon_bitmap_cache[icon]
|
if not rule_icons:
|
||||||
icon_cache[id_][dex] = icon_bitmap
|
continue
|
||||||
|
icon_list = [ic.strip() for ic in rule_icons.split(':')]
|
||||||
|
if icon_list and not kind.endswith('_composed'):
|
||||||
|
icons = icon_list
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
icons.extend(icon_list)
|
||||||
|
|
||||||
|
if icons:
|
||||||
|
icon_string = ':'.join(icons)
|
||||||
|
if icon_string in icon_bitmap_cache:
|
||||||
|
icon_bitmap = icon_bitmap_cache[icon_string]
|
||||||
|
icon_cache[id_][cache_index] = icon_bitmap
|
||||||
return icon_bitmap
|
return icon_bitmap
|
||||||
|
|
||||||
|
icon_bitmaps = []
|
||||||
|
total_width = 0
|
||||||
|
for icon in icons:
|
||||||
d = os.path.join(config_dir, 'cc_icons', icon)
|
d = os.path.join(config_dir, 'cc_icons', icon)
|
||||||
if (os.path.exists(d)):
|
if (os.path.exists(d)):
|
||||||
icon_bitmap = QPixmap(d)
|
bm = QPixmap(d)
|
||||||
h = icon_bitmap.height()
|
icon_bitmaps.append(bm)
|
||||||
w = icon_bitmap.width()
|
total_width += bm.width()
|
||||||
# If the image is landscape and width is more than 50%
|
if len(icon_bitmaps) > 1:
|
||||||
# large than height, use the pixmap. This tells Qt to display
|
i = len(icon_bitmaps)
|
||||||
# the image full width. It might be clipped to row height.
|
result = QPixmap((i * 128) + ((i-1)*2), 128)
|
||||||
if w < (3 * h)/2:
|
result.fill(Qt.transparent)
|
||||||
icon_bitmap = QIcon(icon_bitmap)
|
painter = QPainter(result)
|
||||||
icon_cache[id_][dex] = icon_bitmap
|
x = 0
|
||||||
icon_bitmap_cache[icon] = icon_bitmap
|
for bm in icon_bitmaps:
|
||||||
|
painter.drawPixmap(x, 0, bm)
|
||||||
|
x += bm.width() + 2
|
||||||
|
painter.end()
|
||||||
|
else:
|
||||||
|
result = icon_bitmaps[0]
|
||||||
|
|
||||||
|
# If the image height is less than the row height, leave it alone
|
||||||
|
# The -2 allows for a pixel above and below. Also ensure that
|
||||||
|
# it is always a bit positive
|
||||||
|
rh = max(2, self.model.row_height - 2)
|
||||||
|
if result.height() > rh:
|
||||||
|
result = result.scaledToHeight(rh, mode=Qt.SmoothTransformation)
|
||||||
|
icon_cache[id_][cache_index] = result
|
||||||
|
icon_bitmap_cache[icon_string] = result
|
||||||
self.mi = None
|
self.mi = None
|
||||||
return icon_bitmap
|
return result
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
# }}}
|
# }}}
|
||||||
@ -145,7 +175,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
|
self.colors = frozenset([unicode(c) for c in QColor.colorNames()])
|
||||||
self._clear_caches()
|
self._clear_caches()
|
||||||
self.column_color = ColumnColor(self.formatter, self.colors)
|
self.column_color = ColumnColor(self.formatter, self.colors)
|
||||||
self.column_icon = ColumnIcon(self.formatter)
|
self.column_icon = ColumnIcon(self.formatter, self)
|
||||||
|
|
||||||
self.book_on_device = None
|
self.book_on_device = None
|
||||||
self.editable_cols = ['title', 'authors', 'rating', 'publisher',
|
self.editable_cols = ['title', 'authors', 'rating', 'publisher',
|
||||||
@ -168,6 +198,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.row_height = 0
|
||||||
self.read_config()
|
self.read_config()
|
||||||
|
|
||||||
def _clear_caches(self):
|
def _clear_caches(self):
|
||||||
@ -176,6 +207,9 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.icon_bitmap_cache = {}
|
self.icon_bitmap_cache = {}
|
||||||
self.color_row_fmt_cache = None
|
self.color_row_fmt_cache = None
|
||||||
|
|
||||||
|
def set_row_height(self, height):
|
||||||
|
self.row_height = height
|
||||||
|
|
||||||
def change_alignment(self, colname, alignment):
|
def change_alignment(self, colname, alignment):
|
||||||
if colname in self.column_map and alignment in ('left', 'right', 'center'):
|
if colname in self.column_map and alignment in ('left', 'right', 'center'):
|
||||||
old = self.alignment_map.get(colname, 'left')
|
old = self.alignment_map.get(colname, 'left')
|
||||||
@ -765,16 +799,21 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
if rules:
|
if rules:
|
||||||
key = self.column_map[col]
|
key = self.column_map[col]
|
||||||
id_ = None
|
id_ = None
|
||||||
|
fmts = []
|
||||||
for kind, k, fmt in rules:
|
for kind, k, fmt in rules:
|
||||||
if k == key and kind == 'icon_only':
|
if k == key and kind in {'icon_only', 'icon_only_composed'}:
|
||||||
if id_ is None:
|
if id_ is None:
|
||||||
id_ = self.id(index)
|
id_ = self.id(index)
|
||||||
self.column_icon.mi = None
|
self.column_icon.mi = None
|
||||||
ccicon = self.column_icon(id_, key, fmt, 'icon_only', self.db,
|
fmts.append((kind, fmt))
|
||||||
|
|
||||||
|
if fmts:
|
||||||
|
cache_index = key + ':DisplayRole'
|
||||||
|
ccicon = self.column_icon(id_, key, fmts, cache_index, self.db,
|
||||||
self.icon_cache, self.icon_bitmap_cache)
|
self.icon_cache, self.icon_bitmap_cache)
|
||||||
if ccicon is not None:
|
if ccicon is not None:
|
||||||
return NONE
|
return NONE
|
||||||
self.icon_cache[id_][key+'icon_only'] = None
|
self.icon_cache[id_][cache_index] = 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())
|
||||||
@ -831,21 +870,25 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
key = self.column_map[col]
|
key = self.column_map[col]
|
||||||
id_ = None
|
id_ = None
|
||||||
need_icon_with_text = False
|
need_icon_with_text = False
|
||||||
|
fmts = []
|
||||||
for kind, k, fmt in rules:
|
for kind, k, fmt in rules:
|
||||||
if k == key and kind in ('icon', 'icon_only'):
|
if k == key and kind.startswith('icon'):
|
||||||
if id_ is None:
|
if id_ is None:
|
||||||
id_ = self.id(index)
|
id_ = self.id(index)
|
||||||
self.column_icon.mi = None
|
self.column_icon.mi = None
|
||||||
if kind == 'icon':
|
fmts.append((kind, fmt))
|
||||||
|
if kind in ('icon', 'icon_composed'):
|
||||||
need_icon_with_text = True
|
need_icon_with_text = True
|
||||||
ccicon = self.column_icon(id_, key, fmt, kind, self.db,
|
if fmts:
|
||||||
|
cache_index = key + ':DecorationRole'
|
||||||
|
ccicon = self.column_icon(id_, key, fmts, cache_index, self.db,
|
||||||
self.icon_cache, self.icon_bitmap_cache)
|
self.icon_cache, self.icon_bitmap_cache)
|
||||||
if ccicon is not None:
|
if ccicon is not None:
|
||||||
return ccicon
|
return ccicon
|
||||||
if need_icon_with_text:
|
if need_icon_with_text:
|
||||||
self.icon_cache[id_][key+'icon'] = self.bool_blank_icon
|
self.icon_cache[id_][cache_index] = self.bool_blank_icon
|
||||||
return self.bool_blank_icon
|
return self.bool_blank_icon
|
||||||
self.icon_cache[id_][key+'icon'] = None
|
self.icon_cache[id_][cache_index] = 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,
|
||||||
|
@ -649,6 +649,7 @@ class BooksView(QTableView): # {{{
|
|||||||
self.resizeRowToContents(0)
|
self.resizeRowToContents(0)
|
||||||
self.verticalHeader().setDefaultSectionSize(self.rowHeight(0) +
|
self.verticalHeader().setDefaultSectionSize(self.rowHeight(0) +
|
||||||
gprefs['extra_row_spacing'])
|
gprefs['extra_row_spacing'])
|
||||||
|
self._model.set_row_height(self.rowHeight(0))
|
||||||
self.row_sizing_done = True
|
self.row_sizing_done = True
|
||||||
|
|
||||||
def resize_column_to_fit(self, column):
|
def resize_column_to_fit(self, column):
|
||||||
|
@ -7,13 +7,13 @@ __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
|
import os, textwrap
|
||||||
|
|
||||||
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, QStandardItem, QStandardItemModel, QCheckBox)
|
||||||
|
|
||||||
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
|
||||||
@ -29,7 +29,9 @@ from calibre.utils.icu import lower
|
|||||||
all_columns_string = _('All Columns')
|
all_columns_string = _('All Columns')
|
||||||
|
|
||||||
icon_rule_kinds = [(_('icon with text'), 'icon'),
|
icon_rule_kinds = [(_('icon with text'), 'icon'),
|
||||||
(_('icon with no text'), 'icon_only') ]
|
(_('icon with no text'), 'icon_only'),
|
||||||
|
(_('composed icons w/text'), 'icon_composed'),
|
||||||
|
(_('composed icons w/no text'), 'icon_only_composed'),]
|
||||||
|
|
||||||
class ConditionEditor(QWidget): # {{{
|
class ConditionEditor(QWidget): # {{{
|
||||||
|
|
||||||
@ -312,6 +314,10 @@ class RuleEditor(QDialog): # {{{
|
|||||||
for tt, t in icon_rule_kinds:
|
for tt, t in icon_rule_kinds:
|
||||||
self.kind_box.addItem(tt, t)
|
self.kind_box.addItem(tt, t)
|
||||||
l.addWidget(self.kind_box, 2, 1)
|
l.addWidget(self.kind_box, 2, 1)
|
||||||
|
self.kind_box.setToolTip(textwrap.fill(_(
|
||||||
|
'If you choose composed icons and multiple rules match, then all the'
|
||||||
|
' matching icons will be combined, otherwise the icon from the'
|
||||||
|
' first rule to match will be used.')))
|
||||||
|
|
||||||
self.l3 = l3 = QLabel(_('of the column:'))
|
self.l3 = l3 = QLabel(_('of the column:'))
|
||||||
l.addWidget(l3, 2, 2)
|
l.addWidget(l3, 2, 2)
|
||||||
@ -331,7 +337,6 @@ class RuleEditor(QDialog): # {{{
|
|||||||
l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 7)
|
l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 7)
|
||||||
else:
|
else:
|
||||||
self.filename_box = QComboBox()
|
self.filename_box = QComboBox()
|
||||||
self.filename_box.setInsertPolicy(self.filename_box.InsertAlphabetically)
|
|
||||||
d = os.path.join(config_dir, 'cc_icons')
|
d = os.path.join(config_dir, 'cc_icons')
|
||||||
self.icon_file_names = []
|
self.icon_file_names = []
|
||||||
if os.path.exists(d):
|
if os.path.exists(d):
|
||||||
@ -341,9 +346,15 @@ class RuleEditor(QDialog): # {{{
|
|||||||
if icon_file.endswith('.png'):
|
if icon_file.endswith('.png'):
|
||||||
self.icon_file_names.append(icon_file)
|
self.icon_file_names.append(icon_file)
|
||||||
self.icon_file_names.sort(key=sort_key)
|
self.icon_file_names.sort(key=sort_key)
|
||||||
self.update_filename_box()
|
|
||||||
|
|
||||||
l.addWidget(self.filename_box, 2, 5)
|
vb = QVBoxLayout()
|
||||||
|
self.multiple_icon_cb = QCheckBox(_('Choose more than one icon'))
|
||||||
|
vb.addWidget(self.multiple_icon_cb)
|
||||||
|
self.update_filename_box()
|
||||||
|
self.multiple_icon_cb.clicked.connect(self.multiple_box_clicked)
|
||||||
|
vb.addWidget(self.filename_box)
|
||||||
|
l.addLayout(vb, 2, 5)
|
||||||
|
|
||||||
self.filename_button = QPushButton(QIcon(I('document_open.png')),
|
self.filename_button = QPushButton(QIcon(I('document_open.png')),
|
||||||
_('&Add icon'))
|
_('&Add icon'))
|
||||||
l.addWidget(self.filename_button, 2, 6)
|
l.addWidget(self.filename_button, 2, 6)
|
||||||
@ -401,18 +412,37 @@ 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)
|
||||||
else:
|
else:
|
||||||
|
self.rule_icon_files = []
|
||||||
self.filename_button.clicked.connect(self.filename_button_clicked)
|
self.filename_button.clicked.connect(self.filename_button_clicked)
|
||||||
|
|
||||||
self.resize(self.sizeHint())
|
self.resize(self.sizeHint())
|
||||||
|
|
||||||
|
def multiple_box_clicked(self):
|
||||||
|
self.update_filename_box()
|
||||||
|
self.update_icon_filenames_in_box()
|
||||||
|
|
||||||
def update_filename_box(self):
|
def update_filename_box(self):
|
||||||
self.filename_box.clear()
|
doing_multiple = self.multiple_icon_cb.isChecked()
|
||||||
|
|
||||||
|
model = QStandardItemModel()
|
||||||
|
self.filename_box.setModel(model)
|
||||||
self.icon_file_names.sort(key=sort_key)
|
self.icon_file_names.sort(key=sort_key)
|
||||||
self.filename_box.addItem('')
|
if doing_multiple:
|
||||||
self.filename_box.addItems(self.icon_file_names)
|
item = QStandardItem(_('Open to see checkboxes'))
|
||||||
|
else:
|
||||||
|
item = QStandardItem('')
|
||||||
|
model.appendRow(item)
|
||||||
|
|
||||||
for i,filename in enumerate(self.icon_file_names):
|
for i,filename in enumerate(self.icon_file_names):
|
||||||
|
item = QStandardItem(filename)
|
||||||
|
if doing_multiple:
|
||||||
|
item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled);
|
||||||
|
item.setData(Qt.Unchecked, Qt.CheckStateRole)
|
||||||
|
else:
|
||||||
|
item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable);
|
||||||
icon = QIcon(os.path.join(config_dir, 'cc_icons', filename))
|
icon = QIcon(os.path.join(config_dir, 'cc_icons', filename))
|
||||||
self.filename_box.setItemIcon(i+1, icon)
|
item.setIcon(icon)
|
||||||
|
model.appendRow(item)
|
||||||
|
|
||||||
def update_color_label(self):
|
def update_color_label(self):
|
||||||
pal = QApplication.palette()
|
pal = QApplication.palette()
|
||||||
@ -432,9 +462,9 @@ class RuleEditor(QDialog): # {{{
|
|||||||
all_files=False, select_only_single_file=True)
|
all_files=False, select_only_single_file=True)
|
||||||
if path:
|
if path:
|
||||||
icon_path = path[0]
|
icon_path = path[0]
|
||||||
icon_name = sanitize_file_name_unicode(
|
icon_name = lower(sanitize_file_name_unicode(
|
||||||
os.path.splitext(
|
os.path.splitext(
|
||||||
os.path.basename(icon_path))[0]+'.png')
|
os.path.basename(icon_path))[0]+'.png'))
|
||||||
if icon_name not in self.icon_file_names:
|
if icon_name not in self.icon_file_names:
|
||||||
self.icon_file_names.append(icon_name)
|
self.icon_file_names.append(icon_name)
|
||||||
self.update_filename_box()
|
self.update_filename_box()
|
||||||
@ -449,6 +479,11 @@ class RuleEditor(QDialog): # {{{
|
|||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
if self.multiple_icon_cb.isChecked():
|
||||||
|
if icon_name not in self.rule_icon_files:
|
||||||
|
self.rule_icon_files.append(icon_name)
|
||||||
|
self.update_icon_filenames_in_box()
|
||||||
|
else:
|
||||||
self.filename_box.setCurrentIndex(self.filename_box.findText(icon_name))
|
self.filename_box.setCurrentIndex(self.filename_box.findText(icon_name))
|
||||||
self.filename_box.adjustSize()
|
self.filename_box.adjustSize()
|
||||||
except:
|
except:
|
||||||
@ -456,6 +491,35 @@ class RuleEditor(QDialog): # {{{
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def get_filenames_from_box(self):
|
||||||
|
if self.multiple_icon_cb.isChecked():
|
||||||
|
model = self.filename_box.model()
|
||||||
|
fnames = []
|
||||||
|
for i in range(1, model.rowCount()):
|
||||||
|
item = model.item(i, 0)
|
||||||
|
if item.checkState() == Qt.Checked:
|
||||||
|
fnames.append(lower(unicode(item.text())))
|
||||||
|
fname = ' : '.join(fnames)
|
||||||
|
else:
|
||||||
|
fname = lower(unicode(self.filename_box.currentText()))
|
||||||
|
return fname
|
||||||
|
|
||||||
|
def update_icon_filenames_in_box(self):
|
||||||
|
if self.rule_icon_files:
|
||||||
|
if not self.multiple_icon_cb.isChecked():
|
||||||
|
idx = self.filename_box.findText(self.rule_icon_files[0])
|
||||||
|
if idx >= 0:
|
||||||
|
self.filename_box.setCurrentIndex(idx)
|
||||||
|
else:
|
||||||
|
self.filename_box.setCurrentIndex(0)
|
||||||
|
else:
|
||||||
|
model = self.filename_box.model()
|
||||||
|
for icon in self.rule_icon_files:
|
||||||
|
idx = self.filename_box.findText(icon)
|
||||||
|
if idx >= 0:
|
||||||
|
item = model.item(idx)
|
||||||
|
item.setCheckState(Qt.Checked)
|
||||||
|
|
||||||
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)
|
||||||
@ -468,13 +532,15 @@ class RuleEditor(QDialog): # {{{
|
|||||||
if idx >= 0:
|
if idx >= 0:
|
||||||
self.color_box.setCurrentIndex(idx)
|
self.color_box.setCurrentIndex(idx)
|
||||||
else:
|
else:
|
||||||
self.kind_box.setCurrentIndex(0 if kind == 'icon' else 1)
|
for i,tup in enumerate(icon_rule_kinds):
|
||||||
if rule.color:
|
if kind == tup[1]:
|
||||||
idx = self.filename_box.findText(rule.color)
|
self.kind_box.setCurrentIndex(i)
|
||||||
if idx >= 0:
|
break
|
||||||
self.filename_box.setCurrentIndex(idx)
|
self.rule_icon_files = [ic.strip() for ic in rule.color.split(':')]
|
||||||
else:
|
if len(self.rule_icon_files) > 1:
|
||||||
self.filename_box.setCurrentIndex(0)
|
self.multiple_icon_cb.setChecked(True)
|
||||||
|
self.update_filename_box()
|
||||||
|
self.update_icon_filenames_in_box()
|
||||||
|
|
||||||
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())
|
||||||
@ -492,10 +558,9 @@ class RuleEditor(QDialog): # {{{
|
|||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
if self.rule_kind != 'color':
|
if self.rule_kind != 'color':
|
||||||
fname = lower(unicode(self.filename_box.currentText()))
|
fname = self.get_filenames_from_box()
|
||||||
if not fname:
|
if not fname:
|
||||||
error_dialog(self, _('No icon selected'),
|
error_dialog(self, _('No icon selected'),
|
||||||
_('You must choose an icon for this rule'), show=True)
|
_('You must choose an icon for this rule'), show=True)
|
||||||
@ -528,7 +593,7 @@ class RuleEditor(QDialog): # {{{
|
|||||||
def rule(self):
|
def rule(self):
|
||||||
r = Rule(self.fm)
|
r = Rule(self.fm)
|
||||||
if self.rule_kind != 'color':
|
if self.rule_kind != 'color':
|
||||||
r.color = unicode(self.filename_box.currentText())
|
r.color = self.get_filenames_from_box()
|
||||||
else:
|
else:
|
||||||
r.color = unicode(self.color_box.currentText())
|
r.color = unicode(self.color_box.currentText())
|
||||||
idx = self.column_box.currentIndex()
|
idx = self.column_box.currentIndex()
|
||||||
@ -635,6 +700,15 @@ class RulesModel(QAbstractListModel): # {{{
|
|||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def rule_to_html(self, kind, col, rule):
|
def rule_to_html(self, kind, col, rule):
|
||||||
|
trans_kind = 'not found'
|
||||||
|
if kind == 'color':
|
||||||
|
trans_kind = _('color')
|
||||||
|
else:
|
||||||
|
for tt, t in icon_rule_kinds:
|
||||||
|
if kind == t:
|
||||||
|
trans_kind = tt
|
||||||
|
break
|
||||||
|
|
||||||
if not isinstance(rule, Rule):
|
if not isinstance(rule, Rule):
|
||||||
if kind == 'color':
|
if kind == 'color':
|
||||||
return _('''
|
return _('''
|
||||||
@ -646,21 +720,11 @@ class RulesModel(QAbstractListModel): # {{{
|
|||||||
<p>Advanced Rule: set <b>%(typ)s</b> for column <b>%(col)s</b>:
|
<p>Advanced Rule: set <b>%(typ)s</b> for column <b>%(col)s</b>:
|
||||||
<pre>%(rule)s</pre>
|
<pre>%(rule)s</pre>
|
||||||
''')%dict(col=col,
|
''')%dict(col=col,
|
||||||
typ=icon_rule_kinds[0][0]
|
typ=trans_kind,
|
||||||
if kind == icon_rule_kinds[0][1] else icon_rule_kinds[1][0],
|
|
||||||
rule=prepare_string_for_xml(rule))
|
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]
|
||||||
|
|
||||||
trans_kind = 'not found'
|
|
||||||
if kind == 'color':
|
|
||||||
trans_kind = _('color')
|
|
||||||
else:
|
|
||||||
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
|
||||||
conditions are met:</p>
|
conditions are met:</p>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user