KG updates

This commit is contained in:
GRiker 2011-06-01 09:55:25 -06:00
commit c409d7188d
4 changed files with 123 additions and 66 deletions

View File

@ -44,11 +44,16 @@ class SafeFormat(TemplateFormatter):
def get_value(self, orig_key, args, kwargs): def get_value(self, orig_key, args, kwargs):
if not orig_key: if not orig_key:
return '' return ''
key = orig_key.lower() orig_key = orig_key.lower()
key = orig_key
if key != 'title_sort' and key not in TOP_LEVEL_IDENTIFIERS: if key != 'title_sort' and key not in TOP_LEVEL_IDENTIFIERS:
key = field_metadata.search_term_to_field_key(key) key = field_metadata.search_term_to_field_key(key)
if key is None or (self.book and key not in self.book.all_field_keys()): if key is None or (self.book and
raise ValueError(_('Value: unknown field ') + orig_key) key not in self.book.all_field_keys()):
if hasattr(self.book, orig_key):
key = orig_key
else:
raise ValueError(_('Value: unknown field ') + orig_key)
b = self.book.get_user_metadata(key, False) b = self.book.get_user_metadata(key, False)
if b and b['datatype'] == 'int' and self.book.get(key, 0) == 0: if b and b['datatype'] == 'int' and self.book.get(key, 0) == 0:
v = '' v = ''

View File

