From ae8764d4563e2e88f3f56976f446e9198d4386a8 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 13 Dec 2010 12:33:33 +0000 Subject: [PATCH 1/6] Enhancement #7881 - keep manage tags editor positioned near last delete. --- src/calibre/gui2/dialogs/tag_list_editor.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/dialogs/tag_list_editor.py b/src/calibre/gui2/dialogs/tag_list_editor.py index a7d6fe03e7..ced0e9a505 100644 --- a/src/calibre/gui2/dialogs/tag_list_editor.py +++ b/src/calibre/gui2/dialogs/tag_list_editor.py @@ -105,9 +105,13 @@ class TagListEditor(QDialog, Ui_TagListEditor): if not question_dialog(self, _('Are your sure?'), '

'+_('Are you certain you want to delete the following items?')+'
'+ct): return - + row = self.available_tags.row(deletes[0]) for item in deletes: (id,ign) = item.data(Qt.UserRole).toInt() self.to_delete.append(id) self.available_tags.takeItem(self.available_tags.row(item)) + if row >= self.available_tags.count(): + row = self.available_tags.count() - 1 + if row >= 0: + self.available_tags.scrollToItem(self.available_tags.item(row)) From a110eb19ddd82eac08e63b5bf98539d52e578bf3 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 13 Dec 2010 15:08:05 +0000 Subject: [PATCH 2/6] Fix bug in sorting using icu sort_key --- src/calibre/gui2/dialogs/tag_categories.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/dialogs/tag_categories.py b/src/calibre/gui2/dialogs/tag_categories.py index 60092e4bd2..7573f04012 100644 --- a/src/calibre/gui2/dialogs/tag_categories.py +++ b/src/calibre/gui2/dialogs/tag_categories.py @@ -145,7 +145,7 @@ class TagCategories(QDialog, Ui_TagCategories): index = self.all_items[node.data(Qt.UserRole).toPyObject()].index if index not in self.applied_items: self.applied_items.append(index) - self.applied_items.sort(key=lambda x:sort_key(self.all_items[x])) + self.applied_items.sort(key=lambda x:sort_key(self.all_items[x].name)) self.display_filtered_categories(None) def unapply_tags(self, node=None): From 881bfef0f2ca3298bd85ace291d90fd974d8c2a8 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 13 Dec 2010 15:12:53 +0000 Subject: [PATCH 3/6] Avoid doing tag_view.recount() when the tags pane is not visible --- src/calibre/gui2/init.py | 2 ++ src/calibre/gui2/tag_view.py | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 27a6a2352a..fc70f0579d 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -123,6 +123,8 @@ class Stack(QStackedWidget): # {{{ _('Tag Browser'), I('tags.png'), parent=parent, side_index=0, initial_side_size=200, shortcut=_('Shift+Alt+T')) + parent.tb_splitter.state_changed.connect( + self.tb_widget.set_pane_is_visible, Qt.QueuedConnection) parent.tb_splitter.addWidget(self.tb_widget) parent.tb_splitter.addWidget(parent.cb_splitter) parent.tb_splitter.setCollapsible(parent.tb_splitter.other_index, False) diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 2ede698c85..d6c0156f13 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -87,6 +87,13 @@ class TagsView(QTreeView): # {{{ self.setDragDropMode(self.DropOnly) self.setDropIndicatorShown(True) self.setAutoExpandDelay(500) + self.pane_is_visible = False + + def set_pane_is_visible(self, to_what): + pv = self.pane_is_visible + self.pane_is_visible = to_what + if to_what and not pv: + self.recount() def set_database(self, db, tag_match, sort_by): self.hidden_categories = config['tag_browser_hidden_categories'] @@ -300,7 +307,7 @@ class TagsView(QTreeView): # {{{ return self.isExpanded(idx) def recount(self, *args): - if self.disable_recounting: + if self.disable_recounting or not self.pane_is_visible: return self.refresh_signal_processed = True ci = self.currentIndex() @@ -969,6 +976,7 @@ class TagBrowserWidget(QWidget): # {{{ self._layout.setContentsMargins(0,0,0,0) parent.tags_view = TagsView(parent) + self.tags_view = parent.tags_view self._layout.addWidget(parent.tags_view) parent.sort_by = QComboBox(parent) @@ -998,6 +1006,9 @@ class TagBrowserWidget(QWidget): # {{{ _('Add your own categories to the Tag Browser')) parent.edit_categories.setStatusTip(parent.edit_categories.toolTip()) + def set_pane_is_visible(self, to_what): + self.tags_view.set_pane_is_visible(to_what) + # }}} From c260cb052b7cea5b5e43be29bfe57f3d384f2d21 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 13 Dec 2010 19:11:41 +0000 Subject: [PATCH 4/6] Fix #7888: empty tags list throws exception in save_to_disk, converting the result to 'tags' --- src/calibre/library/save_to_disk.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/calibre/library/save_to_disk.py b/src/calibre/library/save_to_disk.py index af57d563ac..62a2e28e27 100644 --- a/src/calibre/library/save_to_disk.py +++ b/src/calibre/library/save_to_disk.py @@ -119,10 +119,8 @@ class SafeFormat(TemplateFormatter): try: b = self.book.get_user_metadata(key, False) except: - if DEBUG: - traceback.print_exc() + traceback.print_exc() b = None - if b is not None and b['datatype'] == 'composite': if key in self.composite_values: return self.composite_values[key] @@ -135,8 +133,7 @@ class SafeFormat(TemplateFormatter): return val.replace('/', '_').replace('\\', '_') return '' except: - if DEBUG: - traceback.print_exc() + traceback.print_exc() return key def get_components(template, mi, id, timefmt='%b %Y', length=250, @@ -155,6 +152,8 @@ def get_components(template, mi, id, timefmt='%b %Y', length=250, format_args['tags'] = mi.format_tags() if format_args['tags'].startswith('/'): format_args['tags'] = format_args['tags'][1:] + else: + format_args['tags'] = '' if mi.series: format_args['series'] = tsfmt(mi.series) if mi.series_index is not None: From be0f3b096a019d35ff35f390472cb254da8c1e23 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 13 Dec 2010 13:29:07 -0700 Subject: [PATCH 5/6] Fix a regression in 0.7.33 that broke updating covers in ebook files when saving to disk. Fixes #7886 (Possible bug in setting new cover) --- src/calibre/library/save_to_disk.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/calibre/library/save_to_disk.py b/src/calibre/library/save_to_disk.py index 62a2e28e27..7090a2afa8 100644 --- a/src/calibre/library/save_to_disk.py +++ b/src/calibre/library/save_to_disk.py @@ -253,6 +253,7 @@ def do_save_book_to_disk(id_, mi, cover, plugboards, if not os.path.exists(dirpath): raise + ocover = mi.cover if opts.save_cover and cover and os.access(cover, os.R_OK): with open(base_path+'.jpg', 'wb') as f: with open(cover, 'rb') as s: @@ -266,6 +267,8 @@ def do_save_book_to_disk(id_, mi, cover, plugboards, with open(base_path+'.opf', 'wb') as f: f.write(opf) + mi.cover = ocover + written = False for fmt in formats: global plugboard_save_to_disk_value, plugboard_any_format_value From 3a1fd7af5665ddcfb8523ae460359703e7779ac8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 13 Dec 2010 15:06:34 -0700 Subject: [PATCH 6/6] Bulk metadata edit: Add options to delete cover/generate default cover. Fixes #7885 (Bulk remove covers) --- src/calibre/gui2/dialogs/metadata_bulk.py | 26 +++++++++++++++-- src/calibre/gui2/dialogs/metadata_bulk.ui | 35 ++++++++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index a640c50fb8..e0f1f83c73 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -102,7 +102,7 @@ class MyBlockingBusy(QDialog): remove_all, remove, add, au, aus, do_aus, rating, pub, do_series, \ do_autonumber, do_remove_format, remove_format, do_swap_ta, \ do_remove_conv, do_auto_author, series, do_series_restart, \ - series_start_value, do_title_case, clear_series = self.args + series_start_value, do_title_case, cover_action, clear_series = self.args # first loop: do author and title. These will commit at the end of each @@ -129,6 +129,23 @@ class MyBlockingBusy(QDialog): self.db.set_title(id, titlecase(title), notify=False) if au: self.db.set_authors(id, string_to_authors(au), notify=False) + if cover_action == 'remove': + self.db.remove_cover(id) + elif cover_action == 'generate': + from calibre.ebooks import calibre_cover + from calibre.ebooks.metadata import fmt_sidx + from calibre.gui2 import config + mi = self.db.get_metadata(id, index_is_id=True) + series_string = None + if mi.series: + series_string = _('Book %s of %s')%( + fmt_sidx(mi.series_index, + use_roman=config['use_roman_numerals_for_series_number']), + mi.series) + + cdata = calibre_cover(mi.title, mi.format_field('authors')[-1], + series_string=series_string) + self.db.set_cover(id, cdata) elif self.current_phase == 2: # All of these just affect the DB, so we can tolerate a total rollback if do_auto_author: @@ -678,11 +695,16 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): do_remove_conv = self.remove_conversion_settings.isChecked() do_auto_author = self.auto_author_sort.isChecked() do_title_case = self.change_title_to_title_case.isChecked() + cover_action = None + if self.cover_remove.isChecked(): + cover_action = 'remove' + elif self.cover_generate.isChecked(): + cover_action = 'generate' args = (remove_all, remove, add, au, aus, do_aus, rating, pub, do_series, do_autonumber, do_remove_format, remove_format, do_swap_ta, do_remove_conv, do_auto_author, series, do_series_restart, - series_start_value, do_title_case, clear_series) + series_start_value, do_title_case, cover_action, clear_series) bb = MyBlockingBusy(_('Applying changes to %d books.\nPhase {0} {1}%%.') %len(self.ids), args, self.db, self.ids, diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 344bde0fa0..cd644f88ba 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -381,7 +381,7 @@ Future conversion of these books will use the default settings. - + Qt::Vertical @@ -394,6 +394,39 @@ Future conversion of these books will use the default settings. + + + + Change &cover + + + + + + &No change + + + true + + + + + + + &Remove cover + + + + + + + &Generate default cover + + + + + +