From b06596fffbeb4102ed573fee1366e345e64db6d9 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 24 Dec 2010 22:44:04 +0000 Subject: [PATCH 1/7] First try at using the new comments editor for custom comments columns --- src/calibre/gui2/book_details.py | 4 +- src/calibre/gui2/custom_column_widgets.py | 9 +-- src/calibre/gui2/dialogs/comments_dialog.py | 5 +- src/calibre/gui2/dialogs/comments_dialog.ui | 37 ++++++----- src/calibre/gui2/dialogs/template_dialog.py | 25 +++++++ src/calibre/gui2/dialogs/template_dialog.ui | 73 +++++++++++++++++++++ src/calibre/gui2/library/delegates.py | 24 +++++-- src/calibre/gui2/library/models.py | 2 + 8 files changed, 153 insertions(+), 26 deletions(-) create mode 100644 src/calibre/gui2/dialogs/template_dialog.py create mode 100644 src/calibre/gui2/dialogs/template_dialog.ui diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index a3caa82e4b..50ce72686a 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -44,7 +44,9 @@ def render_rows(data): key = key.decode(preferred_encoding, 'replace') if isinstance(txt, str): txt = txt.decode(preferred_encoding, 'replace') - if '' not in txt: + if key.endswith(u':html'): + key = key[:-5] + elif '' not in txt: txt = prepare_string_for_xml(txt) if 'id' in data: if key == _('Path'): diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index ca9243e51e..bf66ea7235 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -15,6 +15,7 @@ from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \ from calibre.utils.date import qt_to_dt, now from calibre.gui2.widgets import TagsLineEdit, EnComboBox +from calibre.gui2.comments_editor import Editor as CommentsEditor from calibre.gui2 import UNDEFINED_QDATE, error_dialog from calibre.utils.config import tweaks from calibre.utils.icu import sort_key @@ -186,9 +187,9 @@ class Comments(Base): self._box = QGroupBox(parent) self._box.setTitle('&'+self.col_metadata['name']) self._layout = QVBoxLayout() - self._tb = QPlainTextEdit(self._box) + self._tb = CommentsEditor(self._box) self._tb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) - self._tb.setTabChangesFocus(True) + #self._tb.setTabChangesFocus(True) self._layout.addWidget(self._tb) self._box.setLayout(self._layout) self.widgets = [self._box] @@ -196,10 +197,10 @@ class Comments(Base): def setter(self, val): if val is None: val = '' - self._tb.setPlainText(val) + self._tb.html = val def getter(self): - val = unicode(self._tb.toPlainText()).strip() + val = unicode(self._tb.html).strip() if not val: val = None return val diff --git a/src/calibre/gui2/dialogs/comments_dialog.py b/src/calibre/gui2/dialogs/comments_dialog.py index 5d53448b94..51b29fa989 100644 --- a/src/calibre/gui2/dialogs/comments_dialog.py +++ b/src/calibre/gui2/dialogs/comments_dialog.py @@ -5,6 +5,7 @@ __license__ = 'GPL v3' from PyQt4.Qt import Qt, QDialog, QDialogButtonBox from calibre.gui2.dialogs.comments_dialog_ui import Ui_CommentsDialog +from calibre.library.comments import comments_to_html class CommentsDialog(QDialog, Ui_CommentsDialog): @@ -18,8 +19,8 @@ class CommentsDialog(QDialog, Ui_CommentsDialog): self.setWindowIcon(icon) if text is not None: - self.textbox.setPlainText(text) - self.textbox.setTabChangesFocus(True) + self.textbox.html = comments_to_html(text) + # self.textbox.setTabChangesFocus(True) self.buttonBox.button(QDialogButtonBox.Ok).setText(_('&OK')) self.buttonBox.button(QDialogButtonBox.Cancel).setText(_('&Cancel')) diff --git a/src/calibre/gui2/dialogs/comments_dialog.ui b/src/calibre/gui2/dialogs/comments_dialog.ui index dccfa48652..9c6e6cb861 100644 --- a/src/calibre/gui2/dialogs/comments_dialog.ui +++ b/src/calibre/gui2/dialogs/comments_dialog.ui @@ -19,22 +19,29 @@ Edit Comments - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Editor + QWidget +
calibre/gui2/comments_editor.h
+
+
diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py new file mode 100644 index 0000000000..aaa4e2bb9a --- /dev/null +++ b/src/calibre/gui2/dialogs/template_dialog.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' +__docformat__ = 'restructuredtext en' +__license__ = 'GPL v3' + +from PyQt4.Qt import Qt, QDialog, QDialogButtonBox +from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog + +class TemplateDialog(QDialog, Ui_TemplateDialog): + + def __init__(self, parent, text): + QDialog.__init__(self, parent) + Ui_TemplateDialog.__init__(self) + self.setupUi(self) + # Remove help icon on title bar + icon = self.windowIcon() + self.setWindowFlags(self.windowFlags()&(~Qt.WindowContextHelpButtonHint)) + self.setWindowIcon(icon) + + if text is not None: + self.textbox.setPlainText(text) + self.textbox.setTabChangesFocus(True) + self.buttonBox.button(QDialogButtonBox.Ok).setText(_('&OK')) + self.buttonBox.button(QDialogButtonBox.Cancel).setText(_('&Cancel')) + diff --git a/src/calibre/gui2/dialogs/template_dialog.ui b/src/calibre/gui2/dialogs/template_dialog.ui new file mode 100644 index 0000000000..3eacace2c5 --- /dev/null +++ b/src/calibre/gui2/dialogs/template_dialog.ui @@ -0,0 +1,73 @@ + + + TemplateDialog + + + + 0 + 0 + 336 + 235 + + + + + 0 + 0 + + + + Edit Comments + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + TemplateDialog + accept() + + + 229 + 211 + + + 157 + 234 + + + + + buttonBox + rejected() + TemplateDialog + reject() + + + 297 + 217 + + + 286 + 234 + + + + + diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index fe7e7d55ba..2ae6cf2936 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -13,7 +13,7 @@ from PyQt4.Qt import QColor, Qt, QModelIndex, QSize, \ QPen, QStyle, QPainter, QStyleOptionViewItemV4, \ QIcon, QDoubleSpinBox, QVariant, QSpinBox, \ QStyledItemDelegate, QCompleter, \ - QComboBox + QComboBox, QTextDocument from calibre.gui2 import UNDEFINED_QDATE, error_dialog from calibre.gui2.widgets import EnLineEdit, TagsLineEdit @@ -22,6 +22,8 @@ from calibre.utils.config import tweaks from calibre.utils.formatter import validation_formatter from calibre.utils.icu import sort_key from calibre.gui2.dialogs.comments_dialog import CommentsDialog +from calibre.gui2.dialogs.template_dialog import TemplateDialog + class RatingDelegate(QStyledItemDelegate): # {{{ COLOR = QColor("blue") @@ -294,6 +296,20 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{ Delegate for comments data. ''' + def paint(self, painter, option, index): + document = QTextDocument() + value = index.data(Qt.DisplayRole) +# if value.isValid() and not value.isNull(): +# QString text("This is highlighted."); + text = value.toString() + document.setHtml(text); + painter.save() + painter.setClipRect(option.rect) + painter.translate(option.rect.topLeft()); + document.drawContents(painter); + painter.restore() +# painter.translate(-option.rect.topLeft()); + def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] @@ -301,11 +317,11 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{ editor = CommentsDialog(parent, text) d = editor.exec_() if d: - m.setData(index, QVariant(editor.textbox.toPlainText()), Qt.EditRole) + m.setData(index, QVariant(editor.textbox.html), Qt.EditRole) return None def setModelData(self, editor, model, index): - model.setData(index, QVariant(editor.textbox.toPlainText()), Qt.EditRole) + model.setData(index, QVariant(editor.textbox.html), Qt.EditRole) # }}} class CcBoolDelegate(QStyledItemDelegate): # {{{ @@ -351,7 +367,7 @@ class CcTemplateDelegate(QStyledItemDelegate): # {{{ def createEditor(self, parent, option, index): m = index.model() text = m.custom_columns[m.column_map[index.column()]]['display']['composite_template'] - editor = CommentsDialog(parent, text) + editor = TemplateDialog(parent, text) editor.setWindowTitle(_("Edit template")) editor.textbox.setTabChangesFocus(False) editor.textbox.setTabStopWidth(20) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 9da9a2f538..920753a77d 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -334,6 +334,8 @@ class BooksModel(QAbstractTableModel): # {{{ if key not in cf_to_display: continue name, val = mi.format_field(key) + if mi.metadata_for_field(key)['datatype'] == 'comments': + name += ':html' if val: data[name] = val return data From 1fa911c8c962642b611145292776e2c3af37becb Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Fri, 24 Dec 2010 22:46:42 +0000 Subject: [PATCH 2/7] Resize the comments delegate dialog box --- src/calibre/gui2/dialogs/comments_dialog.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/dialogs/comments_dialog.ui b/src/calibre/gui2/dialogs/comments_dialog.ui index 9c6e6cb861..76b23e233d 100644 --- a/src/calibre/gui2/dialogs/comments_dialog.ui +++ b/src/calibre/gui2/dialogs/comments_dialog.ui @@ -6,8 +6,8 @@ 0 0 - 336 - 235 + 400 + 400 From c0c4df77cab4ddddb009743546978e08e8490d69 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 25 Dec 2010 11:42:38 +0000 Subject: [PATCH 3/7] Improve search/replace handling of is_multiple fields --- src/calibre/gui2/dialogs/metadata_bulk.py | 33 ++++++-- src/calibre/gui2/dialogs/metadata_bulk.ui | 99 +++++++++++++++++------ 2 files changed, 101 insertions(+), 31 deletions(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index bde5cae128..9dbc3dee5e 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -417,6 +417,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.multiple_separator.setFixedWidth(30) self.multiple_separator.setText(' ::: ') self.multiple_separator.textChanged.connect(self.s_r_separator_changed) + self.results_count.valueChanged[int].connect(self.s_r_display_bounds_changed) + self.starting_from.valueChanged[int].connect(self.s_r_display_bounds_changed) def s_r_get_field(self, mi, field): if field: @@ -439,6 +441,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): val = [] return val + def s_r_display_bounds_changed(self, i): + self.s_r_search_field_changed(self.search_field.currentIndex()) + def s_r_template_changed(self): self.s_r_search_field_changed(self.search_field.currentIndex()) @@ -454,6 +459,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): mi = self.db.get_metadata(self.ids[i], index_is_id=True) src = unicode(self.search_field.currentText()) t = self.s_r_get_field(mi, src) + if len(t) > 1: + t = t[self.starting_from.value()-1: + self.starting_from.value()-1 + self.results_count.value()] w.setText(unicode(self.multiple_separator.text()).join(t)) if self.search_mode.currentIndex() == 0: @@ -466,12 +474,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): txt = unicode(txt) if not txt: txt = unicode(self.search_field.currentText()) - self.comma_separated.setEnabled(True) if txt and txt in self.writable_fields: self.destination_field_fm = self.db.metadata_for_field(txt) - if self.destination_field_fm['is_multiple']: - self.comma_separated.setEnabled(False) - self.comma_separated.setChecked(True) self.s_r_paint_results(None) def s_r_search_mode_changed(self, val): @@ -542,6 +546,22 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): dest = src dest_mode = self.replace_mode.currentIndex() + if self.destination_field_fm['is_multiple']: + if self.comma_separated.isChecked(): + if dest == 'authors': + splitter = ' & ' + else: + splitter = ',' + + res = [] + for v in val: + for x in v.split(splitter): + if x.strip(): + res.append(x.strip()) + val = res + else: + val = [v.replace(',', '') for v in val] + if dest_mode != 0: dest_val = mi.get(dest, '') if dest_val is None: @@ -602,8 +622,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): try: result = self.s_r_do_regexp(mi) t = self.s_r_do_destination(mi, result) - if len(result) > 1 and self.destination_field_fm is not None and \ - self.destination_field_fm['is_multiple']: + if len(t) > 1 and self.destination_field_fm['is_multiple']: + t = t[self.starting_from.value()-1: + self.starting_from.value()-1 + self.results_count.value()] t = unicode(self.multiple_separator.text()).join(t) else: t = self.s_r_replace_mode_separator().join(t) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index d945909f96..41858b099b 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -658,11 +658,12 @@ If blank, the source field is used if the field is modifiable - Specifies whether a comma should be put between values when copying from a -multiple-valued field to a single-valued field + Specifies whether result items should be split into multiple values or +left as single values. This option has the most effect when the source field is +not multiple and the destination field is multiple - &Use comma + Split &result true @@ -684,28 +685,8 @@ multiple-valued field to a single-valued field - - - - Test text - - - test_text - - - - + - - - - Test result - - - test_result - - - @@ -719,10 +700,62 @@ multiple-valued field to a single-valued field + + + + For multiple-valued fields, sho&w + + + results_count + + + + + + + true + + + 1 + + + 999 + + + 999 + + + + + + + values starting a&t + + + starting_from + + + + + + + true + + + 1 + + + 999 + + + 1 + + + - Multi&ple separator: + with values separated b&y multiple_separator @@ -756,6 +789,20 @@ multiple-valued field to a single-valued field + + + + Test text + + + + + + + Test result + + + @@ -857,6 +904,8 @@ multiple-valued field to a single-valued field destination_field replace_mode comma_separated + results_count + starting_from multiple_separator test_text test_result From 092982e057272e57819310dbb53cf2bb2ccce286 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 25 Dec 2010 12:40:55 +0000 Subject: [PATCH 4/7] More custom comments as html work --- src/calibre/gui2/dialogs/book_info.py | 5 ++++- src/calibre/gui2/library/delegates.py | 18 +++++++++--------- src/calibre/library/server/opds.py | 2 ++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/calibre/gui2/dialogs/book_info.py b/src/calibre/gui2/dialogs/book_info.py index 016f132c57..6cae27d926 100644 --- a/src/calibre/gui2/dialogs/book_info.py +++ b/src/calibre/gui2/dialogs/book_info.py @@ -12,6 +12,7 @@ from calibre.gui2.dialogs.book_info_ui import Ui_BookInfo from calibre.gui2 import dynamic, open_local_file from calibre import fit_image from calibre.library.comments import comments_to_html +from calibre.utils.icu import sort_key class BookInfo(QDialog, Ui_BookInfo): @@ -130,9 +131,11 @@ class BookInfo(QDialog, Ui_BookInfo): for f in formats: f = f.strip() info[_('Formats')] += '%s, '%(f,f) - for key in info.keys(): + for key in sorted(info.keys(), key=sort_key): if key == 'id': continue txt = info[key] + if key.endswith(':html'): + key = key[:-5] if key != _('Path'): txt = u'
\n'.join(textwrap.wrap(txt, 120)) rows += u'%s:%s'%(key, txt) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 2ae6cf2936..957828f93c 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -296,19 +296,19 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{ Delegate for comments data. ''' + def __init__(self, parent): + QStyledItemDelegate.__init__(self, parent) + self.document = QTextDocument() + def paint(self, painter, option, index): - document = QTextDocument() - value = index.data(Qt.DisplayRole) -# if value.isValid() and not value.isNull(): -# QString text("This is highlighted."); - text = value.toString() - document.setHtml(text); + self.document.setHtml(index.data(Qt.DisplayRole).toString()) painter.save() + if option.state & QStyle.State_Selected: + painter.fillRect(option.rect, option.palette.highlight()) painter.setClipRect(option.rect) - painter.translate(option.rect.topLeft()); - document.drawContents(painter); + painter.translate(option.rect.topLeft()) + self.document.drawContents(painter) painter.restore() -# painter.translate(-option.rect.topLeft()); def createEditor(self, parent, option, index): m = index.model() diff --git a/src/calibre/library/server/opds.py b/src/calibre/library/server/opds.py index e447c6966c..fd8c50c594 100644 --- a/src/calibre/library/server/opds.py +++ b/src/calibre/library/server/opds.py @@ -173,6 +173,8 @@ def ACQUISITION_ENTRY(item, version, db, updated, CFM, CKEYS, prefix): extra.append('%s: %s
'%(xml(name), xml(format_tag_string(val, ',', ignore_max=True, no_tag_count=True)))) + elif datatype == 'comments': + extra.append('%s: %s
'%(xml(name), comments_to_html(unicode(val)))) else: extra.append('%s: %s
'%(xml(name), xml(unicode(val)))) comments = item[FM['comments']] From e770af4d47d72792068311e8244d7762b581822b Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 25 Dec 2010 18:08:11 +0000 Subject: [PATCH 5/7] New formatter function, fix problems with strcat and math results, define basic formatter for usbms and formatter --- src/calibre/devices/usbms/books.py | 21 +++------------- src/calibre/utils/formatter.py | 40 +++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/calibre/devices/usbms/books.py b/src/calibre/devices/usbms/books.py index 73afd770c1..1e7d74480a 100644 --- a/src/calibre/devices/usbms/books.py +++ b/src/calibre/devices/usbms/books.py @@ -14,22 +14,7 @@ from calibre.constants import preferred_encoding from calibre import isbytestring, force_unicode from calibre.utils.config import prefs, tweaks from calibre.utils.icu import strcmp -from calibre.utils.formatter import TemplateFormatter - -class SafeFormat(TemplateFormatter): - ''' - Provides a format function that substitutes '' for any missing value - ''' - - def get_value(self, key, args, kwargs): - try: - if key in kwargs: - return kwargs[key] - return key - except: - return key - -safe_formatter = SafeFormat() +from calibre.utils.formatter import eval_formatter class Book(Metadata): def __init__(self, prefix, lpath, size=None, other=None): @@ -131,10 +116,10 @@ class CollectionsBookList(BookList): field_name = field_meta['name'] else: field_name = '' - cat_name = safe_formatter.safe_format( + cat_name = eval_formatter.safe_format( fmt=tweaks['sony_collection_name_template'], kwargs={'category':field_name, 'value':field_value}, - error_value='', book=None) + error_value='GET_CATEGORY', book=None) return cat_name.strip() def get_collections(self, collection_attributes): diff --git a/src/calibre/utils/formatter.py b/src/calibre/utils/formatter.py index 182aff5a7a..bb7e953d19 100644 --- a/src/calibre/utils/formatter.py +++ b/src/calibre/utils/formatter.py @@ -36,7 +36,7 @@ class _Parser(object): return gt def _assign(self, target, value): - setattr(self, target, value) + self.variables[target] = value return value def _concat(self, *args): @@ -55,18 +55,23 @@ class _Parser(object): } x = float(x if x else 0) y = float(y if y else 0) - return ops[op](x, y) + return str(ops[op](x, y)) def _template(self, template): template = template.replace('[[', '{').replace(']]', '}') return self.parent.safe_format(template, self.parent.kwargs, 'TEMPLATE', self.parent.book) + def _eval(self, template): + template = template.replace('[[', '{').replace(']]', '}') + return eval_formatter.safe_format(template, self.variables, 'EVAL', None) + local_functions = { 'add' : (2, partial(_math, op='+')), 'assign' : (2, _assign), 'cmp' : (5, _cmp), 'divide' : (2, partial(_math, op='/')), + 'eval' : (1, _eval), 'field' : (1, lambda s, x: s.parent.get_value(x, [], s.parent.kwargs)), 'multiply' : (2, partial(_math, op='*')), 'strcat' : (-1, _concat), @@ -82,7 +87,7 @@ class _Parser(object): if prog[1] != '': self.error(_('failed to scan program. Invalid input {0}').format(prog[1])) self.parent = parent - setattr(self, '$', val) + self.variables = {'$':val} def error(self, message): m = 'Formatter: ' + message + _(' near ') @@ -144,7 +149,7 @@ class _Parser(object): # We have an identifier. Determine if it is a function id = self.token() if not self.token_op_is_a('('): - return getattr(self, id, _('unknown id ') + id) + return self.variables.get(id, _('unknown id ') + id) # We have a function. # Check if it is a known one. We do this here so error reporting is # better, as it can identify the tokens near the problem. @@ -417,15 +422,18 @@ class TemplateFormatter(string.Formatter): self.kwargs = kwargs self.book = book self.composite_values = {} - try: - ans = self.vformat(fmt, [], kwargs).strip() - except Exception, e: - if DEBUG: - traceback.print_exc() - ans = error_value + ' ' + e.message + if fmt.startswith('program:'): + ans = self._eval_program(None, fmt[8:]) + else: + try: + ans = self.vformat(fmt, [], kwargs).strip() + except Exception, e: + if DEBUG: + traceback.print_exc() + ans = error_value + ' ' + e.message return ans -class ValidateFormat(TemplateFormatter): +class ValidateFormatter(TemplateFormatter): ''' Provides a format function that substitutes '' for any missing value ''' @@ -435,6 +443,14 @@ class ValidateFormat(TemplateFormatter): def validate(self, x): return self.vformat(x, [], {}) -validation_formatter = ValidateFormat() +validation_formatter = ValidateFormatter() +class EvalFormatter(TemplateFormatter): + ''' + A template formatter that uses a simple dict instead of an mi instance + ''' + def get_value(self, key, args, kwargs): + return kwargs.get(key, _('No such variable ') + key) + +eval_formatter = EvalFormatter() From 6e80dca1bbd1b7925409571d034c8353179e5108 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 25 Dec 2010 11:24:50 -0700 Subject: [PATCH 6/7] ... --- src/calibre/gui2/library/delegates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index fef1542737..b41fd78dc3 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -306,7 +306,7 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{ painter.save() if hasattr(QStyle, 'CE_ItemViewItem'): style.drawControl(QStyle.CE_ItemViewItem, option, - painter, self._parent) + painter, self.parent()) elif option.state & QStyle.State_Selected: painter.fillRect(option.rect, option.palette.highlight()) painter.setClipRect(option.rect) From 532749201a15611d262e903409ad5ea3352a6083 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 25 Dec 2010 18:30:50 +0000 Subject: [PATCH 7/7] Make custom_column_widgets.py, book_info.py, and book_details.py use comments_to_html. Fix _parent to parent() --- src/calibre/gui2/book_details.py | 1 + src/calibre/gui2/custom_column_widgets.py | 3 ++- src/calibre/gui2/dialogs/book_info.py | 1 + src/calibre/gui2/library/delegates.py | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index 50ce72686a..dd12080d7f 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -46,6 +46,7 @@ def render_rows(data): txt = txt.decode(preferred_encoding, 'replace') if key.endswith(u':html'): key = key[:-5] + txt = comments_to_html(txt) elif '' not in txt: txt = prepare_string_for_xml(txt) if 'id' in data: diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 40abb05f89..ec18675359 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -19,6 +19,7 @@ from calibre.gui2.comments_editor import Editor as CommentsEditor from calibre.gui2 import UNDEFINED_QDATE, error_dialog from calibre.utils.config import tweaks from calibre.utils.icu import sort_key +from calibre.library.comments import comments_to_html class Base(object): @@ -197,7 +198,7 @@ class Comments(Base): def setter(self, val): if val is None: val = '' - self._tb.html = val + self._tb.html = comments_to_html(val) def getter(self): val = unicode(self._tb.html).strip() diff --git a/src/calibre/gui2/dialogs/book_info.py b/src/calibre/gui2/dialogs/book_info.py index 6cae27d926..1384c27b8c 100644 --- a/src/calibre/gui2/dialogs/book_info.py +++ b/src/calibre/gui2/dialogs/book_info.py @@ -136,6 +136,7 @@ class BookInfo(QDialog, Ui_BookInfo): txt = info[key] if key.endswith(':html'): key = key[:-5] + txt = comments_to_html(txt) if key != _('Path'): txt = u'
\n'.join(textwrap.wrap(txt, 120)) rows += u'%s:%s'%(key, txt) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index fef1542737..b41fd78dc3 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -306,7 +306,7 @@ class CcCommentsDelegate(QStyledItemDelegate): # {{{ painter.save() if hasattr(QStyle, 'CE_ItemViewItem'): style.drawControl(QStyle.CE_ItemViewItem, option, - painter, self._parent) + painter, self.parent()) elif option.state & QStyle.State_Selected: painter.fillRect(option.rect, option.palette.highlight()) painter.setClipRect(option.rect)