diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index f50251e700..03fb8fa4eb 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -160,6 +160,7 @@ class EditMetadataAction(InterfaceAction): break changed.add(d.id) + changed |= d.books_to_refresh if d.row_delta == 0: break current_row += d.row_delta diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py index fa20658c12..43e26fad9d 100644 --- a/src/calibre/gui2/dialogs/metadata_single.py +++ b/src/calibre/gui2/dialogs/metadata_single.py @@ -622,6 +622,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): self.original_author = unicode(self.authors.text()).strip() self.original_title = unicode(self.title.text()).strip() + self.books_to_refresh = set() self.show() @@ -775,7 +776,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): _('You have changed the tags. In order to use the tags' ' editor, you must either discard or apply these ' 'changes. Apply changes?'), show_copy_button=False): - self.apply_tags(commit=True, notify=True) + self.books_to_refresh |= self.apply_tags(commit=True, notify=True, + allow_case_change=True) self.original_tags = unicode(self.tags.text()) else: self.tags.setText(self.original_tags) @@ -882,9 +884,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): break def apply_tags(self, commit=False, notify=False): - self.db.set_tags(self.id, [x.strip() for x in - unicode(self.tags.text()).split(',')], - notify=notify, commit=commit) + return self.db.set_tags(self.id, [x.strip() for x in + unicode(self.tags.text()).split(',')], + notify=notify, commit=commit, allow_case_change=True) def next_triggered(self, row_delta, *args): self.row_delta = row_delta @@ -903,7 +905,10 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): self.db.set_title_sort(self.id, ts, notify=False, commit=False) au = unicode(self.authors.text()).strip() if au and au != self.original_author: - self.db.set_authors(self.id, string_to_authors(au), notify=False) + self.books_to_refresh |= self.db.set_authors(self.id, + string_to_authors(au), + notify=False, + allow_case_change=True) aus = unicode(self.author_sort.text()).strip() if aus: self.db.set_author_sort(self.id, aus, notify=False, commit=False) @@ -913,7 +918,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): notify=False, commit=False) self.db.set_rating(self.id, 2*self.rating.value(), notify=False, commit=False) - self.apply_tags() + self.books_to_refresh |= self.apply_tags() self.db.set_publisher(self.id, unicode(self.publisher.currentText()).strip(), notify=False, commit=False) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 31b8cf46bf..088b9f6d02 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -819,6 +819,7 @@ class BooksModel(QAbstractTableModel): # {{{ value.toDate() if column in ('timestamp', 'pubdate') else \ unicode(value.toString()) id = self.db.id(row) + books_to_refresh = set([id]) if column == 'rating': val = 0 if val < 0 else 5 if val > 5 else val val *= 2 @@ -850,8 +851,9 @@ class BooksModel(QAbstractTableModel): # {{{ return False self.db.set_pubdate(id, qt_to_dt(val, as_utc=False)) else: - self.db.set(row, column, val) - self.refresh_ids([id], row) + books_to_refresh |= self.db.set(row, column, val, + allow_case_change=True) + self.refresh_ids(list(books_to_refresh), row) self.dataChanged.emit(index, index) return True diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index bfe54df36e..88f2ce32de 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -1479,17 +1479,19 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): return float(tweaks['series_index_auto_increment']) return 1.0 - def set(self, row, column, val): + def set(self, row, column, val, allow_case_change=False): ''' Convenience method for setting the title, authors, publisher or rating ''' id = self.data[row][0] col = {'title':1, 'authors':2, 'publisher':3, 'rating':4, 'tags':7}[column] + books_to_refresh = set() self.data.set(row, col, val) if column == 'authors': val = string_to_authors(val) - self.set_authors(id, val, notify=False) + books_to_refresh |= self.set_authors(id, val, notify=False, + allow_case_change=allow_case_change) elif column == 'title': self.set_title(id, val, notify=False) elif column == 'publisher': @@ -1497,11 +1499,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): elif column == 'rating': self.set_rating(id, val, notify=False) elif column == 'tags': - self.set_tags(id, [x.strip() for x in val.split(',') if x.strip()], - append=False, notify=False) + books_to_refresh |= \ + self.set_tags(id, [x.strip() for x in val.split(',') if x.strip()], + append=False, notify=False, allow_case_change=allow_case_change) self.data.refresh_ids(self, [id]) self.set_path(id, True) self.notify('metadata', [id]) + return books_to_refresh def set_metadata(self, id, mi, ignore_errors=False, set_title=True, set_authors=True, commit=True): @@ -1627,28 +1631,38 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): result.append(r) return ' & '.join(result).replace('|', ',') - def _set_authors(self, id, authors): + def _set_authors(self, id, authors, allow_case_change=False): if not authors: authors = [_('Unknown')] self.conn.execute('DELETE FROM books_authors_link WHERE book=?',(id,)) + books_to_refresh = set() for a in authors: if not a: continue a = a.strip().replace(',', '|') if not isinstance(a, unicode): a = a.decode(preferred_encoding, 'replace') - author = self.conn.get('SELECT id from authors WHERE name=?', (a,), all=False) - if author: - aid = author + author_id, name = \ + self.conn.get('SELECT id, name from authors WHERE name=?', (a,))[0] + if author_id: + aid = author_id # Handle change of case - self.conn.execute('UPDATE authors SET name=? WHERE id=?', (a, aid)) + if allow_case_change and name != a: + self.conn.execute('UPDATE authors SET name=? WHERE id=?', (a, aid)) + case_change = True else: aid = self.conn.execute('INSERT INTO authors(name) VALUES (?)', (a,)).lastrowid + case_change = False try: self.conn.execute('INSERT INTO books_authors_link(book, author) VALUES (?,?)', (id, aid)) except IntegrityError: # Sometimes books specify the same author twice in their metadata pass + if case_change: + bks = self.conn.get('SELECT book FROM books_authors_link WHERE author=?', + (aid,)) + books_to_refresh |= set([bk[0] for bk in bks]) + ss = self.author_sort_from_book(id, index_is_id=True) self.conn.execute('UPDATE books SET author_sort=? WHERE id=?', (ss, id)) @@ -1660,21 +1674,25 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.data.set(id, self.FIELD_MAP['au_map'], ':#:'.join([':::'.join((au.replace(',', '|'), aus)) for (au, aus) in aum]), row_is_id=True) + return books_to_refresh - def set_authors(self, id, authors, notify=True, commit=True): + def set_authors(self, id, authors, notify=True, commit=True, + allow_case_change=False): ''' Note that even if commit is False, the db will still be committed to because this causes the location of files to change :param authors: A list of authors. ''' - self._set_authors(id, authors) + books_to_refresh = self._set_authors(id, authors, + allow_case_change=allow_case_change) self.dirtied([id], commit=False) if commit: self.conn.commit() self.set_path(id, index_is_id=True) if notify: self.notify('metadata', [id]) + return books_to_refresh def set_title_sort(self, id, title_sort_, notify=True, commit=True): if not title_sort_: @@ -2119,7 +2137,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): def commit(self): self.conn.commit() - def set_tags(self, id, tags, append=False, notify=True, commit=True): + def set_tags(self, id, tags, append=False, notify=True, commit=True, + allow_case_change=False): ''' @param tags: list of strings @param append: If True existing tags are not removed @@ -2129,6 +2148,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.conn.execute('DELETE FROM tags WHERE (SELECT COUNT(id) FROM books_tags_link WHERE tag=tags.id) < 1') otags = self.get_tags(id) tags = self.cleanup_tags(tags) + books_to_refresh = set() for tag in (set(tags)-otags): tag = tag.strip() if not tag: @@ -2144,8 +2164,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if idx > -1: etag = existing_tags[idx] tid = self.conn.get('SELECT id FROM tags WHERE name=?', (etag,), all=False) - if etag != tag: + if allow_case_change and etag != tag: self.conn.execute('UPDATE tags SET name=? WHERE id=?', (tag, tid)) + case_changed = True + else: + case_changed = False else: tid = self.conn.execute('INSERT INTO tags(name) VALUES(?)', (tag,)).lastrowid @@ -2153,6 +2176,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): (id, tid), all=False): self.conn.execute('INSERT INTO books_tags_link(book, tag) VALUES (?,?)', (id, tid)) + if case_changed: + bks = self.conn.get('SELECT book FROM books_tags_link WHERE tag=?', + (tid,)) + books_to_refresh |= set([bk[0] for bk in bks]) self.dirtied([id], commit=False) if commit: self.conn.commit() @@ -2160,6 +2187,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.data.set(id, self.FIELD_MAP['tags'], tags, row_is_id=True) if notify: self.notify('metadata', [id]) + return books_to_refresh def unapply_tags(self, book_id, tags, notify=True): for tag in tags: