enums now always have None. Significant speed increasing when recomputing author sort values

This commit is contained in:
Kovid Goyal 2010-12-03 09:30:51 -07:00
commit 3be66119d0
9 changed files with 54 additions and 58 deletions

View File

@ -318,16 +318,14 @@ class Enumeration(Base):
QComboBox(parent)] QComboBox(parent)]
w = self.widgets[1] w = self.widgets[1]
vals = self.col_metadata['display']['enum_values'] vals = self.col_metadata['display']['enum_values']
w.addItem('')
for v in vals: for v in vals:
w.addItem(v) w.addItem(v)
def initialize(self, book_id): def initialize(self, book_id):
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) 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) val = self.normalize_db_val(val)
self.initial_val = val
idx = self.widgets[1].findText(val) idx = self.widgets[1].findText(val)
if idx < 0: if idx < 0:
error_dialog(self.parent, '', error_dialog(self.parent, '',
@ -340,13 +338,21 @@ class Enumeration(Base):
self.widgets[1].setCurrentIndex(idx) self.widgets[1].setCurrentIndex(idx)
def setter(self, val): def setter(self, val):
if val is None:
val = ''
self.widgets[1].setCurrentIndex(self.widgets[1].findText(val)) self.widgets[1].setCurrentIndex(self.widgets[1].findText(val))
def getter(self): def getter(self):
return unicode(self.widgets[1].currentText()) 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 = { widgets = {
'bool' : Bool, 'bool' : Bool,
'rating' : Rating, 'rating' : Rating,
@ -597,7 +603,7 @@ class BulkEnumeration(BulkBase, Enumeration):
dialog_shown = False dialog_shown = False
for book_id in book_ids: for book_id in book_ids:
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) 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: if not dialog_shown:
error_dialog(self.parent, '', error_dialog(self.parent, '',
_('The enumeration "{0}" contains invalid values ' _('The enumeration "{0}" contains invalid values '
@ -620,6 +626,7 @@ class BulkEnumeration(BulkBase, Enumeration):
w = self.widgets[1] w = self.widgets[1]
vals = self.col_metadata['display']['enum_values'] vals = self.col_metadata['display']['enum_values']
w.addItem('Do Not Change') w.addItem('Do Not Change')
w.addItem('')
for v in vals: for v in vals:
w.addItem(v) w.addItem(v)
@ -631,6 +638,9 @@ class BulkEnumeration(BulkBase, Enumeration):
def setter(self, val): def setter(self, val):
if val == ' nochange ': if val == ' nochange ':
self.widgets[1].setCurrentIndex(0) self.widgets[1].setCurrentIndex(0)
else:
if val is None:
self.widgets[1].setCurrentIndex(1)
else: else:
self.widgets[1].setCurrentIndex(self.widgets[1].findText(val)) self.widgets[1].setCurrentIndex(self.widgets[1].findText(val))
@ -640,12 +650,6 @@ class BulkEnumeration(BulkBase, Enumeration):
if val != self.initial_val and val != ' nochange ': if val != self.initial_val and val != ' nochange ':
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify) 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): class RemoveTags(QWidget):
def __init__(self, parent, values): def __init__(self, parent, values):

View File

@ -263,28 +263,22 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{
m = index.model() m = index.model()
col = m.column_map[index.column()] col = m.column_map[index.column()]
editor = QComboBox(parent) editor = QComboBox(parent)
editor.addItem('')
for v in m.custom_columns[col]['display']['enum_values']: for v in m.custom_columns[col]['display']['enum_values']:
editor.addItem(v) editor.addItem(v)
return editor return editor
def setModelData(self, editor, model, index): def setModelData(self, editor, model, index):
val = unicode(editor.currentText()) val = unicode(editor.currentText())
m = index.model() if not val:
col = m.column_map[index.column()] val = None
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]
model.setData(index, QVariant(val), Qt.EditRole) model.setData(index, QVariant(val), Qt.EditRole)
def setEditorData(self, editor, index): def setEditorData(self, editor, index):
m = index.model() m = index.model()
val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']] val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']]
if val is None: if val is None:
# This shouldn't happen val = ''
m = index.model()
col = m.column_map[index.column()]
val = m.custom_columns[col]['display']['enum_values'][0]
idx = editor.findText(val) idx = editor.findText(val)
if idx < 0: if idx < 0:
editor.setCurrentIndex(0) editor.setCurrentIndex(0)

View File

@ -724,6 +724,8 @@ class BooksModel(QAbstractTableModel): # {{{
val = val if val else None val = val if val else None
elif typ == 'enumeration': elif typ == 'enumeration':
val = unicode(value.toString()).strip() val = unicode(value.toString()).strip()
if not val:
val = None
elif typ == 'bool': elif typ == 'bool':
val = value.toPyObject() val = value.toPyObject()
elif typ == 'rating': elif typ == 'rating':
@ -732,7 +734,7 @@ class BooksModel(QAbstractTableModel): # {{{
val *= 2 val *= 2
elif typ in ('int', 'float'): elif typ in ('int', 'float'):
val = unicode(value.toString()).strip() val = unicode(value.toString()).strip()
if val is None or not val: if not val:
val = None val = None
elif typ == 'datetime': elif typ == 'datetime':
val = value.toDate() val = value.toDate()

View File

@ -167,6 +167,10 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
return self.simple_error('', _('You must enter at least one' return self.simple_error('', _('You must enter at least one'
' value for enumeration columns')) ' value for enumeration columns'))
l = [v.strip() for v in unicode(self.enum_box.text()).split(',')] 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): for i in range(0, len(l)-1):
if l[i] in l[i+1:]: if l[i] in l[i+1:]:
return self.simple_error('', _('The value "{0}" is in the ' return self.simple_error('', _('The value "{0}" is in the '

View File

@ -212,10 +212,9 @@
<item> <item>
<widget class="QLineEdit" name="enum_box"> <widget class="QLineEdit" name="enum_box">
<property name="toolTip"> <property name="toolTip">
<string>A comma-separated list of permitted values. You can specify <string>A comma-separated list of permitted values. The empty value is always
empty values by entering only the comma. For example, the list included, and is the default. For example, the list 'one,two,three' has
',one,two,three' has 4 valid values, one of them empty. The first four values, the first of them being the empty value.</string>
value in the list is the default.</string>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@ -231,7 +230,7 @@ value in the list is the default.</string>
<string>Default: (nothing)</string> <string>Default: (nothing)</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>The first value entered will be the default value for this enumeration</string> <string>The empty string is always the first value</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -106,9 +106,12 @@ class TagsView(QTreeView): # {{{
self.refresh_required.connect(self.recount, type=Qt.QueuedConnection) self.refresh_required.connect(self.recount, type=Qt.QueuedConnection)
self.sort_by.currentIndexChanged.connect(self.sort_changed) self.sort_by.currentIndexChanged.connect(self.sort_changed)
self.made_connections = True self.made_connections = True
self.refresh_signal_processed = True
db.add_listener(self.database_changed) db.add_listener(self.database_changed)
def database_changed(self, event, ids): def database_changed(self, event, ids):
if self.refresh_signal_processed:
self.refresh_signal_processed = False
self.refresh_required.emit() self.refresh_required.emit()
@property @property
@ -295,6 +298,7 @@ class TagsView(QTreeView): # {{{
return self.isExpanded(idx) return self.isExpanded(idx)
def recount(self, *args): def recount(self, *args):
self.refresh_signal_processed = True
ci = self.currentIndex() ci = self.currentIndex()
if not ci.isValid(): if not ci.isValid():
ci = self.indexAt(QPoint(10, 10)) ci = self.indexAt(QPoint(10, 10))
@ -937,7 +941,9 @@ class TagBrowserMixin(object): # {{{
if old_author != new_author: if old_author != new_author:
# The id might change if the new author already exists # The id might change if the new author already exists
id = db.rename_author(id, new_author) 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.library_view.model().refresh()
self.tags_view.recount() self.tags_view.recount()

View File

@ -254,12 +254,6 @@ class ResultCache(SearchQueryParser): # {{{
if field_metadata[key]['datatype'] == 'composite': if field_metadata[key]['datatype'] == 'composite':
self.composites.append((key, field_metadata[key]['rec_index'])) 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): def __getitem__(self, row):
return self._data[self._map_filtered[row]] return self._data[self._map_filtered[row]]
@ -697,10 +691,6 @@ class ResultCache(SearchQueryParser): # {{{
mi = db.get_metadata(id, index_is_id=True) mi = db.get_metadata(id, index_is_id=True)
for k,c in self.composites: for k,c in self.composites:
self._data[id][c] = mi.get(k, None) 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: except IndexError:
return None return None
try: try:
@ -721,10 +711,6 @@ class ResultCache(SearchQueryParser): # {{{
mi = db.get_metadata(id, index_is_id=True) mi = db.get_metadata(id, index_is_id=True)
for k,c in self.composites: for k,c in self.composites:
self._data[id][c] = mi.get(k) 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[0:0] = ids
self._map_filtered[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) mi = db.get_metadata(item[0], index_is_id=True)
for k,c in self.composites: for k,c in self.composites:
item[c] = mi.get(k) 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] self._map = [i[0] for i in self._data if i is not None]
if field is not None: if field is not None:

View File

@ -136,6 +136,12 @@ class CustomColumns(object):
x = bool(int(x)) x = bool(int(x))
return x return x
def adapt_enum(x, d):
v = adapt_text(x, d)
if not v:
v = None
return v
self.custom_data_adapters = { self.custom_data_adapters = {
'float': lambda x,d : x if x is None else float(x), 'float': lambda x,d : x if x is None else float(x),
'int': lambda x,d : x if x is None else int(x), 'int': lambda x,d : x if x is None else int(x),
@ -145,7 +151,7 @@ class CustomColumns(object):
'datetime' : adapt_datetime, 'datetime' : adapt_datetime,
'text':adapt_text, 'text':adapt_text,
'series':adapt_text, 'series':adapt_text,
'enumeration': adapt_text 'enumeration': adapt_enum
} }
# Create Tag Browser categories for custom columns # Create Tag Browser categories for custom columns
@ -177,8 +183,6 @@ class CustomColumns(object):
ans = ans.split('|') if ans else [] ans = ans.split('|') if ans else []
if data['display'].get('sort_alpha', False): if data['display'].get('sort_alpha', False):
ans.sort(cmp=lambda x,y:cmp(x.lower(), y.lower())) 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 return ans
def get_custom_extra(self, idx, label=None, num=None, index_is_id=False): 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) val = self.custom_data_adapters[data['datatype']](val, data)
if data['normalized']: if data['normalized']:
if data['datatype'] == 'enumeration' and \ if data['datatype'] == 'enumeration' and (
val not in data['display']['enum_values']: val and val not in data['display']['enum_values']):
return None return None
if not append or not data['is_multiple']: if not append or not data['is_multiple']:
self.conn.execute('DELETE FROM %s WHERE book=?'%lt, (id_,)) self.conn.execute('DELETE FROM %s WHERE book=?'%lt, (id_,))

View File

@ -1639,15 +1639,16 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
return [] return []
return result 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=?', \ self.conn.execute('UPDATE authors SET sort=? WHERE id=?', \
(new_sort.strip(), old_id)) (new_sort.strip(), old_id))
if commit:
self.conn.commit() self.conn.commit()
# Now change all the author_sort fields in books by this author # 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,)) bks = self.conn.get('SELECT book from books_authors_link WHERE author=?', (old_id,))
for (book_id,) in bks: for (book_id,) in bks:
ss = self.author_sort_from_book(book_id, index_is_id=True) 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): def rename_author(self, old_id, new_name):
# Make sure that any commas in new_name are changed to '|'! # Make sure that any commas in new_name are changed to '|'!