@ -95,25 +95,27 @@ class TemplateLineEditor(QLineEdit):
class TagWizard(QDialog): class TagWizard(QDialog):
text_template = " strcmp(field('{f}'), '{v}', '{fv}', '{tv}', '{fv}')" text_template = (" strcmp(field('{f}'), '{v}', '{ltv}', '{eqv}', '{gtv}')", True)
text_empty_template = " test(field('{f}'), '{fv}', '{tv}')" text_empty_template = (" test(field('{f}'), '{fv}', '{tv}')", False)
text_re_template = " contains(field('{f}'), '{v}', '{tv}', '{fv}')" text_re_template = (" contains(field('{f}'), '{v}', '{tv}', '{fv}')", False)
templates = { templates = {
'text.mult' : " str_in_list(field('{f}'), '{mult}', '{v}', '{tv}', '{fv}')", 'text.mult' : (" str_in_list(field('{f}'), '{mult}', '{v}', '{tv}', '{fv}')", False),
'text.mult.re' : " in_list(field('{f}'), '{mult}', '^{v}$', '{tv}', '{fv}')", 'text.mult.re' : (" in_list(field('{f}'), '{mult}', '^{v}$', '{tv}', '{fv}')", False),
'text.mult.empty' : " test(field('{f}'), '{fv}', '{tv}')", 'text.mult.empty' : (" test(field('{f}'), '{fv}', '{tv}')", False),
'text' : text_template, 'text' : text_template,
'text.re' : text_re_template, 'text.re' : text_re_template,
'text.empty' : text_empty_template, 'text.empty' : text_empty_template,
'rating' : " cmp(field('{f}'), '{v}', '{fv}', '{tv}', '{fv}')", 'rating' : (" cmp(raw_field('{f}'), '{v}', '{ltv}', '{eqv}', '{gtv}')", True),
'rating.empty' : text_empty_template, 'rating.empty' : text_empty_template,
'int' : " cmp(field('{f}'), '{v}', '{fv}', '{tv}', '{fv}')", 'int' : (" cmp(raw_field('{f}'), '{v}', '{ltv}', '{eqv}', '{gtv}')", True),
'int.empty' : text_empty_template, 'int.empty' : text_empty_template,
'float' : " cmp(field('{f}'), '{v}', '{fv}', '{tv}', '{fv}')", 'float' : (" cmp(raw_field('{f}'), '{v}', '{ltv}', '{eqv}', '{gtv}')", True),
'float.empty' : text_empty_template, 'float.empty' : text_empty_template,
'bool' : " strcmp(field('{f}'), '{v}', '{fv}', '{tv}', '{fv}')", 'bool' : (" strcmp(field('{f}'), '{v}', '{ltv}', '{eqv}', '{gtv}')", True),
'bool.empty' : text_empty_template, 'bool.empty' : text_empty_template,
'datetime' : (" strcmp(format_date(raw_field('{f}'), 'yyyyMMdd'), format_date('{v}', 'yyyyMMdd'), '{ltv}', '{eqv}', '{gtv}')", True),
'datetime.empty' : text_empty_template,
'series' : text_template, 'series' : text_template,
'series.re' : text_re_template, 'series.re' : text_re_template,
'series.empty' : text_empty_template, 'series.empty' : text_empty_template,
@ -128,6 +130,22 @@ class TagWizard(QDialog):
'comments.empty' : text_empty_template, 'comments.empty' : text_empty_template,
} }
relationals = ('=', '!=', '<', '>', '<=', '>=')
relational_truth_vals = {
'=': ('', '1', ''),
'!=': ('1', '', '1'),
'<': ('1', '', ''),
'>': ('', '', '1'),
'<=': ('1', '1', ''),
'>=': ('', '1', '1'),
}
@staticmethod
def uses_this_wizard(txt):
if not txt or txt.startswith('program:\n#tag wizard'):
return True
return False
def __init__(self, parent, db, txt, mi): def __init__(self, parent, db, txt, mi):
QDialog.__init__(self, parent) QDialog.__init__(self, parent)
self.setWindowTitle(_('Coloring Wizard')) self.setWindowTitle(_('Coloring Wizard'))
@ -141,8 +159,7 @@ class TagWizard(QDialog):
m = db.metadata_for_field(k) m = db.metadata_for_field(k)
if k.endswith('_index') or ( if k.endswith('_index') or (
m['kind'] == 'field' and m['name'] and m['kind'] == 'field' and m['name'] and
k not in ('ondevice', 'path', 'size', 'sort') and k not in ('ondevice', 'path', 'size', 'sort')):
m['datatype'] not in ('datetime')):
self.columns.append(k) self.columns.append(k)
self.completion_values[k]['dt'] = m['datatype'] self.completion_values[k]['dt'] = m['datatype']
if m['is_custom']: if m['is_custom']:
@ -203,11 +220,12 @@ class TagWizard(QDialog):
h.setAlignment(Qt.AlignCenter) h.setAlignment(Qt.AlignCenter)
l.addWidget(h, 0, 2, 1, 1) l.addWidget(h, 0, 2, 1, 1)
h = QLabel(_('not')) h = QLabel(_('op'))
h.setToolTip('<p>' + h.setToolTip('<p>' +
_('Check this box to indicate that the value must <b>not</b> match ' _('Use this box to tell what comparison operation to use. Some '
'to use the color. For example, you can check if a tag does ' 'comparisons cannot be used with certain options. For example, '
'not exist by entering that tag and checking this box.') + '</p>') 'if regular expressions are used, only equals and not equals '
'are valid.') + '</p>')
h.setAlignment(Qt.AlignCenter) h.setAlignment(Qt.AlignCenter)
l.addWidget(h, 0, 3, 1, 1) l.addWidget(h, 0, 3, 1, 1)
@ -246,7 +264,7 @@ class TagWizard(QDialog):
l.addWidget(c, 0, 7, 1, 1) l.addWidget(c, 0, 7, 1, 1)
self.andboxes = [] self.andboxes = []
self.notboxes = [] self.opboxes = []
self.tagboxes = [] self.tagboxes = []
self.colorboxes = [] self.colorboxes = []
self.reboxes = [] self.reboxes = []
@ -284,13 +302,17 @@ class TagWizard(QDialog):
w.setText(_('is')) w.setText(_('is'))
l.addWidget(w, i, 2, 1, 1) l.addWidget(w, i, 2, 1, 1)
create_widget(QCheckBox, self.notboxes, l, i, 3, None) w = create_widget(QComboBox, self.opboxes, l, i, 3, None)
w.setMaximumWidth(40)
w = create_widget(QCheckBox, self.emptyboxes, l, i, 4, None) w = create_widget(QCheckBox, self.emptyboxes, l, i, 4, None)
w.stateChanged.connect(partial(self.empty_box_changed, line=i-1)) w.stateChanged.connect(partial(self.empty_box_changed, line=i-1))
create_widget(MultiCompleteLineEdit, self.tagboxes, l, i, 5, None, align=0) create_widget(MultiCompleteLineEdit, self.tagboxes, l, i, 5, None, align=0)
create_widget(QCheckBox, self.reboxes, l, i, 6, None)
w = create_widget(QCheckBox, self.reboxes, l, i, 6, None)
w.stateChanged.connect(partial(self.re_box_changed, line=i-1))
create_widget(QComboBox, self.colorboxes, l, i, 7, self.colors) create_widget(QComboBox, self.colorboxes, l, i, 7, self.colors)
w = create_widget(QLabel, None, l, maxlines+1, 5, None) w = create_widget(QLabel, None, l, maxlines+1, 5, None)
@ -315,20 +337,23 @@ class TagWizard(QDialog):
if len(vals) == 2: if len(vals) == 2:
t, c = vals t, c = vals
f = 'tags' f = 'tags'
a = n = e = re = False a = re = e = 0
op = '='
else: else:
t,c,f,re,a,n,e = vals t,c,f,re,a,op,e = vals
try: try:
self.colboxes[i].setCurrentIndex(self.colboxes[i].findText(f)) self.colboxes[i].setCurrentIndex(self.colboxes[i].findText(f))
self.colorboxes[i].setCurrentIndex( self.colorboxes[i].setCurrentIndex(
self.colorboxes[i].findText(c)) self.colorboxes[i].findText(c))
self.tagboxes[i].setText(t) self.tagboxes[i].setText(t)
self.reboxes[i].setChecked(re == '2') self.reboxes[i].setChecked(re == '2')
self.andboxes[i].setChecked(a == '2')
self.notboxes[i].setChecked(n == '2')
self.emptyboxes[i].setChecked(e == '2') self.emptyboxes[i].setChecked(e == '2')
self.andboxes[i].setChecked(a == '2')
self.opboxes[i].setCurrentIndex(self.opboxes[i].findText(op))
i += 1 i += 1
except: except:
import traceback
traceback.print_exc()
pass pass
w = QLabel(_('Preview')) w = QLabel(_('Preview'))
@ -357,26 +382,6 @@ class TagWizard(QDialog):
_('EXCEPTION'), self.mi) _('EXCEPTION'), self.mi)
self.test_box.setText(t) self.test_box.setText(t)
def column_changed(self, s, line=None):
k = unicode(s)
if k in self.completion_values:
valbox = self.tagboxes[line]
valbox.update_items_cache(self.completion_values[k]['v'])
if self.completion_values[k]['m']:
valbox.set_separator(', ')
else:
valbox.set_separator(None)
dt = self.completion_values[k]['dt']
if dt in ('int', 'float', 'rating', 'bool'):
self.reboxes[line].setChecked(0)
self.reboxes[line].setEnabled(False)
else:
self.reboxes[line].setEnabled(True)
else:
valbox.update_items_cache([])
valbox.set_separator(None)
def generate_program(self): def generate_program(self):
res = ("program:\n#tag wizard -- do not directly edit\n" res = ("program:\n#tag wizard -- do not directly edit\n"
" first_non_empty(\n") " first_non_empty(\n")
@ -384,9 +389,9 @@ class TagWizard(QDialog):
was_and = had_line = False was_and = had_line = False
line = 0 line = 0
for tb, cb, fb, reb, ab, nb, eb in zip( for tb, cb, fb, reb, ab, ob, eb in zip(
self.tagboxes, self.colorboxes, self.colboxes, self.tagboxes, self.colorboxes, self.colboxes,
self.reboxes, self.andboxes, self.notboxes, self.emptyboxes): self.reboxes, self.andboxes, self.opboxes, self.emptyboxes):
f = unicode(fb.currentText()) f = unicode(fb.currentText())
if not f: if not f:
continue continue
@ -394,14 +399,11 @@ class TagWizard(QDialog):
dt = self.completion_values[f]['dt'] dt = self.completion_values[f]['dt']
c = unicode(cb.currentText()).strip() c = unicode(cb.currentText()).strip()
re = reb.checkState() re = reb.checkState()
a = ab.checkState() a = ab.checkState()
n = nb.checkState() op = unicode(ob.currentText())
e = eb.checkState() e = eb.checkState()
line += 1 line += 1
tval = '' if n == 2 else '1'
fval = '1' if n == 2 else ''
if m: if m:
tags = [t.strip() for t in unicode(tb.text()).split(m) if t.strip()] tags = [t.strip() for t in unicode(tb.text()).split(m) if t.strip()]
if re == 2: if re == 2:
@ -428,8 +430,15 @@ class TagWizard(QDialog):
lines[-1] += ',' lines[-1] += ','
key = dt + ('.mult' if m else '') + ('.empty' if e else '') + ('.re' if re else '') key = dt + ('.mult' if m else '') + ('.empty' if e else '') + ('.re' if re else '')
template = self.templates[key] tval = '1' if op == '=' else ''
lines.append(template.format(v=tags, f=f, tv=tval, fv=fval, mult=m)) fval = '' if op == '=' else '1'
template, is_relational = self.templates[key]
if is_relational:
ltv, eqv, gtv = self.relational_truth_vals[op]
else:
ltv, eqv, gtv = (None, None, None)
lines.append(template.format(v=tags, f=f, tv=tval, fv=fval, mult=m,
ltv=ltv, eqv=eqv, gtv=gtv))
if a == 2: if a == 2:
was_and = True was_and = True
@ -444,9 +453,9 @@ class TagWizard(QDialog):
res += ')\n' res += ')\n'
self.template = res self.template = res
res = '' res = ''
for tb, cb, fb, reb, ab, nb, eb in zip( for tb, cb, fb, reb, ab, ob, eb in zip(
self.tagboxes, self.colorboxes, self.colboxes, self.tagboxes, self.colorboxes, self.colboxes,
self.reboxes, self.andboxes, self.notboxes, self.emptyboxes): self.reboxes, self.andboxes, self.opboxes, self.emptyboxes):
t = unicode(tb.text()).strip() t = unicode(tb.text()).strip()
if t.endswith(','): if t.endswith(','):
t = t[:-1] t = t[:-1]
@ -454,15 +463,57 @@ class TagWizard(QDialog):
f = unicode(fb.currentText()) f = unicode(fb.currentText())
re = unicode(reb.checkState()) re = unicode(reb.checkState())
a = unicode(ab.checkState()) a = unicode(ab.checkState())
n = unicode(nb.checkState()) op = unicode(ob.currentText())
e = unicode(eb.checkState()) e = unicode(eb.checkState())
if f and (t or e) and (a == '2' or c): if f and (t or e) and (a == '2' or c):
res += '#' + t + ':|:' + c + ':|:' + f + ':|:' + re + ':|:' + \ res += '#' + t + ':|:' + c + ':|:' + f + ':|:' + re + ':|:' + \
a + ':|:' + n + ':|:' + e + '\n' a + ':|:' + op + ':|:' + e + '\n'
res += '#else:' + else_txt + '\n' res += '#else:' + else_txt + '\n'
self.template += res self.template += res
return True return True
def column_changed(self, s, line=None):
k = unicode(s)
valbox = self.tagboxes[line]
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)
dt = self.completion_values[k]['dt']
if dt in ('int', 'float', 'rating', 'bool'):
self.reboxes[line].setChecked(0)
self.reboxes[line].setEnabled(False)
else:
self.reboxes[line].setEnabled(True)
self.fill_in_opbox(line)
else:
valbox.update_items_cache([])
valbox.set_separator(None)
def fill_in_opbox(self, line):
opbox = self.opboxes[line]
opbox.clear()
k = unicode(self.colboxes[line].currentText())
if not k:
return
if k in self.completion_values:
rebox = self.reboxes[line]
ebox = self.emptyboxes[line]
idx = opbox.currentIndex()
if self.completion_values[k]['m'] or \
rebox.checkState() == 2 or ebox.checkState() == 2:
opbox.addItems(self.relationals[0:2])
idx = idx if idx < 2 else 0
else:
opbox.addItems(self.relationals)
opbox.setCurrentIndex(max(idx, 0))
def re_box_changed(self, state, line=None):
self.fill_in_opbox(line)
def empty_box_changed(self, state, line=None): def empty_box_changed(self, state, line=None):
if state == 2: if state == 2:
self.tagboxes[line].setText('') self.tagboxes[line].setText('')
@ -472,6 +523,7 @@ class TagWizard(QDialog):
else: else:
self.reboxes[line].setEnabled(True) self.reboxes[line].setEnabled(True)
self.tagboxes[line].setEnabled(True) self.tagboxes[line].setEnabled(True)
self.fill_in_opbox(line)
def and_box_changed(self, state, line=None): def and_box_changed(self, state, line=None):
if state == 2: if state == 2:

