GUI ssearch: improve interaction with completer

This commit is contained in:
Jean-Francois Dockes 2019-02-04 11:46:45 +01:00
parent b079f0fb94
commit 541c407033
2 changed files with 65 additions and 30 deletions

View File

@ -122,20 +122,19 @@ void RclCompleterModel::onPartialWord(
for (int i = 0; i < prefs.ssearchHistory.count(); i++) { for (int i = 0; i < prefs.ssearchHistory.count(); i++) {
LOGDEB1("[" << qs2u8s(prefs.ssearchHistory[i]) << "] contains [" << LOGDEB1("[" << qs2u8s(prefs.ssearchHistory[i]) << "] contains [" <<
qs2u8s(qtext) << "] ?\n"); qs2u8s(qtext) << "] ?\n");
// If there is current text, only show a limited count of
// matching entries, else show the full history.
if (onlyspace || if (onlyspace ||
prefs.ssearchHistory[i].contains(qtext, Qt::CaseInsensitive)) { prefs.ssearchHistory[i].contains(qtext, Qt::CaseInsensitive)) {
LOGDEB1("YES\n");
currentlist.push_back(prefs.ssearchHistory[i]); currentlist.push_back(prefs.ssearchHistory[i]);
if (!onlyspace && ++histmatch >= maxhistmatch) if (!onlyspace && ++histmatch >= maxhistmatch)
break; break;
} else {
LOGDEB1("NO\n");
} }
} }
firstfromindex = currentlist.size(); firstfromindex = currentlist.size();
// Look for Recoll terms beginning with the partial word // Look for Recoll terms beginning with the partial word
if (!partial.empty() && partial.compare(" ")) { if (!qpartial.trimmed().isEmpty()) {
Rcl::TermMatchResult rclmatches; Rcl::TermMatchResult rclmatches;
if (!rcldb->termMatch(Rcl::Db::ET_WILD, string(), if (!rcldb->termMatch(Rcl::Db::ET_WILD, string(),
partial + "*", rclmatches, maxdbtermmatch)) { partial + "*", rclmatches, maxdbtermmatch)) {
@ -172,16 +171,16 @@ void SSearch::init()
connect(searchTypCMB, SIGNAL(activated(int)), this, connect(searchTypCMB, SIGNAL(activated(int)), this,
SLOT(searchTypeChanged(int))); SLOT(searchTypeChanged(int)));
RclCompleterModel *completermodel = new RclCompleterModel(this); m_completermodel = new RclCompleterModel(this);
QCompleter *completer = new QCompleter(completermodel, this); QCompleter *completer = new QCompleter(m_completermodel, this);
completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
completer->setFilterMode(Qt::MatchContains); completer->setFilterMode(Qt::MatchContains);
completer->setCaseSensitivity(Qt::CaseInsensitive); completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setMaxVisibleItems(completervisibleitems); completer->setMaxVisibleItems(completervisibleitems);
queryText->setCompleter(completer); queryText->setCompleter(completer);
connect( connect(this, SIGNAL(partialWord(int, const QString&, const QString&)),
this, SIGNAL(partialWord(int, const QString&, const QString&)), m_completermodel,
completermodel, SLOT(onPartialWord(int,const QString&,const QString&))); SLOT(onPartialWord(int,const QString&,const QString&)));
connect(completer, SIGNAL(activated(const QString&)), this, connect(completer, SIGNAL(activated(const QString&)), this,
SLOT(onCompletionActivated(const QString&))); SLOT(onCompletionActivated(const QString&)));
connect(historyPB, SIGNAL(clicked()), this, SLOT(onHistoryClicked())); connect(historyPB, SIGNAL(clicked()), this, SLOT(onHistoryClicked()));
@ -206,28 +205,46 @@ void SSearch::clearAll()
queryText->clear(); queryText->clear();
} }
// 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
// there is no match (e.g. the user clicked the history button and
// selected an entry), the query text will not be set.
// So:
// - We set the query text to the popup activation value in all cases
// - We schedule a callback to set the text to what we want (which is the
// concatenation of the user entry before the current partial word and the
// pop up data.
// - Note that a history click will replace a current partial word,
// so that the effect is different if there is a space at the end
// of the entry or not: pure concatenation vs replacement of the
// last (partial) word.
void SSearch::restoreText() void SSearch::restoreText()
{ {
queryText->setText(m_savedEditText); LOGDEB("SSearch::restoreText: savedEdit: " << qs2u8s(m_savedEditText) <<
endl);
if (!m_savedEditText.trimmed().isEmpty()) {
// If the popup text begins with the saved text, just let it replace
if (currentText().lastIndexOf(m_savedEditText) != 0) {
queryText->setText(m_savedEditText.trimmed() + " " + currentText());
}
m_savedEditText = "";
}
} }
void SSearch::onCompletionActivated(const QString& text) void SSearch::onCompletionActivated(const QString& text)
{ {
LOGDEB1("SSearch::onCompletionActivated: current text " << LOGDEB("SSearch::onCompletionActivated: queryText [" <<
qs2u8s(currentText()) << endl); qs2u8s(currentText()) << "] text [" << qs2u8s(text) << "]\n");
m_savedEditText = m_savedEditText + text; queryText->setText(text);
QTimer::singleShot(0, this, SLOT(restoreText())); QTimer::singleShot(0, this, SLOT(restoreText()));
} }
void SSearch::onHistoryClicked() void SSearch::onHistoryClicked()
{ {
QKeyEvent event(QEvent::KeyPress, Qt::Key_Space, 0, " "); if (m_completermodel) {
QApplication::sendEvent(queryText, &event); m_completermodel->onPartialWord(SST_LANG, "", "");
event = QKeyEvent(QEvent::KeyRelease, Qt::Key_Space, 0); queryText->completer()->complete();
QApplication::sendEvent(queryText, &event); }
queryText->setText(" ");
QTimer::singleShot(0, queryText->completer()->popup(),
SLOT(scrollToTop()));
} }
void SSearch::searchTextEdited(const QString& text) void SSearch::searchTextEdited(const QString& text)
@ -254,16 +271,12 @@ void SSearch::searchTextChanged(const QString& text)
if (text.isEmpty()) { if (text.isEmpty()) {
searchPB->setEnabled(false); searchPB->setEnabled(false);
clearqPB->setEnabled(false); clearqPB->setEnabled(false);
historyPB->setEnabled(true);
queryText->setFocus(); queryText->setFocus();
emit clearSearch(); emit clearSearch();
} else { } else {
searchPB->setEnabled(true); searchPB->setEnabled(true);
clearqPB->setEnabled(true); clearqPB->setEnabled(true);
} }
if (!text.trimmed().isEmpty()) {
historyPB->setEnabled(false);
}
} }
void SSearch::searchTypeChanged(int typ) void SSearch::searchTypeChanged(int typ)
@ -535,14 +548,35 @@ int SSearch::getPartialWord(QString& word)
{ {
// Extract last word in text // Extract last word in text
QString txt = currentText(); QString txt = currentText();
int cs = txt.lastIndexOf(" "); if (txt.isEmpty()) {
if (cs == -1) return -1;
}
int lstidx = txt.size()-1;
// If the input ends with a space or dquote (phrase input), or
// dquote+qualifiers, no partial word.
if (txt[lstidx] == ' ') {
return -1;
}
int cs = txt.lastIndexOf("\"");
if (cs > 0) {
bool dquoteToEndNoSpace{true};
for (int i = cs; i <= lstidx; i++) {
if (txt[i] == " ") {
dquoteToEndNoSpace = false;
break;
}
}
if (dquoteToEndNoSpace) {
return -1;
}
}
cs = txt.lastIndexOf(" ");
if (cs < 0)
cs = 0; cs = 0;
else else
cs++; cs++;
if (txt.size() == 0 || cs == txt.size()) {
return -1;
}
word = txt.right(txt.size() - cs); word = txt.right(txt.size() - cs);
return cs; return cs;
} }

View File

@ -112,6 +112,7 @@ private:
QString m_savedEditText; QString m_savedEditText;
/* Saved xml version of the search, as we start it */ /* Saved xml version of the search, as we start it */
std::string m_xml; std::string m_xml;
RclCompleterModel *m_completermodel{nullptr};
}; };