Fix (I hope) crashes in MultiCompleteComboBox. Also the drop down arrow now only shows the items that start with whatever text is currently entered in the box

This commit is contained in:
Kovid Goyal 2012-07-02 14:12:28 +05:30
parent e6788b5814
commit c8b5db5209
9 changed files with 41 additions and 149 deletions

View file

@ -7,7 +7,7 @@
from PyQt4.Qt import (QLineEdit, QAbstractListModel, Qt,
QApplication, QCompleter, pyqtSignal)
QApplication, QCompleter)
from calibre.utils.icu import sort_key, lower
from calibre.gui2 import NONE
@ -56,7 +56,7 @@ class MultiCompleteLineEdit(QLineEdit, LineEditECM):
to complete non multiple fields as well.
'''
def __init__(self, parent=None):
def __init__(self, parent=None, completer_widget=None):
QLineEdit.__init__(self, parent)
self.sep = ','
@ -66,7 +66,7 @@ def __init__(self, parent=None):
self._model = CompleteModel(parent=self)
self._completer = c = QCompleter(self._model, self)
c.setWidget(self)
c.setWidget(self if completer_widget is None else completer_widget)
c.setCompletionMode(QCompleter.PopupCompletion)
c.setCaseSensitivity(Qt.CaseInsensitive)
c.setModelSorting(self._model.sorting)
@ -158,21 +158,13 @@ def fset(self, items):
class MultiCompleteComboBox(EnComboBox):
clear_edit_text = pyqtSignal()
def __init__(self, *args):
EnComboBox.__init__(self, *args)
self.setLineEdit(MultiCompleteLineEdit(self))
# Needed to allow changing the case of an existing item
# otherwise on focus out, the text is changed to the
# item that matches case insensitively
c = self.lineEdit().completer()
c.setCaseSensitivity(Qt.CaseSensitive)
self.dummy_model = CompleteModel(self)
c.setModel(self.dummy_model)
self.lineEdit()._completer.setWidget(self)
self.clear_edit_text.connect(self.clearEditText,
type=Qt.QueuedConnection)
self.le = MultiCompleteLineEdit(self, completer_widget=self)
self.setLineEdit(self.le)
def showPopup(self):
self.le._completer.complete()
def update_items_cache(self, complete_items):
self.lineEdit().update_items_cache(complete_items)
@ -187,18 +179,10 @@ def set_add_separator(self, what):
self.lineEdit().set_add_separator(what)
def show_initial_value(self, what):
'''
Show an initial value. Handle the case of the initial value being blank
correctly (on Qt 4.8.0 having a blank value causes the first value from
the completer to be shown, when the event loop runs).
'''
what = unicode(what)
what = unicode(what) if what else u''
le = self.lineEdit()
if not what.strip():
self.clear_edit_text.emit()
else:
self.setEditText(what)
le.selectAll()
self.setEditText(what)
le.selectAll()
if __name__ == '__main__':
from PyQt4.Qt import QDialog, QVBoxLayout
@ -207,5 +191,8 @@ def show_initial_value(self, what):
d.setLayout(QVBoxLayout())
le = MultiCompleteComboBox(d)
d.layout().addWidget(le)
le.all_items = ['one', 'otwo', 'othree', 'ooone', 'ootwo', 'oothree']
items = ['one', 'otwo', 'othree', 'ooone', 'ootwo',
'oothree']
le.update_items_cache(items)
le.show_initial_value('')
d.exec_()

View file

@ -12,8 +12,8 @@
from calibre.gui2 import choose_images, error_dialog
from calibre.gui2.convert.metadata_ui import Ui_Form
from calibre.ebooks.metadata import (authors_to_string, string_to_authors,
MetaInformation, title_sort)
from calibre.ebooks.metadata import (string_to_authors, MetaInformation,
title_sort)
from calibre.ebooks.metadata.opf2 import metadata_to_opf
from calibre.ptempfile import PersistentTemporaryFile
from calibre.gui2.convert import Widget
@ -74,14 +74,12 @@ def initialize_metadata_options(self):
mi = self.db.get_metadata(self.book_id, index_is_id=True)
self.title.setText(mi.title)
if mi.publisher:
self.publisher.setCurrentIndex(self.publisher.findText(mi.publisher))
self.publisher.show_initial_value(mi.publisher if mi.publisher else '')
self.author_sort.setText(mi.author_sort if mi.author_sort else '')
self.tags.setText(', '.join(mi.tags if mi.tags else []))
self.tags.update_items_cache(self.db.all_tags())
self.comment.html = comments_to_html(mi.comments) if mi.comments else ''
if mi.series:
self.series.setCurrentIndex(self.series.findText(mi.series))
self.series.show_initial_value(mi.series if mi.series else '')
if mi.series_index is not None:
try:
self.series_index.setValue(mi.series_index)
@ -118,16 +116,11 @@ def initalize_authors(self):
self.author.set_add_separator(tweaks['authors_completer_append_separator'])
self.author.update_items_cache(self.db.all_author_names())
for i in all_authors:
id, name = i
name = authors_to_string([name.strip().replace('|', ',') for n in name.split(',')])
self.author.addItem(name)
au = self.db.authors(self.book_id, True)
if not au:
au = _('Unknown')
au = ' & '.join([a.strip().replace('|', ',') for a in au.split(',')])
self.author.setEditText(au)
self.author.show_initial_value(au)
def initialize_series(self):
all_series = self.db.all_series()
@ -135,22 +128,12 @@ def initialize_series(self):
self.series.set_separator(None)
self.series.update_items_cache([x[1] for x in all_series])
for i in all_series:
id, name = i
self.series.addItem(name)
self.series.setCurrentIndex(-1)
def initialize_publisher(self):
all_publishers = self.db.all_publishers()
all_publishers.sort(key=lambda x : sort_key(x[1]))
self.publisher.set_separator(None)
self.publisher.update_items_cache([x[1] for x in all_publishers])
for i in all_publishers:
id, name = i
self.publisher.addItem(name)
self.publisher.setCurrentIndex(-1)
def get_title_and_authors(self):
title = unicode(self.title.text()).strip()
if not title:
@ -179,6 +162,7 @@ def get_metadata(self):
if tags:
mi.tags = tags
print (mi)
return mi
def select_cover(self):

View file

@ -314,14 +314,7 @@ def initialize(self, book_id):
if self.col_metadata['is_multiple']:
self.setter(val)
else:
idx = None
for i, c in enumerate(values):
if c == val:
idx = i
self.widgets[1].addItem(c)
self.widgets[1].setEditText('')
if idx is not None:
self.widgets[1].setCurrentIndex(idx)
self.widgets[1].show_initial_value(val)
def setter(self, val):
if self.col_metadata['is_multiple']:
@ -396,16 +389,8 @@ def initialize(self, book_id):
self.initial_index = s_index
self.initial_val = val
val = self.normalize_db_val(val)
idx = None
self.name_widget.clear()
for i, c in enumerate(values):
if c == val:
idx = i
self.name_widget.addItem(c)
self.name_widget.update_items_cache(values)
self.name_widget.setEditText('')
if idx is not None:
self.widgets[1].setCurrentIndex(idx)
self.name_widget.show_initial_value(val)
def getter(self):
n = unicode(self.name_widget.currentText()).strip()
@ -860,8 +845,6 @@ def initialize(self, book_id):
self.idx_widget.setChecked(False)
self.main_widget.set_separator(None)
self.main_widget.update_items_cache(self.all_values)
for c in self.all_values:
self.main_widget.addItem(c)
self.main_widget.setEditText('')
self.a_c_checkbox.setChecked(False)
@ -1005,15 +988,8 @@ def initialize(self, book_ids):
if not self.col_metadata['is_multiple']:
val = self.get_initial_value(book_ids)
self.initial_val = val = self.normalize_db_val(val)
idx = None
self.main_widget.blockSignals(True)
for i, c in enumerate(self.all_values):
if c == val:
idx = i
self.main_widget.addItem(c)
self.main_widget.setEditText('')
if idx is not None:
self.main_widget.setCurrentIndex(idx)
self.main_widget.show_initial_value(val)
self.main_widget.blockSignals(False)
def commit(self, book_ids, notify=False):

View file

@ -6,8 +6,7 @@
from PyQt4.Qt import QDialog, QGridLayout, QLabel, QDialogButtonBox, \
QApplication, QSpinBox, QToolButton, QIcon
from calibre.ebooks.metadata import authors_to_string, string_to_authors
from calibre.utils.icu import sort_key
from calibre.ebooks.metadata import string_to_authors
from calibre.gui2.complete import MultiCompleteComboBox
from calibre.utils.config import tweaks
@ -56,17 +55,10 @@ def reset_author(self, *args):
self.authors_combo.setEditText(_('Unknown'))
def initialize_authors(self, db, author):
all_authors = db.all_authors()
all_authors.sort(key=lambda x : sort_key(x[1]))
for i in all_authors:
id, name = i
name = [name.strip().replace('|', ',') for n in name.split(',')]
self.authors_combo.addItem(authors_to_string(name))
au = author
if not au:
au = _('Unknown')
self.authors_combo.setEditText(au.replace('|', ','))
self.authors_combo.show_initial_value(au.replace('|', ','))
self.authors_combo.set_separator('&')
self.authors_combo.set_space_before_sep(True)

View file

@ -876,38 +876,25 @@ def initalize_authors(self):
all_authors = self.db.all_authors()
all_authors.sort(key=lambda x : sort_key(x[1]))
for i in all_authors:
id, name = i
name = name.strip().replace('|', ',')
self.authors.addItem(name)
self.authors.setEditText('')
self.authors.set_separator('&')
self.authors.set_space_before_sep(True)
self.authors.set_add_separator(tweaks['authors_completer_append_separator'])
self.authors.update_items_cache(self.db.all_author_names())
self.authors.show_initial_value('')
def initialize_series(self):
all_series = self.db.all_series()
all_series.sort(key=lambda x : sort_key(x[1]))
self.series.set_separator(None)
self.series.update_items_cache([x[1] for x in all_series])
for i in all_series:
id, name = i
self.series.addItem(name)
self.series.setEditText('')
self.series.show_initial_value('')
def initialize_publisher(self):
all_publishers = self.db.all_publishers()
all_publishers.sort(key=lambda x : sort_key(x[1]))
self.publisher.set_separator(None)
self.publisher.update_items_cache([x[1] for x in all_publishers])
for i in all_publishers:
id, name = i
self.publisher.addItem(name)
self.publisher.setEditText('')
self.publisher.show_initial_value('')
def tag_editor(self, *args):
d = TagEditor(self, self.db, None)

View file

@ -25,10 +25,6 @@ def __init__(self, parent, db):
all_authors = db.all_authors()
all_authors.sort(key=lambda x : sort_key(x[1]))
for i in all_authors:
id, name = i
name = name.strip().replace('|', ',')
self.authors_box.addItem(name)
self.authors_box.setEditText('')
self.authors_box.set_separator('&')
self.authors_box.set_space_before_sep(True)
@ -39,10 +35,7 @@ def __init__(self, parent, db):
all_series.sort(key=lambda x : sort_key(x[1]))
self.series_box.set_separator(None)
self.series_box.update_items_cache([x[1] for x in all_series])
for i in all_series:
id, name = i
self.series_box.addItem(name)
self.series_box.setEditText('')
self.series_box.show_initial_value('')
all_tags = db.all_tags()
self.tags_box.update_items_cache(all_tags)

View file

@ -32,8 +32,6 @@ def init_langs(self, db):
all_items = sorted(self._lang_map.itervalues(),
key=lambda x: (-pmap.get(x, 0), sort_key(x)))
self.update_items_cache(all_items)
for item in all_items:
self.addItem(item)
@property
def vals(self):

View file

@ -125,8 +125,6 @@ def createEditor(self, parent, option, index):
editor.set_separator(None)
complete_items = [i[1] for i in self.auto_complete_function()]
editor.update_items_cache(complete_items)
for item in sorted(complete_items, key=sort_key):
editor.addItem(item)
ct = index.data(Qt.DisplayRole).toString()
editor.show_initial_value(ct)
else:
@ -166,8 +164,6 @@ def createEditor(self, parent, option, index):
all_items = list(self.db.all_custom(
label=self.db.field_metadata.key_to_label(col)))
editor.update_items_cache(all_items)
for item in sorted(all_items, key=sort_key):
editor.addItem(item)
ct = index.data(Qt.DisplayRole).toString()
editor.show_initial_value(ct)
else:

View file

@ -246,14 +246,6 @@ def get_default(self):
def initialize(self, db, id_):
self.books_to_refresh = set([])
all_authors = db.all_authors()
all_authors.sort(key=lambda x : sort_key(x[1]))
self.clear()
for i in all_authors:
id, name = i
name = name.strip().replace('|', ',')
self.addItem(name)
self.set_separator('&')
self.set_space_before_sep(True)
self.set_add_separator(tweaks['authors_completer_append_separator'])
@ -299,7 +291,6 @@ def fset(self, val):
self.setEditText(' & '.join([x.strip() for x in val]))
self.lineEdit().setCursorPosition(0)
return property(fget=fget, fset=fset)
def break_cycles(self):
@ -488,19 +479,12 @@ def initialize(self, db, id_):
all_series.sort(key=lambda x : sort_key(x[1]))
self.update_items_cache([x[1] for x in all_series])
series_id = db.series_id(id_, index_is_id=True)
idx, c = None, 0
self.clear()
inval = ''
for i in all_series:
id, name = i
if id == series_id:
idx = c
self.addItem(name)
c += 1
self.lineEdit().setText('')
if idx is not None:
self.setCurrentIndex(idx)
self.original_val = self.current_val
if i[0] == series_id:
inval = i[1]
break
self.original_val = self.current_val = inval
def commit(self, db, id_):
series = self.current_val
@ -1373,17 +1357,12 @@ def initialize(self, db, id_):
all_publishers.sort(key=lambda x : sort_key(x[1]))
self.update_items_cache([x[1] for x in all_publishers])
publisher_id = db.publisher_id(id_, index_is_id=True)
idx = None
self.clear()
for i, x in enumerate(all_publishers):
id_, name = x
if id_ == publisher_id:
idx = i
self.addItem(name)
self.setEditText('')
if idx is not None:
self.setCurrentIndex(idx)
inval = ''
for pid, name in all_publishers:
if pid == publisher_id:
inval = name
break
self.original_val = self.current_val = inval
def commit(self, db, id_):
self.books_to_refresh |= db.set_publisher(id_, self.current_val,