From 947ae40a97ea6a2b25ec946c074a5021708a57e0 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Thu, 3 Feb 2011 11:43:38 +0000 Subject: [PATCH] Add case change to series, publishers, and custom columns --- src/calibre/gui2/custom_column_widgets.py | 12 ++- src/calibre/gui2/dialogs/metadata_single.py | 12 +-- src/calibre/gui2/library/models.py | 11 +- src/calibre/library/custom_columns.py | 33 +++--- src/calibre/library/database2.py | 105 ++++++++++++-------- 5 files changed, 108 insertions(+), 65 deletions(-) diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 5180999379..eae6dc79c3 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -44,8 +44,10 @@ class Base(object): val = self.gui_val val = self.normalize_ui_val(val) if val != self.initial_val: - self.db.set_custom(book_id, val, num=self.col_id, notify=notify, - commit=False) + return self.db.set_custom(book_id, val, num=self.col_id, + notify=notify, commit=False, allow_case_change=True) + else: + return set() def normalize_db_val(self, val): return val @@ -330,8 +332,10 @@ class Series(Base): num=self.col_id) else: s_index = None - self.db.set_custom(book_id, val, extra=s_index, - num=self.col_id, notify=notify, commit=False) + return self.db.set_custom(book_id, val, extra=s_index, num=self.col_id, + notify=notify, commit=False, allow_case_change=True) + else: + return set() class Enumeration(Base): diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py index 0085d40c2d..aec8c4fd60 100644 --- a/src/calibre/gui2/dialogs/metadata_single.py +++ b/src/calibre/gui2/dialogs/metadata_single.py @@ -923,12 +923,12 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): self.db.set_rating(self.id, 2*self.rating.value(), notify=False, commit=False) self.books_to_refresh |= self.apply_tags() - self.db.set_publisher(self.id, - unicode(self.publisher.currentText()).strip(), - notify=False, commit=False) - self.db.set_series(self.id, + self.books_to_refresh |= self.db.set_publisher(self.id, + unicode(self.publisher.currentText()).strip(), + notify=False, commit=False, allow_case_change=True) + self.books_to_refresh |= self.db.set_series(self.id, unicode(self.series.currentText()).strip(), notify=False, - commit=False) + commit=False, allow_case_change=True) self.db.set_series_index(self.id, self.series_index.value(), notify=False, commit=False) self.db.set_comment(self.id, @@ -949,7 +949,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): else: self.db.remove_cover(self.id) for w in getattr(self, 'custom_column_widgets', []): - w.commit(self.id) + self.books_to_refresh |= w.commit(self.id) self.db.commit() except IOError, err: if err.errno == 13: # Permission denied diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 088b9f6d02..0b6991665b 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -800,9 +800,10 @@ class BooksModel(QAbstractTableModel): # {{{ return True id = self.db.id(row) - self.db.set_custom(id, val, extra=s_index, + books_to_refresh = set([id]) + books_to_refresh |= self.db.set_custom(id, val, extra=s_index, label=label, num=None, append=False, notify=True) - self.refresh_ids([id], current_row=row) + self.refresh_ids(list(books_to_refresh), current_row=row) return True def setData(self, index, value, role): @@ -827,7 +828,8 @@ class BooksModel(QAbstractTableModel): # {{{ elif column == 'series': val = val.strip() if not val: - self.db.set_series(id, val) + books_to_refresh |= self.db.set_series(id, val, + allow_case_change=True) self.db.set_series_index(id, 1.0) else: pat = re.compile(r'\[([.0-9]+)\]') @@ -841,7 +843,8 @@ class BooksModel(QAbstractTableModel): # {{{ if ni != 1: self.db.set_series_index(id, ni) if val: - self.db.set_series(id, val) + books_to_refresh |= self.db.set_series(id, val, + allow_case_change=True) elif column == 'timestamp': if val.isNull() or not val.isValid(): return False diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py index f94081f046..f166acfbb3 100644 --- a/src/calibre/library/custom_columns.py +++ b/src/calibre/library/custom_columns.py @@ -440,22 +440,24 @@ class CustomColumns(object): self.dirtied(ids, commit=False) self.conn.commit() - def set_custom(self, id, val, label=None, num=None, - append=False, notify=True, extra=None, commit=True): - self._set_custom(id, val, label=label, num=num, append=append, - notify=notify, extra=extra) + def set_custom(self, id, val, label=None, num=None, append=False, + notify=True, extra=None, commit=True, allow_case_change=False): + rv = self._set_custom(id, val, label=label, num=num, append=append, + notify=notify, extra=extra, + allow_case_change=allow_case_change) self.dirtied([id], commit=False) if commit: self.conn.commit() + return rv - def _set_custom(self, id_, val, label=None, num=None, - append=False, notify=True, extra=None): + def _set_custom(self, id_, val, label=None, num=None, append=False, + notify=True, extra=None, allow_case_change=False): if label is not None: data = self.custom_column_label_map[label] if num is not None: data = self.custom_column_num_map[num] if data['datatype'] == 'composite': - return None + return set() if not data['editable']: raise ValueError('Column %r is not editable'%data['label']) table, lt = self.custom_table_names(data['num']) @@ -466,10 +468,11 @@ class CustomColumns(object): if data['datatype'] == 'series' and extra is None: (val, extra) = self._get_series_values(val) + books_to_refresh = set() if data['normalized']: if data['datatype'] == 'enumeration' and ( val and val not in data['display']['enum_values']): - return None + return books_to_refresh if not append or not data['is_multiple']: self.conn.execute('DELETE FROM %s WHERE book=?'%lt, (id_,)) self.conn.execute( @@ -483,6 +486,7 @@ class CustomColumns(object): for x in set(set_val) - set(existing): if x is None: continue + case_change = False existing = list(self.all_custom(num=data['num'])) lx = [t.lower() if hasattr(t, 'lower') else t for t in existing] try: @@ -492,13 +496,14 @@ class CustomColumns(object): if idx > -1: ex = existing[idx] xid = self.conn.get( - 'SELECT id FROM %s WHERE value=?'%table, (ex,), all=False) + 'SELECT id FROM %s WHERE value=?'%table, (ex,), all=False) if ex != x: + case_change = True self.conn.execute( - 'UPDATE %s SET value=? WHERE id=?'%table, (x, xid)) + 'UPDATE %s SET value=? WHERE id=?'%table, (x, xid)) else: xid = self.conn.execute( - 'INSERT INTO %s(value) VALUES(?)'%table, (x,)).lastrowid + 'INSERT INTO %s(value) VALUES(?)'%table, (x,)).lastrowid if not self.conn.get( 'SELECT book FROM %s WHERE book=? AND value=?'%lt, (id_, xid), all=False): @@ -512,6 +517,10 @@ class CustomColumns(object): self.conn.execute( '''INSERT INTO %s(book, value) VALUES (?,?)'''%lt, (id_, xid)) + if case_change: + bks = self.conn.get('SELECT book FROM %s WHERE value=?'%lt, + (xid,)) + books_to_refresh |= set([bk[0] for bk in bks]) nval = self.conn.get( 'SELECT custom_%s FROM meta2 WHERE id=?'%data['num'], (id_,), all=False) @@ -530,7 +539,7 @@ class CustomColumns(object): row_is_id=True) if notify: self.notify('metadata', [id_]) - return nval + return books_to_refresh def clean_custom(self): st = ('DELETE FROM {table} WHERE (SELECT COUNT(id) FROM {lt} WHERE' diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index c147773f1f..54ade889c1 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -1495,7 +1495,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): elif column == 'title': self.set_title(id, val, notify=False) elif column == 'publisher': - self.set_publisher(id, val, notify=False) + books_to_refresh |= self.set_publisher(id, val, notify=False, + allow_case_change=allow_case_change) elif column == 'rating': self.set_rating(id, val, notify=False) elif column == 'tags': @@ -1637,35 +1638,32 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.conn.execute('DELETE FROM books_authors_link WHERE book=?',(id,)) books_to_refresh = set() for a in authors: + case_change = False if not a: continue a = a.strip().replace(',', '|') if not isinstance(a, unicode): a = a.decode(preferred_encoding, 'replace') - aus = self.conn.get('SELECT id, name from authors WHERE name=?', (a,)) + aus = self.conn.get('SELECT id, name FROM authors WHERE name=?', (a,)) if aus: - author_id, name = aus[0] - else: - author_id, name = (None, None) - if author_id: - aid = author_id + aid, name = aus[0] # Handle change of case if allow_case_change and name != a: - self.conn.execute('UPDATE authors SET name=? WHERE id=?', (a, aid)) - case_change = True + 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 + aid = self.conn.execute('''INSERT INTO authors(name) + VALUES (?)''', (a,)).lastrowid try: - self.conn.execute('INSERT INTO books_authors_link(book, author) VALUES (?,?)', - (id, aid)) + 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,)) + 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)) @@ -1755,24 +1753,41 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.notify('metadata', [id]) - def set_publisher(self, id, publisher, notify=True, commit=True): + def set_publisher(self, id, publisher, notify=True, commit=True, + allow_case_change=False): self.conn.execute('DELETE FROM books_publishers_link WHERE book=?',(id,)) - self.conn.execute('DELETE FROM publishers WHERE (SELECT COUNT(id) FROM books_publishers_link WHERE publisher=publishers.id) < 1') + self.conn.execute('''DELETE FROM publishers WHERE (SELECT COUNT(id) + FROM books_publishers_link + WHERE publisher=publishers.id) < 1''') + books_to_refresh = set() if publisher: + case_change = False if not isinstance(publisher, unicode): publisher = publisher.decode(preferred_encoding, 'replace') - pub = self.conn.get('SELECT id from publishers WHERE name=?', (publisher,), all=False) - if pub: - aid = pub + pubx = self.conn.get('''SELECT id,name from publishers + WHERE name=?''', (publisher,)) + if pubx: + aid, cur_name = pubx[0] + if allow_case_change and publisher != cur_name: + self.conn.execute('''UPDATE publishers SET name=? + WHERE id=?''', (publisher, aid)) + case_change = True else: - aid = self.conn.execute('INSERT INTO publishers(name) VALUES (?)', (publisher,)).lastrowid - self.conn.execute('INSERT INTO books_publishers_link(book, publisher) VALUES (?,?)', (id, aid)) - self.dirtied([id], commit=False) - if commit: - self.conn.commit() - self.data.set(id, self.FIELD_MAP['publisher'], publisher, row_is_id=True) - if notify: - self.notify('metadata', [id]) + aid = self.conn.execute('''INSERT INTO publishers(name) + VALUES (?)''', (publisher,)).lastrowid + self.conn.execute('''INSERT INTO books_publishers_link(book, publisher) + VALUES (?,?)''', (id, aid)) + if case_change: + bks = self.conn.get('''SELECT book FROM books_publishers_link + WHERE publisher=?''', (aid,)) + books_to_refresh |= set([bk[0] for bk in bks]) + self.dirtied([id], commit=False) + if commit: + self.conn.commit() + self.data.set(id, self.FIELD_MAP['publisher'], publisher, row_is_id=True) + if notify: + self.notify('metadata', [id]) + return books_to_refresh def set_uuid(self, id, uuid, notify=True, commit=True): if uuid: @@ -2144,7 +2159,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): ''' if not append: self.conn.execute('DELETE FROM books_tags_link WHERE book=?', (id,)) - self.conn.execute('DELETE FROM tags WHERE (SELECT COUNT(id) FROM books_tags_link WHERE tag=tags.id) < 1') + 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() @@ -2170,10 +2186,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): else: tid = self.conn.execute('INSERT INTO tags(name) VALUES(?)', (tag,)).lastrowid - if not self.conn.get('SELECT book FROM books_tags_link WHERE book=? AND tag=?', - (id, tid), all=False): - self.conn.execute('INSERT INTO books_tags_link(book, tag) VALUES (?,?)', - (id, tid)) + if not self.conn.get('''SELECT book FROM books_tags_link + WHERE book=? AND tag=?''', (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,)) @@ -2191,7 +2207,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): for tag in tags: id = self.conn.get('SELECT id FROM tags WHERE name=?', (tag,), all=False) if id: - self.conn.execute('DELETE FROM books_tags_link WHERE tag=? AND book=?', (id, book_id)) + self.conn.execute('''DELETE FROM books_tags_link + WHERE tag=? AND book=?''', (id, book_id)) self.conn.commit() self.data.refresh_ids(self, [book_id]) if notify: @@ -2235,31 +2252,41 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): pass return (val, None) - def set_series(self, id, series, notify=True, commit=True): + def set_series(self, id, series, notify=True, commit=True, allow_case_change=True): self.conn.execute('DELETE FROM books_series_link WHERE book=?',(id,)) self.conn.execute('''DELETE FROM series WHERE (SELECT COUNT(id) FROM books_series_link WHERE series=series.id) < 1''') (series, idx) = self._get_series_values(series) + books_to_refresh = set() if series: + case_change = False if not isinstance(series, unicode): series = series.decode(preferred_encoding, 'replace') series = series.strip() series = u' '.join(series.split()) - s = self.conn.get('SELECT id from series WHERE name=?', (series,), all=False) - if s: - aid = s + sx = self.conn.get('SELECT id,name from series WHERE name=?', (series,)) + if sx: + aid, cur_name = sx[0] + if allow_case_change and cur_name != series: + self.conn.execute('UPDATE series SET name=? WHERE id=?', (series, aid)) + case_change = True else: aid = self.conn.execute('INSERT INTO series(name) VALUES (?)', (series,)).lastrowid self.conn.execute('INSERT INTO books_series_link(book, series) VALUES (?,?)', (id, aid)) if idx: self.set_series_index(id, idx, notify=notify, commit=commit) + if case_change: + bks = self.conn.get('SELECT book FROM books_series_link WHERE series=?', + (aid,)) + books_to_refresh |= set([bk[0] for bk in bks]) self.dirtied([id], commit=False) if commit: self.conn.commit() self.data.set(id, self.FIELD_MAP['series'], series, row_is_id=True) if notify: self.notify('metadata', [id]) + return books_to_refresh def set_series_index(self, id, idx, notify=True, commit=True): if idx is None: