From dd01e7448f5aaa83fc47549056991274940ff9b4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 4 Apr 2014 07:43:30 +0530 Subject: [PATCH 1/7] calibredb check_library: Do not create empty library if user specifies incorrect path --- src/calibre/library/cli.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py index c3509f5a23..7544d8d745 100644 --- a/src/calibre/library/cli.py +++ b/src/calibre/library/cli.py @@ -1211,6 +1211,10 @@ def command_check_library(args, dbpath): for i in list: print ' %-40.40s - %-40.40s'%(i[0], i[1]) + if not LibraryDatabase.exists_at(dbpath): + prints('No library found at', dbpath, file=sys.stderr) + raise SystemExit(1) + db = LibraryDatabase(dbpath) checker = CheckLibrary(dbpath, db) checker.scan_library(names, exts) From 20d653e54cf7c6ec70c9298d243f20013932044d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 4 Apr 2014 08:03:40 +0530 Subject: [PATCH 2/7] version 1.31 --- Changelog.yaml | 47 ++++++++++++++++++++++++++++++++++++++++ src/calibre/constants.py | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Changelog.yaml b/Changelog.yaml index 4655b36679..359fbe70c7 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -20,6 +20,53 @@ # new recipes: # - title: +- version: 1.31.0 + date: 2014-04-04 + + new features: + - title: "DOCX Input: Support for converting indexes created using the Word Index tool. The entries in the index are automatically converted into links pointing to the indexed locations." + + - title: "AZW3 Output: Add support for converting documents with very large table of contents (with more than 2000 entries)." + tickets: [1250475] + + - title: "Edit Book: Add a button to easily insert HTML tags. Useful if you want to quickly surround selected text with an arbitrary tag. You can right click the button to get a list of recently used tags." + + - title: "Driver for Tolino Vision (OS X/Linux only)." + tickets: [1301875] + + - title: "Edit book: Allow editing SVG files as raw XML" + + bug fixes: + - title: "DOCX Input: Fix incorrect numbering being generated for numbered lists in some circumstances." + tickets: [1301044] + + - title: "calibredb check_library: Do not create empty library if user specifies incorrect path" + + - title: "DOCX Input: Fix handling of hyperlinks in documents where the hyperlink is specified as a field internally (Microsoft Word does not use fields for hyperlinks)" + + - title: "Get Books: Update WH Smiths plugin for website changes and remove Diesel eBooks, as they are shutting down" + + - title: "AZW3 Output: Fix a bug that caused popup footnotes in some AZW3 files to not work properly. The popup would show all remaining footnotes instead of only the current footnote." + tickets: [1293290] + + - title: "AZW3 Output: Various tweaks to the internal structure and headers of the output file to make it closer to what kindlegen 2.9 generates" + + - title: "Edit Book: When user is editing files belonging to another user account on linux/os x rather than erroring out when saving, change the ownership of the file to the editing user." + tickets: [1299097] + + - title: "Edit Book: Fix insert Inline ToC creating non-linear jumps in class names" + + - title: "Fix regression that broke ebook-device cp" + + improved recipes: + - CNET + - El Pais Impreso + - CNet News + - Antyweb + + new recipes: + - title: + - version: 1.30.0 date: 2014-03-28 diff --git a/src/calibre/constants.py b/src/calibre/constants.py index cfe5f6e3b9..096eb032cf 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -4,7 +4,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __appname__ = u'calibre' -numeric_version = (1, 30, 0) +numeric_version = (1, 31, 0) __version__ = u'.'.join(map(unicode, numeric_version)) __author__ = u"Kovid Goyal " From d0cfd06911916cd083a8fd3ab66b77cce6b7bab6 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Fri, 4 Apr 2014 10:27:57 +0200 Subject: [PATCH 3/7] Make the list of color names tooltip appear when creating an enum column as well as when editing one. --- src/calibre/gui2/preferences/create_custom_column.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/preferences/create_custom_column.py b/src/calibre/gui2/preferences/create_custom_column.py index c354e1cc99..b089844127 100644 --- a/src/calibre/gui2/preferences/create_custom_column.py +++ b/src/calibre/gui2/preferences/create_custom_column.py @@ -84,10 +84,15 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): for t in self.column_types: self.column_type_box.addItem(self.column_types[t]['text']) self.column_type_box.currentIndexChanged.connect(self.datatype_changed) + + all_colors = [unicode(s) for s in list(QColor.colorNames())] + self.enum_colors_label.setToolTip('

' + ', '.join(all_colors) + '

') + if not self.editing_col: self.datatype_changed() self.exec_() return + self.setWindowTitle(_('Edit a custom column')) self.heading_label.setText(_('Edit a custom column')) self.shortcuts.setVisible(False) @@ -141,9 +146,6 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): elif ct == '*text': self.is_names.setChecked(c['display'].get('is_names', False)) - all_colors = [unicode(s) for s in list(QColor.colorNames())] - self.enum_colors_label.setToolTip('

' + ', '.join(all_colors) + '

') - self.composite_contains_html.setToolTip('

' + _('If checked, this column will be displayed as HTML in ' 'book details and the content server. This can be used to ' From fce3f5682632ff6b0705d4cdb88d033172de0f94 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 4 Apr 2014 17:21:30 +0530 Subject: [PATCH 4/7] Allow specifying arbitrary colors for column coloring rules --- src/calibre/gui2/preferences/coloring.py | 46 ++++++++++++------------ src/calibre/gui2/widgets2.py | 44 +++++++++++++++++++++++ 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/calibre/gui2/preferences/coloring.py b/src/calibre/gui2/preferences/coloring.py index 4d8dfce9c5..c3445e886d 100644 --- a/src/calibre/gui2/preferences/coloring.py +++ b/src/calibre/gui2/preferences/coloring.py @@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en' import os, textwrap from PyQt4.Qt import (QWidget, QDialog, QLabel, QGridLayout, QComboBox, QSize, - QLineEdit, QIntValidator, QDoubleValidator, QFrame, QColor, Qt, QIcon, + QLineEdit, QIntValidator, QDoubleValidator, QFrame, Qt, QIcon, QScrollArea, QPushButton, QVBoxLayout, QDialogButtonBox, QToolButton, QListView, QAbstractListModel, pyqtSignal, QSizePolicy, QSpacerItem, QApplication, QStandardItem, QStandardItemModel, QCheckBox) @@ -21,6 +21,7 @@ from calibre.utils.icu import sort_key from calibre.gui2 import error_dialog, choose_files, pixmap_to_data from calibre.gui2.dialogs.template_dialog import TemplateDialog from calibre.gui2.metadata.single_download import RichTextDelegate +from calibre.gui2.widgets2 import ColorButton from calibre.library.coloring import (Rule, conditionable_columns, displayable_columns, rule_from_template, color_row_key) from calibre.utils.localization import lang_map @@ -33,7 +34,8 @@ icon_rule_kinds = [(_('icon with text'), 'icon'), (_('composed icons w/text'), 'icon_composed'), (_('composed icons w/no text'), 'icon_only_composed'),] -class ConditionEditor(QWidget): # {{{ + +class ConditionEditor(QWidget): # {{{ ACTION_MAP = { 'bool' : ( @@ -86,7 +88,6 @@ class ConditionEditor(QWidget): # {{{ for x in ('float', 'rating'): ACTION_MAP[x] = ACTION_MAP['int'] - def __init__(self, fm, parent=None): QWidget.__init__(self, parent) self.fm = fm @@ -108,8 +109,6 @@ class ConditionEditor(QWidget): # {{{ self.column_box = QComboBox(self) l.addWidget(self.column_box, 0, 1) - - self.l2 = l2 = QLabel(two) l.addWidget(l2, 0, 2) @@ -277,7 +276,7 @@ class ConditionEditor(QWidget): # {{{ self.value_box.setEnabled(False) # }}} -class RuleEditor(QDialog): # {{{ +class RuleEditor(QDialog): # {{{ def __init__(self, fm, pref_name, parent=None): QDialog.__init__(self, parent) @@ -329,7 +328,7 @@ class RuleEditor(QDialog): # {{{ l.addWidget(l4, 2, 4) if self.rule_kind == 'color': - self.color_box = QComboBox(self) + self.color_box = ColorButton(parent=self) self.color_label = QLabel('Sample text Sample text') self.color_label.setTextFormat(Qt.RichText) l.addWidget(self.color_box, 2, 5) @@ -393,7 +392,7 @@ class RuleEditor(QDialog): # {{{ self.conditions = [] if self.rule_kind == 'color': - for b in (self.column_box, self.color_box): + for b in (self.column_box, ): b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon) b.setMinimumContentsLength(15) @@ -407,10 +406,9 @@ class RuleEditor(QDialog): # {{{ self.column_box.setCurrentIndex(0) if self.rule_kind == 'color': - self.color_box.addItems(QColor.colorNames()) - self.color_box.setCurrentIndex(0) + self.color_box.color = '#000' self.update_color_label() - self.color_box.currentIndexChanged.connect(self.update_color_label) + self.color_box.color_changed.connect(self.update_color_label) else: self.rule_icon_files = [] self.filename_button.clicked.connect(self.filename_button_clicked) @@ -436,10 +434,10 @@ class RuleEditor(QDialog): # {{{ for i,filename in enumerate(self.icon_file_names): item = QStandardItem(filename) if doing_multiple: - item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled); + item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setData(Qt.Unchecked, Qt.CheckStateRole) else: - item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable); + item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) icon = QIcon(os.path.join(config_dir, 'cc_icons', filename)) item.setIcon(icon) model.appendRow(item) @@ -448,7 +446,7 @@ class RuleEditor(QDialog): # {{{ pal = QApplication.palette() bg1 = unicode(pal.color(pal.Base).name()) bg2 = unicode(pal.color(pal.AlternateBase).name()) - c = unicode(self.color_box.currentText()) + c = self.color_box.color self.color_label.setText('''  {st}   {st}  @@ -528,9 +526,7 @@ class RuleEditor(QDialog): # {{{ def apply_rule(self, kind, col, rule): if kind == 'color': if rule.color: - idx = self.color_box.findText(rule.color) - if idx >= 0: - self.color_box.setCurrentIndex(idx) + self.color_box.color = rule.color else: for i,tup in enumerate(icon_rule_kinds): if kind == tup[1]: @@ -595,7 +591,7 @@ class RuleEditor(QDialog): # {{{ if self.rule_kind != 'color': r.color = self.get_filenames_from_box() else: - r.color = unicode(self.color_box.currentText()) + r.color = self.color_box.color idx = self.column_box.currentIndex() col = unicode(self.column_box.itemData(idx).toString()) for c in self.conditions: @@ -611,7 +607,7 @@ class RuleEditor(QDialog): # {{{ return kind, col, r # }}} -class RulesModel(QAbstractListModel): # {{{ +class RulesModel(QAbstractListModel): # {{{ def __init__(self, prefs, fm, pref_name, parent=None): QAbstractListModel.__init__(self, parent) @@ -623,7 +619,8 @@ class RulesModel(QAbstractListModel): # {{{ rules = list(prefs[pref_name]) self.rules = [] for col, template in rules: - if col not in self.fm and col != color_row_key: continue + if col not in self.fm and col != color_row_key: + continue try: rule = rule_from_template(self.fm, template) except: @@ -634,7 +631,8 @@ class RulesModel(QAbstractListModel): # {{{ rules = list(prefs[pref_name]) self.rules = [] for kind, col, template in rules: - if col not in self.fm and col != color_row_key: continue + if col not in self.fm and col != color_row_key: + continue try: rule = rule_from_template(self.fm, template) except: @@ -764,7 +762,7 @@ class RulesModel(QAbstractListModel): # {{{ # }}} -class EditRules(QWidget): # {{{ +class EditRules(QWidget): # {{{ changed = pyqtSignal() @@ -881,7 +879,7 @@ class EditRules(QWidget): # {{{ icon_rule_kind=kind) if d.exec_() == d.Accepted: - if len(d.rule) == 2: # Convert template dialog rules to a triple + if len(d.rule) == 2: # Convert template dialog rules to a triple d.rule = ('color', d.rule[0], d.rule[1]) kind, col, r = d.rule if kind and r is not None and col: @@ -945,7 +943,7 @@ if __name__ == '__main__': d.add_blank_condition() d.exec_() - col, r = d.rule + kind, col, r = d.rule print ('Column to be colored:', col) print ('Template:') diff --git a/src/calibre/gui2/widgets2.py b/src/calibre/gui2/widgets2.py index 8d801a91bd..c21a6d7ae1 100644 --- a/src/calibre/gui2/widgets2.py +++ b/src/calibre/gui2/widgets2.py @@ -6,6 +6,8 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal ' +from PyQt4.Qt import QPushButton, QPixmap, QIcon, QColor, Qt, QColorDialog, pyqtSignal + from calibre.gui2.complete2 import LineEdit from calibre.gui2.widgets import history @@ -46,3 +48,45 @@ class HistoryLineEdit2(LineEdit): history.set(self.store_name, self.history) self.update_items_cache(self.history) +class ColorButton(QPushButton): + + color_changed = pyqtSignal(object) + + def __init__(self, initial_color=None, parent=None, choose_text=None): + QPushButton.__init__(self, parent) + self._color = None + self.choose_text = choose_text or _('Choose &color') + self.color = initial_color + self.clicked.connect(self.choose_color) + + @dynamic_property + def color(self): + def fget(self): + return self._color + def fset(self, val): + val = unicode(val or '') + col = QColor(val) + orig = self._color + if col.isValid(): + self._color = val + self.setText(val) + p = QPixmap(self.iconSize()) + p.fill(col) + self.setIcon(QIcon(p)) + else: + self._color = None + self.setText(self.choose_text) + self.setIcon(QIcon()) + if orig != col: + self.color_changed.emit(self._color) + return property(fget=fget, fset=fset) + + def choose_color(self): + col = QColorDialog.getColor(QColor(self._color or Qt.white), self, _('Choose a color')) + if col.isValid(): + r, g, b, a = col.getRgb() + if a != 255: + self.color = '#%02x%02x%02x%02x' % col.getRgb() + else: + self.color = '#%02x%02x%02x' % (r, g, b) + From f6a6ab51c5b5d5686e55320f09887b1f9b5d565d Mon Sep 17 00:00:00 2001 From: Stephan Hradek Date: Thu, 3 Apr 2014 19:12:51 +0200 Subject: [PATCH 5/7] Allow specifying arbitrary colors as hex triplets when creating custom columns with a fixed set of values. Fixes #1302078 [Allowing RGB colors for custom columns](https://bugs.launchpad.net/calibre/+bug/1302078) --- src/calibre/gui2/preferences/create_custom_column.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/preferences/create_custom_column.py b/src/calibre/gui2/preferences/create_custom_column.py index b089844127..c2f21bd2bf 100644 --- a/src/calibre/gui2/preferences/create_custom_column.py +++ b/src/calibre/gui2/preferences/create_custom_column.py @@ -297,7 +297,7 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): return self.simple_error('', _('The colors box must be empty or ' 'contain the same number of items as the value box')) for tc in c: - if tc not in QColor.colorNames(): + if tc not in QColor.colorNames() and not re.match("#(?:[0-9a-f]{3}){1,4}",tc,re.I): return self.simple_error('', _('The color {0} is unknown').format(tc)) From 3346f0af4f6392da385d2b63e13568f9a792105c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 4 Apr 2014 17:28:29 +0530 Subject: [PATCH 6/7] Dont serialize alpha color component as the QColor constructor cannot handle them --- src/calibre/gui2/widgets2.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/calibre/gui2/widgets2.py b/src/calibre/gui2/widgets2.py index c21a6d7ae1..ad4aaee495 100644 --- a/src/calibre/gui2/widgets2.py +++ b/src/calibre/gui2/widgets2.py @@ -84,9 +84,5 @@ class ColorButton(QPushButton): def choose_color(self): col = QColorDialog.getColor(QColor(self._color or Qt.white), self, _('Choose a color')) if col.isValid(): - r, g, b, a = col.getRgb() - if a != 255: - self.color = '#%02x%02x%02x%02x' % col.getRgb() - else: - self.color = '#%02x%02x%02x' % (r, g, b) + self.color = unicode(col.name()) From cadaab14fe3aec64430f6526c8990c8a9f8fc54f Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Fri, 4 Apr 2014 15:07:12 +0200 Subject: [PATCH 7/7] Add Kovid's ColorButton to the advanced coloring rule editor --- src/calibre/gui2/__init__.py | 1 + src/calibre/gui2/dialogs/template_dialog.py | 5 +---- src/calibre/gui2/dialogs/template_dialog.ui | 9 ++++++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index bc61ce9a91..f0a1ad36cd 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1137,6 +1137,7 @@ def build_forms(srcdir, info=None): dat = dat.replace('import images_rc', '') dat = dat.replace('from library import', 'from calibre.gui2.library import') dat = dat.replace('from widgets import', 'from calibre.gui2.widgets import') + dat = dat.replace('from widgets2 import', 'from calibre.gui2.widgets2 import') dat = dat.replace('from convert.xpath_wizard import', 'from calibre.gui2.convert.xpath_wizard import') dat = re.sub(r'^ {4}def _translate\(context, text, disambig\):\s+return.*$', ' pass', dat, diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py index ab185d8a6a..dfd51cb5d9 100644 --- a/src/calibre/gui2/dialogs/template_dialog.py +++ b/src/calibre/gui2/dialogs/template_dialog.py @@ -229,9 +229,6 @@ class TemplateDialog(QDialog, Ui_TemplateDialog): for n1, k1 in cols: self.colored_field.addItem(n1, k1) self.colored_field.setCurrentIndex(self.colored_field.findData(color_field)) - colors = QColor.colorNames() - colors.sort() - self.color_name.addItems(colors) elif self.iconing: self.icon_layout.setVisible(True) for n1, k1 in cols: @@ -362,7 +359,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog): def color_to_clipboard(self): app = QApplication.instance() c = app.clipboard() - c.setText(unicode(self.color_name.currentText())) + c.setText(unicode(self.color_name.color)) def icon_to_clipboard(self): app = QApplication.instance() diff --git a/src/calibre/gui2/dialogs/template_dialog.ui b/src/calibre/gui2/dialogs/template_dialog.ui index 11dafa4627..897e4e1686 100644 --- a/src/calibre/gui2/dialogs/template_dialog.ui +++ b/src/calibre/gui2/dialogs/template_dialog.ui @@ -48,7 +48,7 @@ - + @@ -246,6 +246,13 @@ + + + ColorButton + QPushButton +

widgets2.h
+ +