mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Eliminate MultiComplete*
This commit is contained in:
parent
4bed21a52f
commit
ae1f768c1a
375
src/calibre/gui2/complete2.py
Normal file
375
src/calibre/gui2/complete2.py
Normal 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_()
|
@ -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. <br><br>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>
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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. <br><br>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>
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user