diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index b0b68033bb..6b6669f4e0 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -318,16 +318,14 @@ class Enumeration(Base): QComboBox(parent)] w = self.widgets[1] vals = self.col_metadata['display']['enum_values'] + w.addItem('') for v in vals: w.addItem(v) def initialize(self, book_id): val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) - if val is None: - # This really shouldn't happen - val = self.col_metadata['display']['enum_values'][0] - self.initial_val = val val = self.normalize_db_val(val) + self.initial_val = val idx = self.widgets[1].findText(val) if idx < 0: error_dialog(self.parent, '', @@ -340,13 +338,21 @@ class Enumeration(Base): self.widgets[1].setCurrentIndex(idx) def setter(self, val): - if val is None: - val = '' self.widgets[1].setCurrentIndex(self.widgets[1].findText(val)) def getter(self): return unicode(self.widgets[1].currentText()) + def normalize_db_val(self, val): + if val is None: + val = '' + return val + + def normalize_ui_val(self, val): + if not val: + val = None + return val + widgets = { 'bool' : Bool, 'rating' : Rating, @@ -597,7 +603,7 @@ class BulkEnumeration(BulkBase, Enumeration): dialog_shown = False for book_id in book_ids: val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) - if val not in self.col_metadata['display']['enum_values']: + if val and val not in self.col_metadata['display']['enum_values']: if not dialog_shown: error_dialog(self.parent, '', _('The enumeration "{0}" contains invalid values ' @@ -620,6 +626,7 @@ class BulkEnumeration(BulkBase, Enumeration): w = self.widgets[1] vals = self.col_metadata['display']['enum_values'] w.addItem('Do Not Change') + w.addItem('') for v in vals: w.addItem(v) @@ -632,7 +639,10 @@ class BulkEnumeration(BulkBase, Enumeration): if val == ' nochange ': self.widgets[1].setCurrentIndex(0) else: - self.widgets[1].setCurrentIndex(self.widgets[1].findText(val)) + if val is None: + self.widgets[1].setCurrentIndex(1) + else: + self.widgets[1].setCurrentIndex(self.widgets[1].findText(val)) def commit(self, book_ids, notify=False): val = self.gui_val @@ -640,12 +650,6 @@ class BulkEnumeration(BulkBase, Enumeration): if val != self.initial_val and val != ' nochange ': self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify) - def normalize_db_val(self, val): - if val is None: - # this really shouldn't happen - val = self.col_metadata['display']['enum_values'][0] - return val - class RemoveTags(QWidget): def __init__(self, parent, values): diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index bb73a55fc9..03309d1fba 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -263,28 +263,22 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{ m = index.model() col = m.column_map[index.column()] editor = QComboBox(parent) + editor.addItem('') for v in m.custom_columns[col]['display']['enum_values']: editor.addItem(v) return editor def setModelData(self, editor, model, index): val = unicode(editor.currentText()) - m = index.model() - col = m.column_map[index.column()] - if val not in m.custom_columns[col]['display']['enum_values']: - # This shouldn't happen ... - print 'shouldnt happen' - val = m.custom_columns[col]['display']['enum_values'][0] + if not val: + val = None model.setData(index, QVariant(val), Qt.EditRole) def setEditorData(self, editor, index): m = index.model() val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']] if val is None: - # This shouldn't happen - m = index.model() - col = m.column_map[index.column()] - val = m.custom_columns[col]['display']['enum_values'][0] + val = '' idx = editor.findText(val) if idx < 0: editor.setCurrentIndex(0) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index bee90fc44c..e09f85dc6b 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -724,6 +724,8 @@ class BooksModel(QAbstractTableModel): # {{{ val = val if val else None elif typ == 'enumeration': val = unicode(value.toString()).strip() + if not val: + val = None elif typ == 'bool': val = value.toPyObject() elif typ == 'rating': @@ -732,7 +734,7 @@ class BooksModel(QAbstractTableModel): # {{{ val *= 2 elif typ in ('int', 'float'): val = unicode(value.toString()).strip() - if val is None or not val: + if not val: val = None elif typ == 'datetime': val = value.toDate() diff --git a/src/calibre/gui2/preferences/create_custom_column.py b/src/calibre/gui2/preferences/create_custom_column.py index 419fed046d..3eed04f709 100644 --- a/src/calibre/gui2/preferences/create_custom_column.py +++ b/src/calibre/gui2/preferences/create_custom_column.py @@ -167,6 +167,10 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn): return self.simple_error('', _('You must enter at least one' ' value for enumeration columns')) l = [v.strip() for v in unicode(self.enum_box.text()).split(',')] + for v in l: + if not v: + return self.simple_error('', _('You cannot provide the empty ' + 'value, as it is included by default')) for i in range(0, len(l)-1): if l[i] in l[i+1:]: return self.simple_error('', _('The value "{0}" is in the ' diff --git a/src/calibre/gui2/preferences/create_custom_column.ui b/src/calibre/gui2/preferences/create_custom_column.ui index 360c1a4345..bdf4f624a4 100644 --- a/src/calibre/gui2/preferences/create_custom_column.ui +++ b/src/calibre/gui2/preferences/create_custom_column.ui @@ -212,10 +212,9 @@ - A comma-separated list of permitted values. You can specify -empty values by entering only the comma. For example, the list -',one,two,three' has 4 valid values, one of them empty. The first -value in the list is the default. + A comma-separated list of permitted values. The empty value is always +included, and is the default. For example, the list 'one,two,three' has +four values, the first of them being the empty value. @@ -231,7 +230,7 @@ value in the list is the default. Default: (nothing) - The first value entered will be the default value for this enumeration + The empty string is always the first value diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 972a1eeba3..768b699ca9 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -106,10 +106,13 @@ class TagsView(QTreeView): # {{{ self.refresh_required.connect(self.recount, type=Qt.QueuedConnection) self.sort_by.currentIndexChanged.connect(self.sort_changed) self.made_connections = True + self.refresh_signal_processed = True db.add_listener(self.database_changed) def database_changed(self, event, ids): - self.refresh_required.emit() + if self.refresh_signal_processed: + self.refresh_signal_processed = False + self.refresh_required.emit() @property def match_all(self): @@ -295,6 +298,7 @@ class TagsView(QTreeView): # {{{ return self.isExpanded(idx) def recount(self, *args): + self.refresh_signal_processed = True ci = self.currentIndex() if not ci.isValid(): ci = self.indexAt(QPoint(10, 10)) @@ -937,7 +941,9 @@ class TagBrowserMixin(object): # {{{ if old_author != new_author: # The id might change if the new author already exists id = db.rename_author(id, new_author) - db.set_sort_field_for_author(id, unicode(new_sort)) + db.set_sort_field_for_author(id, unicode(new_sort), + commit=False, notify=False) + db.commit() self.library_view.model().refresh() self.tags_view.recount() diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index 8365cfe773..7b4c66c8b8 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -254,12 +254,6 @@ class ResultCache(SearchQueryParser): # {{{ if field_metadata[key]['datatype'] == 'composite': self.composites.append((key, field_metadata[key]['rec_index'])) - self.enumerations = [] - for key in field_metadata: - if field_metadata[key]['datatype'] == 'enumeration': - self.enumerations.append((field_metadata[key]['display']['enum_values'][0], - field_metadata[key]['rec_index'])) - def __getitem__(self, row): return self._data[self._map_filtered[row]] @@ -697,10 +691,6 @@ class ResultCache(SearchQueryParser): # {{{ mi = db.get_metadata(id, index_is_id=True) for k,c in self.composites: self._data[id][c] = mi.get(k, None) - if len(self.enumerations) > 0: - for v,c in self.enumerations: - if self._data[id][c] is None: - self._data[id][c] = v except IndexError: return None try: @@ -721,10 +711,6 @@ class ResultCache(SearchQueryParser): # {{{ mi = db.get_metadata(id, index_is_id=True) for k,c in self.composites: self._data[id][c] = mi.get(k) - if len(self.enumerations) > 0: - for v,c in self.self._data[id][c]: - if self._data[id][c] is None: - self._data[id][c] = v self._map[0:0] = ids self._map_filtered[0:0] = ids @@ -754,10 +740,6 @@ class ResultCache(SearchQueryParser): # {{{ mi = db.get_metadata(item[0], index_is_id=True) for k,c in self.composites: item[c] = mi.get(k) - if len(self.enumerations) > 0: - for v,c in self.enumerations: - if item[c] is None: - item[c] = v self._map = [i[0] for i in self._data if i is not None] if field is not None: diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py index dc3a67e860..f544a9bf7e 100644 --- a/src/calibre/library/custom_columns.py +++ b/src/calibre/library/custom_columns.py @@ -136,6 +136,12 @@ class CustomColumns(object): x = bool(int(x)) return x + def adapt_enum(x, d): + v = adapt_text(x, d) + if not v: + v = None + return v + self.custom_data_adapters = { 'float': lambda x,d : x if x is None else float(x), 'int': lambda x,d : x if x is None else int(x), @@ -145,7 +151,7 @@ class CustomColumns(object): 'datetime' : adapt_datetime, 'text':adapt_text, 'series':adapt_text, - 'enumeration': adapt_text + 'enumeration': adapt_enum } # Create Tag Browser categories for custom columns @@ -177,8 +183,6 @@ class CustomColumns(object): ans = ans.split('|') if ans else [] if data['display'].get('sort_alpha', False): ans.sort(cmp=lambda x,y:cmp(x.lower(), y.lower())) - elif data['datatype'] == 'enumeration' and ans is None: - ans = data['display']['enum_values'][0] return ans def get_custom_extra(self, idx, label=None, num=None, index_is_id=False): @@ -442,8 +446,8 @@ class CustomColumns(object): val = self.custom_data_adapters[data['datatype']](val, data) if data['normalized']: - if data['datatype'] == 'enumeration' and \ - val not in data['display']['enum_values']: + if data['datatype'] == 'enumeration' and ( + val and val not in data['display']['enum_values']): return None if not append or not data['is_multiple']: self.conn.execute('DELETE FROM %s WHERE book=?'%lt, (id_,)) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index a07e46577e..4e05aa3a95 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -1639,15 +1639,16 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): return [] return result - def set_sort_field_for_author(self, old_id, new_sort): + def set_sort_field_for_author(self, old_id, new_sort, commit=True, notify=False): self.conn.execute('UPDATE authors SET sort=? WHERE id=?', \ (new_sort.strip(), old_id)) - self.conn.commit() + if commit: + self.conn.commit() # Now change all the author_sort fields in books by this author bks = self.conn.get('SELECT book from books_authors_link WHERE author=?', (old_id,)) for (book_id,) in bks: ss = self.author_sort_from_book(book_id, index_is_id=True) - self.set_author_sort(book_id, ss) + self.set_author_sort(book_id, ss, notify=notify, commit=commit) def rename_author(self, old_id, new_name): # Make sure that any commas in new_name are changed to '|'!