View File

@ -34,7 +34,7 @@ booksize()
format_date(val, format_string) format_date(val, format_string)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: BuiltinFormat_date .. autoclass:: BuiltinFormatDate
ondevice() ondevice()
^^^^^^^^^^^ ^^^^^^^^^^^

View File

@ -520,11 +520,11 @@ class BuiltinSubitems(BuiltinFormatterFunction):
pass pass
return ', '.join(sorted(rv, key=sort_key)) return ', '.join(sorted(rv, key=sort_key))
class BuiltinFormat_date(BuiltinFormatterFunction): class BuiltinFormatDate(BuiltinFormatterFunction):
name = 'format_date' name = 'format_date'
arg_count = 2 arg_count = 2
__doc__ = doc = _('format_date(val, format_string) -- format the value, which must ' __doc__ = doc = _('format_date(val, format_string) -- format the value, '
'be a date field, using the format_string, returning a string. ' 'which must be a date, using the format_string, returning a string. '
'The formatting codes are: ' 'The formatting codes are: '
'd : the day as number without a leading zero (1 to 31) ' 'd : the day as number without a leading zero (1 to 31) '
'dd : the day as number with a leading zero (01 to 31) ' 'dd : the day as number with a leading zero (01 to 31) '
@ -539,7 +539,7 @@ class BuiltinFormat_date(BuiltinFormatterFunction):
'iso : the date with time and timezone. Must be the only format present') 'iso : the date with time and timezone. Must be the only format present')
def evaluate(self, formatter, kwargs, mi, locals, val, format_string): def evaluate(self, formatter, kwargs, mi, locals, val, format_string):
if not val: if not val or val == 'None':
return '' return ''
try: try:
dt = parse_date(val) dt = parse_date(val)
@ -704,7 +704,7 @@ builtin_divide = BuiltinDivide()
builtin_eval = BuiltinEval() builtin_eval = BuiltinEval()
builtin_first_non_empty = BuiltinFirstNonEmpty() builtin_first_non_empty = BuiltinFirstNonEmpty()
builtin_field = BuiltinField() builtin_field = BuiltinField()
builtin_format_date = BuiltinFormat_date() builtin_format_date = BuiltinFormatDate()
builtin_ifempty = BuiltinIfempty() builtin_ifempty = BuiltinIfempty()
builtin_in_list = BuiltinInList() builtin_in_list = BuiltinInList()
builtin_list_item = BuiltinListitem() builtin_list_item = BuiltinListitem()