When the current completion begins with the current input, append and select it in the lineedit to better put it in evidence

This commit is contained in:
Jean-Francois Dockes 2019-10-10 09:39:30 +02:00
parent 5210088e8f
commit 44a529513f
2 changed files with 91 additions and 10 deletions

View File

@ -151,6 +151,7 @@ void RclCompleterModel::onPartialWord(
}
}
endResetModel();
QTimer::singleShot(0, m_parent, SLOT(onCompleterShown()));
}
void SSearch::init()
@ -172,16 +173,18 @@ void SSearch::init()
SLOT(searchTypeChanged(int)));
m_completermodel = new RclCompleterModel(this);
QCompleter *completer = new QCompleter(m_completermodel, this);
completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
completer->setFilterMode(Qt::MatchContains);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setMaxVisibleItems(completervisibleitems);
queryText->setCompleter(completer);
m_completer = new QCompleter(m_completermodel, this);
m_completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
m_completer->setFilterMode(Qt::MatchContains);
m_completer->setCaseSensitivity(Qt::CaseInsensitive);
m_completer->setMaxVisibleItems(completervisibleitems);
queryText->setCompleter(m_completer);
m_completer->popup()->installEventFilter(this);
queryText->installEventFilter(this);
connect(this, SIGNAL(partialWord(int, const QString&, const QString&)),
m_completermodel,
SLOT(onPartialWord(int,const QString&,const QString&)));
connect(completer, SIGNAL(activated(const QString&)), this,
connect(m_completer, SIGNAL(activated(const QString&)), this,
SLOT(onCompletionActivated(const QString&)));
connect(historyPB, SIGNAL(clicked()), this, SLOT(onHistoryClicked()));
}
@ -205,6 +208,77 @@ void SSearch::clearAll()
queryText->clear();
}
void SSearch::onCompleterShown()
{
LOGDEB("SSearch::onCompleterShown\n");
QCompleter *completer = queryText->completer();
if (!completer) {
LOGDEB0("SSearch::onCompleterShown: no completer\n");
return;
}
QAbstractItemView *popup = queryText->completer()->popup();
if (!popup) {
LOGDEB0("SSearch::onCompleterShown: no popup\n");
return;
}
QVariant data = popup->model()->data(popup->currentIndex());
if (!data.isValid()) {
LOGDEB0("SSearch::onCompleterShown: data not valid\n");
return;
}
// Test if the completer text begins with the current input.
QString text = data.toString();
if (!text.lastIndexOf(queryText->text()) == 0) {
return;
}
LOGDEB0("SSearch::onCompleterShown:" <<
" current [" << qs2utf8s(currentText()) <<
"] saved [" << qs2utf8s(m_savedEditText) <<
"] popup [" << qs2utf8s(text) << "]\n");
// We append the completion part to the end of the current input,
// line, and select it so that the user has a clear indication of
// what will happen if they type Enter.
int pos = queryText->cursorPosition();
int len = text.size() - currentText().size();
queryText->setText(text);
queryText->setCursorPosition(pos);
queryText->setSelection(pos, len);
}
// This is to avoid that if the user types Backspace or Del while we
// have inserted / selected the current completion, the lineedit text
// goes back to what it was, the completion fires, and it looks like
// nothing was typed. So we disable the completion if a
bool SSearch::eventFilter(QObject *target, QEvent *event)
{
LOGDEB1("SSearch::eventFilter: event\n");
if (event->type() != QEvent::KeyPress) {
return false;
}
LOGDEB1("SSearch::eventFilter: KeyPress event. Target " << target <<
" popup "<<m_completer->popup() << " lineedit "<<queryText<< "\n");
QKeyEvent *keyEvent = (QKeyEvent *)event;
if (keyEvent->key() == Qt::Key_Backspace && target==m_completer->popup()) {
LOGDEB("SSearch::eventFilter: backspace\n");
queryText->setCompleter(nullptr);
queryText->backspace();
return true;
} else if (keyEvent->key()==Qt::Key_Delete &&target==m_completer->popup()) {
LOGDEB("SSearch::eventFilter: delete\n");
queryText->setCompleter(nullptr);
queryText->del();
return true;
} else {
if (nullptr == queryText->completer()) {
queryText->setCompleter(m_completer);
}
}
return false;
}
// onCompletionActivated() is called when an entry is selected in the
// popup, but the edit text is going to be replaced in any case if
// there is a current match (we can't prevent it in the signal). If

View File

@ -36,12 +36,15 @@ class QTimer;
struct SSearchDef;
class SSearch;
class QCompleter;
class RclCompleterModel : public QAbstractListModel {
Q_OBJECT
public:
RclCompleterModel(QWidget *parent = 0)
: QAbstractListModel(parent) {
RclCompleterModel(SSearch *parent = 0)
: QAbstractListModel((QWidget*)parent), m_parent(parent) {
init();
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
@ -55,6 +58,7 @@ private:
int firstfromindex;
QPixmap clockPixmap;
QPixmap interroPixmap;
SSearch *m_parent{nullptr};
};
class SSearch : public QWidget, public Ui::SSearchBase {
@ -80,6 +84,7 @@ public:
// Restore ssearch UI from saved search
virtual bool fromXML(const SSearchDef& fxml);
virtual QString currentText();
virtual bool eventFilter(QObject *target, QEvent *event);
public slots:
virtual void searchTypeChanged(int);
@ -97,6 +102,7 @@ private slots:
virtual void onCompletionActivated(const QString&);
virtual void restoreText();
virtual void onHistoryClicked();
virtual void onCompleterShown();
signals:
void startSearch(std::shared_ptr<Rcl::SearchData>, bool);
@ -108,12 +114,13 @@ private:
int getPartialWord(QString& word);
bool startSimpleSearch(const string& q, int maxexp = -1);
RclCompleterModel *m_completermodel{nullptr};
QCompleter *m_completer{nullptr};
/* We save multiword entries because the completer replaces them with
the completion */
QString m_savedEditText;
/* Saved xml version of the search, as we start it */
std::string m_xml;
RclCompleterModel *m_completermodel{nullptr};
};