From c8b5db52098f5a417ecf1f58343db1ef1d3c1668 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Jul 2012 14:12:28 +0530 Subject: [PATCH] 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 --- src/calibre/gui2/complete.py | 43 ++++++++-------------- src/calibre/gui2/convert/metadata.py | 28 +++----------- src/calibre/gui2/custom_column_widgets.py | 30 ++------------- src/calibre/gui2/dialogs/add_empty_book.py | 12 +----- src/calibre/gui2/dialogs/metadata_bulk.py | 19 ++-------- src/calibre/gui2/dialogs/search.py | 9 +---- src/calibre/gui2/languages.py | 2 - src/calibre/gui2/library/delegates.py | 4 -- src/calibre/gui2/metadata/basic_widgets.py | 43 ++++++---------------- 9 files changed, 41 insertions(+), 149 deletions(-) diff --git a/src/calibre/gui2/complete.py b/src/calibre/gui2/complete.py index fb1f39dfa3..9d78003231 100644 --- a/src/calibre/gui2/complete.py +++ b/src/calibre/gui2/complete.py @@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en' 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 @@ class MultiCompleteLineEdit(QLineEdit, LineEditECM): 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 @@ class MultiCompleteLineEdit(QLineEdit, LineEditECM): 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 @@ class MultiCompleteComboBox(EnComboBox): 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 @@ if __name__ == '__main__': 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_() diff --git a/src/calibre/gui2/convert/metadata.py b/src/calibre/gui2/convert/metadata.py index ba2fa0713e..3643e5548e 100644 --- a/src/calibre/gui2/convert/metadata.py +++ b/src/calibre/gui2/convert/metadata.py @@ -12,8 +12,8 @@ from PyQt4.Qt import QPixmap, SIGNAL 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 @@ class MetadataWidget(Widget, Ui_Form): 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 @@ class MetadataWidget(Widget, Ui_Form): 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 @@ class MetadataWidget(Widget, Ui_Form): 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 @@ class MetadataWidget(Widget, Ui_Form): if tags: mi.tags = tags + print (mi) return mi def select_cover(self): diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 654a9f4b5b..c9c8255076 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -314,14 +314,7 @@ class Text(Base): 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 @@ class Series(Base): 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 @@ class BulkSeries(BulkBase): 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 @@ class BulkText(BulkBase): 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): diff --git a/src/calibre/gui2/dialogs/add_empty_book.py b/src/calibre/gui2/dialogs/add_empty_book.py index d4990e14d4..218bd90483 100644 --- a/src/calibre/gui2/dialogs/add_empty_book.py +++ b/src/calibre/gui2/dialogs/add_empty_book.py @@ -6,8 +6,7 @@ __license__ = 'GPL v3' 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 @@ class AddEmptyBookDialog(QDialog): 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) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 09a244debd..b8f30f3541 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -876,38 +876,25 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): 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) diff --git a/src/calibre/gui2/dialogs/search.py b/src/calibre/gui2/dialogs/search.py index 8736ae2259..cf63d150e6 100644 --- a/src/calibre/gui2/dialogs/search.py +++ b/src/calibre/gui2/dialogs/search.py @@ -25,10 +25,6 @@ class SearchDialog(QDialog, Ui_Dialog): 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 @@ class SearchDialog(QDialog, Ui_Dialog): 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) diff --git a/src/calibre/gui2/languages.py b/src/calibre/gui2/languages.py index 0dfbb38b08..f067027097 100644 --- a/src/calibre/gui2/languages.py +++ b/src/calibre/gui2/languages.py @@ -32,8 +32,6 @@ class LanguagesEdit(MultiCompleteComboBox): 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): diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 60b8e3445d..77c3152842 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -125,8 +125,6 @@ class TextDelegate(QStyledItemDelegate): # {{{ 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 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ 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: diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index 250d4ffad2..d2a983415f 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -246,14 +246,6 @@ class AuthorsEdit(MultiCompleteComboBox): 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 @@ class AuthorsEdit(MultiCompleteComboBox): 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 @@ class SeriesEdit(MultiCompleteComboBox): 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 @@ class PublisherEdit(MultiCompleteComboBox): # {{{ 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,