mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add field box to color wizard
This commit is contained in:
parent
f25c423261
commit
19261f15ee
@ -5,12 +5,16 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from functools import partial
|
||||
from collections import defaultdict
|
||||
|
||||
from PyQt4.Qt import (QLineEdit, QDialog, QGridLayout, QLabel, QCheckBox,
|
||||
QDialogButtonBox, QColor, QComboBox, QIcon)
|
||||
|
||||
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
||||
from calibre.gui2.complete import MultiCompleteLineEdit
|
||||
from calibre.gui2 import error_dialog
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
class TemplateLineEditor(QLineEdit):
|
||||
|
||||
@ -26,8 +30,8 @@ class TemplateLineEditor(QLineEdit):
|
||||
def set_mi(self, mi):
|
||||
self.mi = mi
|
||||
|
||||
def set_tags(self, tags):
|
||||
self.tags = tags
|
||||
def set_db(self, db):
|
||||
self.db = db
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
menu = self.createStandardContextMenu()
|
||||
@ -35,9 +39,6 @@ class TemplateLineEditor(QLineEdit):
|
||||
|
||||
action_open_editor = menu.addAction(_('Open Template Editor'))
|
||||
action_open_editor.triggered.connect(self.open_editor)
|
||||
if self.tags:
|
||||
action_tag_wizard = menu.addAction(_('Open Tag Wizard'))
|
||||
action_tag_wizard.triggered.connect(self.tag_wizard)
|
||||
menu.exec_(event.globalPos())
|
||||
|
||||
def open_editor(self):
|
||||
@ -53,84 +54,117 @@ class TemplateLineEditor(QLineEdit):
|
||||
_('The text in the box was not generated by this wizard'),
|
||||
show=True, show_copy_button=False)
|
||||
return
|
||||
d = TagWizard(self, self.tags, unicode(self.text()))
|
||||
d = TagWizard(self, self.db, unicode(self.text()))
|
||||
if d.exec_():
|
||||
self.setText(d.template)
|
||||
|
||||
class TagWizard(QDialog):
|
||||
|
||||
def __init__(self, parent, tags, txt):
|
||||
def __init__(self, parent, db, txt):
|
||||
QDialog.__init__(self, parent)
|
||||
self.setWindowTitle(_('Tag Wizard'))
|
||||
self.setWindowTitle(_('Coloring Wizard'))
|
||||
self.setWindowIcon(QIcon(I('wizard.png')))
|
||||
|
||||
self.tags = tags
|
||||
self.columns = []
|
||||
self.completion_values = defaultdict(dict)
|
||||
for k in db.all_field_keys():
|
||||
m = db.metadata_for_field(k)
|
||||
if m['datatype'] in ('text', 'enumeration', 'series'):
|
||||
self.columns.append(k)
|
||||
if m['is_custom']:
|
||||
# self.completion_values[k] = {}
|
||||
self.completion_values[k]['v'] = db.all_custom(m['label'])
|
||||
elif k == 'tags':
|
||||
# self.completion_values[k] = {}
|
||||
self.completion_values[k]['v'] = db.all_tags()
|
||||
else:
|
||||
f = getattr(db, 'all' + k, None)
|
||||
if f:
|
||||
self.completion_values[k] = {}
|
||||
self.completion_values[k]['v'] = [v[1] for v in f()]
|
||||
if k in self.completion_values:
|
||||
self.completion_values[k]['m'] = m['is_multiple']
|
||||
|
||||
self.columns.sort(key=sort_key)
|
||||
self.columns.insert(0, '')
|
||||
|
||||
l = QGridLayout()
|
||||
self.setLayout(l)
|
||||
l.setColumnStretch(0, 1)
|
||||
l.setColumnMinimumWidth(0, 300)
|
||||
h = QLabel(_('Tags (see the popup help for more information)'))
|
||||
l.setColumnStretch(1, 10)
|
||||
l.setColumnMinimumWidth(1, 300)
|
||||
|
||||
h = QLabel(_('Column'))
|
||||
l.addWidget(h, 0, 0, 1, 1)
|
||||
|
||||
h = QLabel(_('Values (see the popup help for more information)'))
|
||||
h.setToolTip('<p>' +
|
||||
_('You can enter more than one tag per box, separated by commas. '
|
||||
_('You can enter more than one value per box, separated by commas. '
|
||||
'The comparison ignores letter case.<br>'
|
||||
'A tag value can be a regular expression. Check the box to turn '
|
||||
'A value can be a regular expression. Check the box to turn '
|
||||
'them on. When using regular expressions, note that the wizard '
|
||||
'puts anchors (^ and $) around the expression, so you '
|
||||
'must ensure your expression matches from the beginning '
|
||||
'to the end of the tag.<br>'
|
||||
'to the end of the column you are checking.<br>'
|
||||
'Regular expression examples:') + '<ul>' +
|
||||
_('<li><code><b>.*</b></code> matches any tag. No empty tags are '
|
||||
'checked, so you don\'t need to worry about empty strings</li>'
|
||||
'<li><code><b>A.*</b></code> matches any tag beginning with A</li>'
|
||||
'<li><code><b>.*mystery.*</b></code> matches any tag containing '
|
||||
_('<li><code><b>.*</b></code> matches anything in the column. No '
|
||||
'empty values are checked, so you don\'t need to worry about '
|
||||
'empty strings</li>'
|
||||
'<li><code><b>A.*</b></code> matches anything beginning with A</li>'
|
||||
'<li><code><b>.*mystery.*</b></code> matches anything containing '
|
||||
'the word "mystery"</li>') + '</ul></p>')
|
||||
l.addWidget(h , 0, 0, 1, 1)
|
||||
l.addWidget(h , 0, 1, 1, 1)
|
||||
|
||||
c = QLabel(_('is RE'))
|
||||
c.setToolTip('<p>' +
|
||||
_('Check this box if the tag box contains regular expressions') + '</p>')
|
||||
l.addWidget(c, 0, 1, 1, 1)
|
||||
_('Check this box if the values box contains regular expressions') + '</p>')
|
||||
l.addWidget(c, 0, 2, 1, 1)
|
||||
|
||||
c = QLabel(_('Color if tag found'))
|
||||
c = QLabel(_('Color if value found'))
|
||||
c.setToolTip('<p>' +
|
||||
_('At least one of the two color boxes must have a value. Leave '
|
||||
'one color box empty if you want the template to use the next '
|
||||
'line in this wizard. If both boxes are filled in, the rest of '
|
||||
'the lines in this wizard will be ignored.') + '</p>')
|
||||
l.addWidget(c, 0, 2, 1, 1)
|
||||
c = QLabel(_('Color if tag not found'))
|
||||
l.addWidget(c, 0, 3, 1, 1)
|
||||
c = QLabel(_('Color if value not found'))
|
||||
c.setToolTip('<p>' +
|
||||
_('This box is usually filled in only on the last test. If it is '
|
||||
'filled in before the last test, then the color for tag found box '
|
||||
'filled in before the last test, then the color for value found box '
|
||||
'must be empty or all the rest of the tests will be ignored.') + '</p>')
|
||||
l.addWidget(c, 0, 3, 1, 1)
|
||||
l.addWidget(c, 0, 4, 1, 1)
|
||||
self.tagboxes = []
|
||||
self.colorboxes = []
|
||||
self.nfcolorboxes = []
|
||||
self.reboxes = []
|
||||
self.colboxes = []
|
||||
self.colors = [unicode(s) for s in list(QColor.colorNames())]
|
||||
self.colors.insert(0, '')
|
||||
for i in range(0, 10):
|
||||
w = QComboBox()
|
||||
w.addItems(self.columns)
|
||||
l.addWidget(w, i+1, 0, 1, 1)
|
||||
self.colboxes.append(w)
|
||||
|
||||
tb = MultiCompleteLineEdit(self)
|
||||
tb.set_separator(', ')
|
||||
tb.update_items_cache(self.tags)
|
||||
self.tagboxes.append(tb)
|
||||
l.addWidget(tb, i+1, 0, 1, 1)
|
||||
l.addWidget(tb, i+1, 1, 1, 1)
|
||||
w.currentIndexChanged[str].connect(partial(self.column_changed, valbox=tb))
|
||||
|
||||
w = QCheckBox(self)
|
||||
self.reboxes.append(w)
|
||||
l.addWidget(w, i+1, 1, 1, 1)
|
||||
|
||||
w = QComboBox(self)
|
||||
w.addItems(self.colors)
|
||||
self.colorboxes.append(w)
|
||||
l.addWidget(w, i+1, 2, 1, 1)
|
||||
|
||||
w = QComboBox(self)
|
||||
w.addItems(self.colors)
|
||||
self.nfcolorboxes.append(w)
|
||||
self.colorboxes.append(w)
|
||||
l.addWidget(w, i+1, 3, 1, 1)
|
||||
|
||||
w = QComboBox(self)
|
||||
w.addItems(self.colors)
|
||||
self.nfcolorboxes.append(w)
|
||||
l.addWidget(w, i+1, 4, 1, 1)
|
||||
|
||||
if txt:
|
||||
lines = txt.split('\n')[3:]
|
||||
i = 0
|
||||
@ -141,37 +175,59 @@ class TagWizard(QDialog):
|
||||
t, c = vals
|
||||
nc = ''
|
||||
re = False
|
||||
f = 'tags'
|
||||
else:
|
||||
t,c,nc,re = vals
|
||||
t,c,f,nc,re = vals
|
||||
try:
|
||||
self.colorboxes[i].setCurrentIndex(self.colorboxes[i].findText(c))
|
||||
self.nfcolorboxes[i].setCurrentIndex(self.nfcolorboxes[i].findText(nc))
|
||||
self.tagboxes[i].setText(t)
|
||||
self.reboxes[i].setChecked(re == '2')
|
||||
self.colboxes[i].setCurrentIndex(self.colboxes[i].findText(f))
|
||||
except:
|
||||
pass
|
||||
i += 1
|
||||
|
||||
bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel, parent=self)
|
||||
l.addWidget(bb, 100, 2, 1, 2)
|
||||
l.addWidget(bb, 100, 3, 1, 2)
|
||||
bb.accepted.connect(self.accepted)
|
||||
bb.rejected.connect(self.reject)
|
||||
self.template = ''
|
||||
|
||||
def column_changed(self, s, valbox=None):
|
||||
k = unicode(s)
|
||||
if k in self.completion_values:
|
||||
valbox.update_items_cache(self.completion_values[k]['v'])
|
||||
if self.completion_values[k]['m']:
|
||||
valbox.set_separator(', ')
|
||||
else:
|
||||
valbox.set_separator(None)
|
||||
else:
|
||||
valbox.update_items_cache([])
|
||||
valbox.set_separator(None)
|
||||
|
||||
def accepted(self):
|
||||
res = ("program:\n#tag wizard -- do not directly edit\n"
|
||||
" t = field('tags');\n first_non_empty(\n")
|
||||
" first_non_empty(\n")
|
||||
lines = []
|
||||
for tb, cb, nfcb, reb in zip(self.tagboxes, self.colorboxes,
|
||||
self.nfcolorboxes, self.reboxes):
|
||||
tags = [t.strip() for t in unicode(tb.text()).split(',') if t.strip()]
|
||||
for tb, cb, fb, nfcb, reb in zip(self.tagboxes, self.colorboxes,
|
||||
self.colboxes, self.nfcolorboxes, self.reboxes):
|
||||
f = unicode(fb.currentText())
|
||||
if not f:
|
||||
continue
|
||||
m = self.completion_values[f]['m']
|
||||
c = unicode(cb.currentText()).strip()
|
||||
nfc = unicode(nfcb.currentText()).strip()
|
||||
re = reb.checkState()
|
||||
if m:
|
||||
tags = [t.strip() for t in unicode(tb.text()).split(',') if t.strip()]
|
||||
if re == 2:
|
||||
tags = '$|^'.join(tags)
|
||||
else:
|
||||
tags = ','.join(tags)
|
||||
else:
|
||||
tags = unicode(tb.text()).strip()
|
||||
|
||||
if not tags or not (c or nfc):
|
||||
continue
|
||||
if c not in self.colors:
|
||||
@ -185,24 +241,33 @@ class TagWizard(QDialog):
|
||||
show=True, show_copy_button=False)
|
||||
return False
|
||||
if re == 2:
|
||||
lines.append(" in_list(t, ',', '^{0}$', '{1}', '{2}')".\
|
||||
format(tags, c, nfc))
|
||||
if m:
|
||||
lines.append(" in_list(field('{3}'), ',', '^{0}$', '{1}', '{2}')".\
|
||||
format(tags, c, nfc, f))
|
||||
else:
|
||||
lines.append(" str_in_list(t, ',', '{0}', '{1}', '{2}')".\
|
||||
format(tags, c, nfc))
|
||||
lines.append(" contains(field('{3}'), '{0}', '{1}', '{2}')".\
|
||||
format(tags, c, nfc, f))
|
||||
else:
|
||||
if m:
|
||||
lines.append(" str_in_list(field('{3}'), ',', '{0}', '{1}', '{2}')".\
|
||||
format(tags, c, nfc, f))
|
||||
else:
|
||||
lines.append(" strcmp(field('{3}'), '{0}', '{2}', '{1}', '{2}')".\
|
||||
format(tags, c, nfc, f))
|
||||
res += ',\n'.join(lines)
|
||||
res += ')\n'
|
||||
self.template = res
|
||||
res = ''
|
||||
for tb, cb, nfcb, reb in zip(self.tagboxes, self.colorboxes,
|
||||
self.nfcolorboxes, self.reboxes):
|
||||
for tb, cb, fb, nfcb, reb in zip(self.tagboxes, self.colorboxes,
|
||||
self.colboxes, self.nfcolorboxes, self.reboxes):
|
||||
t = unicode(tb.text()).strip()
|
||||
if t.endswith(','):
|
||||
t = t[:-1]
|
||||
c = unicode(cb.currentText()).strip()
|
||||
f = unicode(fb.currentText())
|
||||
nfc = unicode(nfcb.currentText()).strip()
|
||||
re = unicode(reb.checkState())
|
||||
if t and c:
|
||||
res += '#' + t + ':|:' + c + ':|:' + nfc + ':|:' + re + '\n'
|
||||
if f and t and c:
|
||||
res += '#' + t + ':|:' + c + ':|:' + f +':|:' + nfc + ':|:' + re + '\n'
|
||||
self.template += res
|
||||
self.accept()
|
||||
|
@ -204,7 +204,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
choices.sort(key=sort_key)
|
||||
choices.insert(0, '')
|
||||
self.column_color_count = db.column_color_count+1
|
||||
tags = db.all_tags()
|
||||
|
||||
mi=None
|
||||
try:
|
||||
@ -217,7 +216,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
r('column_color_name_'+str(i), db.prefs, choices=choices)
|
||||
r('column_color_template_'+str(i), db.prefs)
|
||||
tpl = getattr(self, 'opt_column_color_template_'+str(i))
|
||||
tpl.set_tags(tags)
|
||||
tpl.set_db(db)
|
||||
tpl.set_mi(mi)
|
||||
toolbutton = getattr(self, 'opt_column_color_wizard_'+str(i))
|
||||
toolbutton.clicked.connect(tpl.tag_wizard)
|
||||
|
@ -331,6 +331,7 @@ class BuiltinInList(BuiltinFormatterFunction):
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, sep, pat, fv, nfv):
|
||||
l = [v.strip() for v in val.split(sep) if v.strip()]
|
||||
if l:
|
||||
for v in l:
|
||||
if re.search(pat, v, flags=re.I):
|
||||
return fv
|
||||
@ -349,6 +350,7 @@ class BuiltinStrInList(BuiltinFormatterFunction):
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, sep, str, fv, nfv):
|
||||
l = [v.strip() for v in val.split(sep) if v.strip()]
|
||||
c = [v.strip() for v in str.split(sep) if v.strip()]
|
||||
if l:
|
||||
for v in l:
|
||||
for t in c:
|
||||
if strcmp(t, v) == 0:
|
||||
|
Loading…
x
Reference in New Issue
Block a user