Eliminate MultiComplete*

This commit is contained in:
Kovid Goyal 2012-07-08 23:08:54 +05:30
parent 4bed21a52f
commit ae1f768c1a
13 changed files with 458 additions and 86 deletions

View File

@ -0,0 +1,375 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import weakref
from PyQt4.Qt import (QLineEdit, QAbstractListModel, Qt, pyqtSignal, QObject,
QApplication, QCompleter, QListView, QPoint)
from calibre.utils.icu import sort_key, primary_startswith
from calibre.gui2 import NONE
from calibre.gui2.widgets import EnComboBox, LineEditECM
class CompleteModel(QAbstractListModel): # {{{
def __init__(self, parent=None):
QAbstractListModel.__init__(self, parent)
self.items = []
self.sorting = QCompleter.UnsortedModel
self.all_items = self.current_items = ()
self.current_prefix = ''
def set_items(self, items):
items = [unicode(x.strip()) for x in items]
items = [x for x in items if x]
items = tuple(sorted(items, key=sort_key))
self.all_items = self.current_items = items
self.reset()
def set_completion_prefix(self, prefix):
old_prefix = self.current_prefix
self.current_prefix = prefix
if prefix == old_prefix:
return
if not prefix:
self.current_items = self.all_items
self.reset()
return
subset = prefix.startswith(old_prefix)
universe = self.current_items if subset else self.all_items
self.current_items = tuple(x for x in universe if primary_startswith(x,
prefix))
self.reset()
def rowCount(self, *args):
return len(self.current_items)
def data(self, index, role):
if role == Qt.DisplayRole:
try:
return self.current_items[index.row()]
except IndexError:
pass
return NONE
# }}}
class Completer(QListView): # {{{
item_selected = pyqtSignal(object)
relayout_needed = pyqtSignal()
def __init__(self, completer_widget, max_visible_items=7):
QListView.__init__(self)
self.completer_widget = weakref.ref(completer_widget)
self.setWindowFlags(Qt.Popup)
self.max_visible_items = max_visible_items
self.setEditTriggers(self.NoEditTriggers)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setSelectionBehavior(self.SelectRows)
self.setSelectionMode(self.SingleSelection)
self.setAlternatingRowColors(True)
self.setModel(CompleteModel(self))
self.setMouseTracking(True)
self.entered.connect(self.item_entered)
self.activated.connect(self.item_chosen)
self.pressed.connect(self.item_chosen)
self.eat_focus_out = True
self.installEventFilter(self)
def item_chosen(self, index):
if not self.isVisible(): return
self.hide()
text = self.model().data(index, Qt.DisplayRole)
self.item_selected.emit(unicode(text))
def set_items(self, items):
self.model().set_items(items)
if self.isVisible():
self.relayout_needed.emit()
def set_completion_prefix(self, prefix):
self.model().set_completion_prefix(prefix)
if self.isVisible():
self.relayout_needed.emit()
def item_entered(self, idx):
self.setCurrentIndex(idx)
def next_match(self, previous=False):
c = self.currentIndex()
if c.isValid():
r = c.row()
else:
r = 0
r = r + (-1 if previous else 1)
index = self.model().index(r % self.model().rowCount())
self.setCurrentIndex(index)
def popup(self):
p = self
m = p.model()
widget = self.completer_widget()
if widget is None:
return
screen = QApplication.desktop().availableGeometry(widget)
h = (p.sizeHintForRow(0) * min(self.max_visible_items, m.rowCount()) +
3) + 3
hsb = p.horizontalScrollBar()
if hsb and hsb.isVisible():
h += hsb.sizeHint().height()
rh = widget.height()
pos = widget.mapToGlobal(QPoint(0, widget.height() - 2))
w = min(widget.width(), screen.width())
if (pos.x() + w) > (screen.x() + screen.width()):
pos.setX(screen.x() + screen.width() - w)
if pos.x() < screen.x():
pos.setX(screen.x())
top = pos.y() - rh - screen.top() + 2
bottom = screen.bottom() - pos.y()
h = max(h, p.minimumHeight())
if h > bottom:
h = min(max(top, bottom), h)
if top > bottom:
pos.setY(pos.y() - h - rh + 2)
p.setGeometry(pos.x(), pos.y(), w, h)
if (not self.currentIndex().isValid() and self.model().rowCount() > 0):
self.setCurrentIndex(self.model().index(0))
if not p.isVisible():
p.show()
def eventFilter(self, obj, e):
'Redirect key presses from the popup to the widget'
widget = self.completer_widget()
if widget is None:
return False
etype = e.type()
if self.eat_focus_out and widget is obj and etype == e.FocusOut:
if self.isVisible():
return True
if obj is not self:
return QObject.eventFilter(self, obj, e)
if etype == e.KeyPress:
key = e.key()
if key == Qt.Key_Escape:
self.hide()
e.accept()
return True
if key == Qt.Key_F4 and e.modifiers() & Qt.AltModifier:
self.hide()
e.accept()
return True
if key in (Qt.Key_End, Qt.Key_Home, Qt.Key_Up, Qt.Key_Down,
Qt.Key_PageUp, Qt.Key_PageDown, Qt.Key_Enter, Qt.Key_Return):
# Let the list view handle these keys
return False
if key in (Qt.Key_Tab, Qt.Key_Backtab):
self.next_match(previous=key == Qt.Key_Backtab)
e.accept()
return True
# Send to widget
self.eat_focus_out = False
widget.keyPressEvent(e)
self.eat_focus_out = True
if not widget.hasFocus():
# Widget lost focus hide the popup
self.hide()
if e.isAccepted():
return True
elif etype == e.MouseButtonPress:
if not self.underMouse():
self.hide()
e.accept()
return True
return False
# }}}
class LineEdit(QLineEdit, LineEditECM):
'''
A line edit that completes on multiple items separated by a
separator. Use the :meth:`update_items_cache` to set the list of
all possible completions. Separator can be controlled with the
:meth:`set_separator` and :meth:`set_space_before_sep` methods.
A call to self.set_separator(None) will allow this widget to be used
to complete non multiple fields as well.
'''
def __init__(self, parent=None, completer_widget=None):
QLineEdit.__init__(self, parent)
self.sep = ','
self.space_before_sep = False
self.add_separator = True
self.original_cursor_pos = None
completer_widget = (self if completer_widget is None else
completer_widget)
self.mcompleter = Completer(completer_widget)
self.mcompleter.item_selected.connect(self.completion_selected,
type=Qt.QueuedConnection)
self.mcompleter.relayout_needed.connect(self.relayout)
self.mcompleter.setFocusProxy(completer_widget)
completer_widget.installEventFilter(self.mcompleter)
self.textEdited.connect(self.text_edited)
self.no_popup = False
# Interface {{{
def update_items_cache(self, complete_items):
self.all_items = complete_items
def set_separator(self, sep):
self.sep = sep
def set_space_before_sep(self, space_before):
self.space_before_sep = space_before
def set_add_separator(self, what):
self.add_separator = bool(what)
@dynamic_property
def all_items(self):
def fget(self):
return self.mcompleter.model().all_items
def fset(self, items):
self.mcompleter.model().set_items(items)
return property(fget=fget, fset=fset)
# }}}
def complete(self, show_all=False):
if show_all:
self.mcompleter.set_completion_prefix('')
if not self.mcompleter.model().current_items:
self.mcompleter.hide()
return
self.mcompleter.popup()
def relayout(self):
self.mcompleter.popup()
def text_edited(self, *args):
if self.no_popup: return
self.update_completions()
self.complete()
def update_completions(self):
' Update the list of completions '
self.original_cursor_pos = cpos = self.cursorPosition()
text = unicode(self.text())
prefix = text[:cpos]
complete_prefix = prefix.lstrip()
if self.sep:
complete_prefix = prefix.split(self.sep)[-1].lstrip()
self.mcompleter.set_completion_prefix(complete_prefix)
def get_completed_text(self, text):
'Get completed text in before and after parts'
if self.sep is None:
return text, ''
else:
cursor_pos = self.original_cursor_pos
if cursor_pos is None:
cursor_pos = self.cursorPosition()
self.original_cursor_pos = None
# Split text
curtext = unicode(self.text())
before_text = curtext[:cursor_pos]
after_text = curtext[cursor_pos:].rstrip()
# Remove the completion prefix from the before text
before_text = self.sep.join(before_text.split(self.sep)[:-1]).rstrip()
if before_text:
# Add the separator to the end of before_text
if self.space_before_sep:
before_text += ' '
before_text += self.sep + ' '
if self.add_separator or after_text:
# Add separator to the end of completed text
if self.space_before_sep:
text = text.rstrip() + ' '
completed_text = text + self.sep + ' '
else:
completed_text = text
return before_text + completed_text, after_text
def completion_selected(self, text):
before_text, after_text = self.get_completed_text(unicode(text))
self.setText(before_text + after_text)
self.setCursorPosition(len(before_text))
class EditWithComplete(EnComboBox):
def __init__(self, *args):
EnComboBox.__init__(self, *args)
self.setLineEdit(LineEdit(self, completer_widget=self))
self.setCompleter(None)
# Interface {{{
def showPopup(self):
self.lineEdit().complete(show_all=True)
def update_items_cache(self, complete_items):
self.lineEdit().update_items_cache(complete_items)
def set_separator(self, sep):
self.lineEdit().set_separator(sep)
def set_space_before_sep(self, space_before):
self.lineEdit().set_space_before_sep(space_before)
def set_add_separator(self, what):
self.lineEdit().set_add_separator(what)
def show_initial_value(self, what):
what = unicode(what) if what else u''
le = self.lineEdit()
self.setEditText(what)
le.selectAll()
@dynamic_property
def all_items(self):
def fget(self): return self.lineEdit().all_items
def fset(self, val): self.lineEdit().all_items = val
return property(fget=fget, fset=fset)
# }}}
def text(self):
return unicode(self.lineEdit().text())
def setText(self, val):
le = self.lineEdit()
le.no_popup = True
le.setText(val)
le.no_popup = False
def setCursorPosition(self, *args):
self.lineEdit().setCursorPosition(*args)
if __name__ == '__main__':
from PyQt4.Qt import QDialog, QVBoxLayout
app = QApplication([])
d = QDialog()
d.setLayout(QVBoxLayout())
le = EditWithComplete(d)
d.layout().addWidget(le)
items = ['one', 'otwo', 'othree', 'ooone', 'ootwo',
'oothree', 'a1', 'a2',u'Edgas', u'Èdgar', u'Édgaq', u'Edgar', u'Édgar']
le.update_items_cache(items)
le.show_initial_value('')
d.exec_()

View File

@ -190,7 +190,7 @@
</widget>
</item>
<item row="4" column="1">
<widget class="MultiCompleteLineEdit" name="tags">
<widget class="EditWithComplete" name="tags">
<property name="toolTip">
<string>Tags categorize the book. This is particularly useful while searching. &lt;br&gt;&lt;br&gt;They can be any words or phrases, separated by commas.</string>
</property>
@ -213,7 +213,7 @@
</widget>
</item>
<item row="5" column="1">
<widget class="MultiCompleteComboBox" name="series">
<widget class="EditWithComplete" name="series">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>10</horstretch>
@ -248,14 +248,14 @@
</widget>
</item>
<item row="3" column="1">
<widget class="MultiCompleteComboBox" name="publisher">
<widget class="EditWithComplete" name="publisher">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="MultiCompleteComboBox" name="author">
<widget class="EditWithComplete" name="author">
<property name="editable">
<bool>true</bool>
</property>
@ -277,14 +277,9 @@
<header>widgets.h</header>
</customwidget>
<customwidget>
<class>MultiCompleteComboBox</class>
<class>EditWithComplete</class>
<extends>QComboBox</extends>
<header>calibre/gui2/complete.h</header>
</customwidget>
<customwidget>
<class>MultiCompleteLineEdit</class>
<extends>QLineEdit</extends>
<header>calibre/gui2/complete.h</header>
<header>calibre/gui2/complete2.h</header>
</customwidget>
<customwidget>
<class>ImageView</class>

View File

@ -13,7 +13,7 @@ from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateTimeEdit,
QPushButton, QMessageBox, QToolButton
from calibre.utils.date import qt_to_dt, now
from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox
from calibre.gui2.complete2 import EditWithComplete
from calibre.gui2.comments_editor import Editor as CommentsEditor
from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog
from calibre.gui2.dialogs.tag_editor import TagEditor
@ -235,7 +235,7 @@ class MultipleWidget(QWidget):
layout.setSpacing(5)
layout.setContentsMargins(0, 0, 0, 0)
self.tags_box = MultiCompleteLineEdit(parent)
self.tags_box = EditWithComplete(parent)
layout.addWidget(self.tags_box, stretch=1000)
self.editor_button = QToolButton(self)
self.editor_button.setToolTip(_('Open Item Editor'))
@ -293,7 +293,7 @@ class Text(Base):
w.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
w.get_editor_button().clicked.connect(self.edit)
else:
w = MultiCompleteComboBox(parent)
w = EditWithComplete(parent)
w.set_separator(None)
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
w.setMinimumContentsLength(25)
@ -363,7 +363,7 @@ class Text(Base):
class Series(Base):
def setup_ui(self, parent):
w = MultiCompleteComboBox(parent)
w = EditWithComplete(parent)
w.set_separator(None)
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
w.setMinimumContentsLength(25)
@ -807,7 +807,7 @@ class BulkDateTime(BulkBase):
class BulkSeries(BulkBase):
def setup_ui(self, parent):
self.make_widgets(parent, MultiCompleteComboBox)
self.make_widgets(parent, EditWithComplete)
values = self.all_values = list(self.db.all_custom(num=self.col_id))
values.sort(key=sort_key)
self.main_widget.setSizeAdjustPolicy(self.main_widget.AdjustToMinimumContentsLengthWithIcon)
@ -934,7 +934,7 @@ class RemoveTags(QWidget):
layout.setSpacing(5)
layout.setContentsMargins(0, 0, 0, 0)
self.tags_box = MultiCompleteLineEdit(parent)
self.tags_box = EditWithComplete(parent)
self.tags_box.update_items_cache(values)
layout.addWidget(self.tags_box, stretch=3)
self.checkbox = QCheckBox(_('Remove all tags'), parent)
@ -956,7 +956,7 @@ class BulkText(BulkBase):
values = self.all_values = list(self.db.all_custom(num=self.col_id))
values.sort(key=sort_key)
if self.col_metadata['is_multiple']:
self.make_widgets(parent, MultiCompleteLineEdit,
self.make_widgets(parent, EditWithComplete,
extra_label_text=_('tags to add'))
self.main_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
self.adding_widget = self.main_widget
@ -976,7 +976,7 @@ class BulkText(BulkBase):
self.main_widget.set_add_separator(
tweaks['authors_completer_append_separator'])
else:
self.make_widgets(parent, MultiCompleteComboBox)
self.make_widgets(parent, EditWithComplete)
self.main_widget.set_separator(None)
self.main_widget.setSizeAdjustPolicy(
self.main_widget.AdjustToMinimumContentsLengthWithIcon)

View File

@ -7,7 +7,7 @@ __license__ = 'GPL v3'
from PyQt4.Qt import QDialog, QGridLayout, QLabel, QDialogButtonBox, \
QApplication, QSpinBox, QToolButton, QIcon
from calibre.ebooks.metadata import string_to_authors
from calibre.gui2.complete import MultiCompleteComboBox
from calibre.gui2.complete2 import EditWithComplete
from calibre.utils.config import tweaks
class AddEmptyBookDialog(QDialog):
@ -32,7 +32,7 @@ class AddEmptyBookDialog(QDialog):
self.author_label = QLabel(_('Set the author of the new books to:'))
self._layout.addWidget(self.author_label, 2, 0, 1, 2)
self.authors_combo = MultiCompleteComboBox(self)
self.authors_combo = EditWithComplete(self)
self.authors_combo.setSizeAdjustPolicy(
self.authors_combo.AdjustToMinimumContentsLengthWithIcon)
self.authors_combo.setEditable(True)

View File

@ -76,7 +76,7 @@
</widget>
</item>
<item row="0" column="1">
<widget class="MultiCompleteComboBox" name="authors">
<widget class="EditWithComplete" name="authors">
<property name="editable">
<bool>true</bool>
</property>
@ -175,7 +175,7 @@
</widget>
</item>
<item row="4" column="1">
<widget class="MultiCompleteComboBox" name="publisher">
<widget class="EditWithComplete" name="publisher">
<property name="editable">
<bool>true</bool>
</property>
@ -195,7 +195,7 @@
</widget>
</item>
<item row="5" column="1">
<widget class="MultiCompleteLineEdit" name="tags">
<widget class="EditWithComplete" name="tags">
<property name="toolTip">
<string>Tags categorize the book. This is particularly useful while searching. &lt;br&gt;&lt;br&gt;They can be any words or phrases, separated by commas.</string>
</property>
@ -229,7 +229,7 @@
</widget>
</item>
<item row="6" column="1">
<widget class="MultiCompleteLineEdit" name="remove_tags">
<widget class="EditWithComplete" name="remove_tags">
<property name="toolTip">
<string>Comma separated list of tags to remove from the books. </string>
</property>
@ -262,7 +262,7 @@
</widget>
</item>
<item row="7" column="1">
<widget class="MultiCompleteComboBox" name="series">
<widget class="EditWithComplete" name="series">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -1181,14 +1181,9 @@ not multiple and the destination field is multiple</string>
<header>widgets.h</header>
</customwidget>
<customwidget>
<class>MultiCompleteComboBox</class>
<class>EditWithComplete</class>
<extends>QComboBox</extends>
<header>calibre/gui2/complete.h</header>
</customwidget>
<customwidget>
<class>MultiCompleteLineEdit</class>
<extends>QLineEdit</extends>
<header>calibre/gui2/complete.h</header>
<header>calibre/gui2/complete2.h</header>
</customwidget>
<customwidget>
<class>HistoryLineEdit</class>

View File

@ -237,21 +237,21 @@
</widget>
</item>
<item row="2" column="1">
<widget class="MultiCompleteComboBox" name="authors_box">
<widget class="EditWithComplete" name="authors_box">
<property name="toolTip">
<string>Enter an author's name. Only one author can be used.</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="MultiCompleteComboBox" name="series_box">
<widget class="EditWithComplete" name="series_box">
<property name="toolTip">
<string>Enter a series name, without an index. Only one series name can be used.</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="MultiCompleteLineEdit" name="tags_box">
<widget class="EditWithComplete" name="tags_box">
<property name="toolTip">
<string>Enter tags separated by spaces</string>
</property>
@ -327,14 +327,9 @@
<header>widgets.h</header>
</customwidget>
<customwidget>
<class>MultiCompleteLineEdit</class>
<extends>QLineEdit</extends>
<header>calibre/gui2/complete.h</header>
</customwidget>
<customwidget>
<class>MultiCompleteComboBox</class>
<class>EditWithComplete</class>
<extends>QComboBox</extends>
<header>calibre/gui2/complete.h</header>
<header>calibre/gui2/complete2.h</header>
</customwidget>
</customwidgets>
<tabstops>

View File

@ -7,14 +7,14 @@ __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from calibre.gui2.complete import MultiCompleteComboBox
from calibre.gui2.complete2 import EditWithComplete
from calibre.utils.localization import lang_map
from calibre.utils.icu import sort_key, lower
class LanguagesEdit(MultiCompleteComboBox):
class LanguagesEdit(EditWithComplete):
def __init__(self, parent=None, db=None):
MultiCompleteComboBox.__init__(self, parent)
EditWithComplete.__init__(self, parent)
self.setSizeAdjustPolicy(self.AdjustToMinimumContentsLengthWithIcon)
self.setMinimumContentsLength(20)

View File

@ -14,7 +14,7 @@ from PyQt4.Qt import (Qt, QApplication, QStyle, QIcon, QDoubleSpinBox,
from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog, rating_font
from calibre.constants import iswindows
from calibre.gui2.widgets import EnLineEdit
from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox
from calibre.gui2.complete2 import EditWithComplete
from calibre.utils.date import now, format_date, qt_to_dt
from calibre.utils.config import tweaks
from calibre.utils.formatter import validation_formatter
@ -121,7 +121,7 @@ class TextDelegate(QStyledItemDelegate): # {{{
def createEditor(self, parent, option, index):
if self.auto_complete_function:
editor = MultiCompleteComboBox(parent)
editor = EditWithComplete(parent)
editor.set_separator(None)
complete_items = [i[1] for i in self.auto_complete_function()]
editor.update_items_cache(complete_items)
@ -132,7 +132,7 @@ class TextDelegate(QStyledItemDelegate): # {{{
return editor
def setModelData(self, editor, model, index):
if isinstance(editor, MultiCompleteComboBox):
if isinstance(editor, EditWithComplete):
val = editor.lineEdit().text()
model.setData(index, QVariant(val), Qt.EditRole)
else:
@ -153,7 +153,7 @@ class CompleteDelegate(QStyledItemDelegate): # {{{
def createEditor(self, parent, option, index):
if self.db and hasattr(self.db, self.items_func_name):
col = index.model().column_map[index.column()]
editor = MultiCompleteComboBox(parent)
editor = EditWithComplete(parent)
editor.set_separator(self.sep)
editor.set_space_before_sep(self.space_before_sep)
if self.sep == '&':
@ -171,7 +171,7 @@ class CompleteDelegate(QStyledItemDelegate): # {{{
return editor
def setModelData(self, editor, model, index):
if isinstance(editor, MultiCompleteComboBox):
if isinstance(editor, EditWithComplete):
val = editor.lineEdit().text()
model.setData(index, QVariant(val), Qt.EditRole)
else:
@ -244,7 +244,7 @@ class CcTextDelegate(QStyledItemDelegate): # {{{
def createEditor(self, parent, option, index):
m = index.model()
col = m.column_map[index.column()]
editor = MultiCompleteLineEdit(parent)
editor = EditWithComplete(parent)
editor.set_separator(None)
complete_items = sorted(list(m.db.all_custom(label=m.db.field_metadata.key_to_label(col))),
key=sort_key)

View File

@ -15,7 +15,6 @@ from PyQt4.Qt import (Qt, QDateTimeEdit, pyqtSignal, QMessageBox,
QPushButton, QSpinBox, QLineEdit, QSizePolicy, QDialogButtonBox, QAction)
from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView
from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox
from calibre.utils.icu import sort_key
from calibre.utils.config import tweaks, prefs
from calibre.ebooks.metadata import (title_sort, authors_to_string,
@ -23,6 +22,7 @@ from calibre.ebooks.metadata import (title_sort, authors_to_string,
from calibre.ebooks.metadata.meta import get_metadata
from calibre.gui2 import (file_icon_provider, UNDEFINED_QDATETIME,
choose_files, error_dialog, choose_images)
from calibre.gui2.complete2 import EditWithComplete
from calibre.utils.date import (local_tz, qt_to_dt, as_local_time,
UNDEFINED_DATE)
from calibre import strftime
@ -204,7 +204,7 @@ class TitleSortEdit(TitleEdit):
# }}}
# Authors {{{
class AuthorsEdit(MultiCompleteComboBox):
class AuthorsEdit(EditWithComplete):
TOOLTIP = ''
LABEL = _('&Author(s):')
@ -212,7 +212,7 @@ class AuthorsEdit(MultiCompleteComboBox):
def __init__(self, parent, manage_authors):
self.dialog = parent
self.books_to_refresh = set([])
MultiCompleteComboBox.__init__(self, parent)
EditWithComplete.__init__(self, parent)
self.setToolTip(self.TOOLTIP)
self.setWhatsThis(self.TOOLTIP)
self.setEditable(True)
@ -443,13 +443,13 @@ class AuthorSortEdit(EnLineEdit):
# }}}
# Series {{{
class SeriesEdit(MultiCompleteComboBox):
class SeriesEdit(EditWithComplete):
TOOLTIP = _('List of known series. You can add new series.')
LABEL = _('&Series:')
def __init__(self, parent):
MultiCompleteComboBox.__init__(self, parent)
EditWithComplete.__init__(self, parent)
self.set_separator(None)
self.dialog = parent
self.setSizeAdjustPolicy(
@ -1086,14 +1086,14 @@ class RatingEdit(QSpinBox): # {{{
# }}}
class TagsEdit(MultiCompleteLineEdit): # {{{
class TagsEdit(EditWithComplete): # {{{
LABEL = _('Ta&gs:')
TOOLTIP = '<p>'+_('Tags categorize the book. This is particularly '
'useful while searching. <br><br>They can be any words '
'or phrases, separated by commas.')
def __init__(self, parent):
MultiCompleteLineEdit.__init__(self, parent)
EditWithComplete.__init__(self, parent)
self.books_to_refresh = set([])
self.setToolTip(self.TOOLTIP)
self.setWhatsThis(self.TOOLTIP)
@ -1327,11 +1327,11 @@ class ISBNDialog(QDialog) : # {{{
# }}}
class PublisherEdit(MultiCompleteComboBox): # {{{
class PublisherEdit(EditWithComplete): # {{{
LABEL = _('&Publisher:')
def __init__(self, parent):
MultiCompleteComboBox.__init__(self, parent)
EditWithComplete.__init__(self, parent)
self.set_separator(None)
self.setSizeAdjustPolicy(
self.AdjustToMinimumContentsLengthWithIcon)

View File

@ -13,6 +13,7 @@ from PyQt4.Qt import (QWidget, pyqtSignal, QCheckBox, QAbstractSpinBox,
from calibre.customize.ui import preferences_plugins
from calibre.utils.config import ConfigProxy
from calibre.gui2.complete2 import EditWithComplete
class AbortCommit(Exception):
pass
@ -133,11 +134,15 @@ class Setting(object):
def initialize(self):
self.gui_obj.blockSignals(True)
if self.datatype == 'choice':
self.gui_obj.clear()
for x in self.choices:
if isinstance(x, basestring):
x = (x, x)
self.gui_obj.addItem(x[0], QVariant(x[1]))
choices = self.choices or []
if isinstance(self.gui_obj, EditWithComplete):
self.gui_obj.all_items = choices
else:
self.gui_obj.clear()
for x in choices:
if isinstance(x, basestring):
x = (x, x)
self.gui_obj.addItem(x[0], QVariant(x[1]))
self.set_gui_val(self.get_config_val(default=False))
self.gui_obj.blockSignals(False)
self.initial_value = self.get_gui_val()
@ -171,11 +176,14 @@ class Setting(object):
elif self.datatype == 'string':
self.gui_obj.setText(val if val else '')
elif self.datatype == 'choice':
idx = self.gui_obj.findData(QVariant(val), role=Qt.UserRole,
flags=self.CHOICES_SEARCH_FLAGS)
if idx == -1:
idx = 0
self.gui_obj.setCurrentIndex(idx)
if isinstance(self.gui_obj, EditWithComplete):
self.gui_obj.setText(val)
else:
idx = self.gui_obj.findData(QVariant(val), role=Qt.UserRole,
flags=self.CHOICES_SEARCH_FLAGS)
if idx == -1:
idx = 0
self.gui_obj.setCurrentIndex(idx)
def get_gui_val(self):
if self.datatype == 'bool':
@ -187,9 +195,12 @@ class Setting(object):
if self.empty_string_is_None and not val:
val = None
elif self.datatype == 'choice':
idx = self.gui_obj.currentIndex()
if idx < 0: idx = 0
val = unicode(self.gui_obj.itemData(idx).toString())
if isinstance(self.gui_obj, EditWithComplete):
val = unicode(self.gui_obj.text())
else:
idx = self.gui_obj.currentIndex()
if idx < 0: idx = 0
val = unicode(self.gui_obj.itemData(idx).toString())
return val
class CommaSeparatedList(Setting):

View File

@ -320,7 +320,7 @@ Manage Authors. You can use the values {author} and
</attribute>
<layout class="QGridLayout" name="gridLayout_10">
<item row="3" column="2" colspan="3">
<widget class="MultiCompleteLineEdit" name="opt_categories_using_hierarchy">
<widget class="EditWithComplete" name="opt_categories_using_hierarchy">
<property name="toolTip">
<string>A comma-separated list of categories in which items containing
periods are displayed in the tag browser trees. For example, if
@ -397,7 +397,7 @@ up into subcategories. If the partition method is set to disable, this value is
</widget>
</item>
<item row="1" column="3" colspan="2">
<widget class="MultiCompleteLineEdit" name="opt_tag_browser_dont_collapse">
<widget class="EditWithComplete" name="opt_tag_browser_dont_collapse">
<property name="toolTip">
<string>A comma-separated list of categories that are not to
be partitioned even if the number of items is larger than
@ -506,9 +506,9 @@ a few top-level elements.</string>
</widget>
<customwidgets>
<customwidget>
<class>MultiCompleteLineEdit</class>
<extends>QLineEdit</extends>
<header>calibre/gui2/complete.h</header>
<class>EditWithComplete</class>
<extends>QComboBox</extends>
<header>calibre/gui2/complete2.h</header>
</customwidget>
</customwidgets>
<resources>

View File

@ -98,7 +98,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
db.prefs.set('grouped_search_make_user_categories', [])
r('grouped_search_make_user_categories', db.prefs, setting=CommaSeparatedList)
self.muc_changed = False
self.opt_grouped_search_make_user_categories.editingFinished.connect(
self.opt_grouped_search_make_user_categories.lineEdit().editingFinished.connect(
self.muc_box_changed)
def set_similar_fields(self, initial=False):
@ -184,6 +184,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.opt_grouped_search_make_user_categories.update_items_cache(terms)
self.gst_names.blockSignals(True)
self.gst_names.clear()
print (1111, self.gst_names)
self.gst_names.addItem('', '')
for t in terms:
self.gst_names.addItem(t, t)

View File

@ -69,7 +69,7 @@
</widget>
</item>
<item row="2" column="1">
<widget class="MultiCompleteLineEdit" name="opt_limit_search_columns_to"/>
<widget class="EditWithComplete" name="opt_limit_search_columns_to"/>
</item>
<item row="5" column="0" colspan="2">
<widget class="QLabel" name="label_3">
@ -134,7 +134,7 @@ a search term by changing the value box then pressing Save.</string>
</widget>
</item>
<item>
<widget class="MultiCompleteLineEdit" name="gst_value"/>
<widget class="EditWithComplete" name="gst_value"/>
</item>
<item>
<widget class="QToolButton" name="gst_save_button">
@ -173,7 +173,7 @@ of a search term by changing the value box then pressing Save.</string>
</widget>
</item>
<item>
<widget class="MultiCompleteLineEdit" name="opt_grouped_search_make_user_categories">
<widget class="EditWithComplete" name="opt_grouped_search_make_user_categories">
<property name="toolTip">
<string>Enter the names of any grouped search terms you wish
to be shown as user categories</string>
@ -301,9 +301,9 @@ to be shown as user categories</string>
</widget>
<customwidgets>
<customwidget>
<class>MultiCompleteLineEdit</class>
<extends>QLineEdit</extends>
<header>calibre/gui2/complete.h</header>
<class>EditWithComplete</class>
<extends>QComboBox</extends>
<header>calibre/gui2/complete2.h</header>
</customwidget>
</customwidgets>
<resources>