Switch to unified view

a/src/qtgui/ssearch_w.cpp b/src/qtgui/ssearch_w.cpp
...
...
63
    queryText->setInsertPolicy(QComboBox::NoInsert);
63
    queryText->setInsertPolicy(QComboBox::NoInsert);
64
64
65
    queryText->addItems(prefs.ssearchHistory);
65
    queryText->addItems(prefs.ssearchHistory);
66
    queryText->setEditText("");
66
    queryText->setEditText("");
67
    connect(queryText->lineEdit(), SIGNAL(returnPressed()),
67
    connect(queryText->lineEdit(), SIGNAL(returnPressed()),
68
      this, SLOT(startSimpleSearch()));
68
            this, SLOT(startSimpleSearch()));
69
    connect(queryText->lineEdit(), SIGNAL(textChanged(const QString&)),
69
    connect(queryText->lineEdit(), SIGNAL(textChanged(const QString&)),
70
      this, SLOT(searchTextChanged(const QString&)));
70
            this, SLOT(searchTextChanged(const QString&)));
71
    connect(clearqPB, SIGNAL(clicked()), 
71
    connect(clearqPB, SIGNAL(clicked()), 
72
      queryText->lineEdit(), SLOT(clear()));
72
            queryText->lineEdit(), SLOT(clear()));
73
    connect(searchPB, SIGNAL(clicked()), this, SLOT(startSimpleSearch()));
73
    connect(searchPB, SIGNAL(clicked()), this, SLOT(startSimpleSearch()));
74
    connect(searchTypCMB, SIGNAL(activated(int)), this, SLOT(searchTypeChanged(int)));
74
    connect(searchTypCMB, SIGNAL(activated(int)), this,
75
            SLOT(searchTypeChanged(int)));
75
76
76
    queryText->installEventFilter(this);
77
    queryText->installEventFilter(this);
77
    queryText->view()->installEventFilter(this);
78
    queryText->view()->installEventFilter(this);
78
    queryText->setInsertPolicy(QComboBox::NoInsert);
79
    queryText->setInsertPolicy(QComboBox::NoInsert);
79
    // Note: we can't do the obvious and save the completer instead because
80
    // Note: we can't do the obvious and save the completer instead because
80
    // the combobox lineedit will delete the completer on setCompleter(0).
81
    // the combobox lineedit will delete the completer on setCompleter(0).
81
    // But the model does not belong to the completer so it's not deleted...
82
    // But the model does not belong to the completer so it's not deleted...
82
    m_savedModel = queryText->completer()->model();
83
    m_savedModel = queryText->completer()->model();
83
    if (prefs.ssearchNoComplete)
84
    if (prefs.ssearchNoComplete)
84
  queryText->completer()->setModel(0);
85
        queryText->completer()->setModel(0);
85
    // Recoll searches are always case-sensitive because of the use of
86
    // Recoll searches are always case-sensitive because of the use of
86
    // capitalization to suppress stemming
87
    // capitalization to suppress stemming
87
    queryText->completer()->setCaseSensitivity(Qt::CaseSensitive);
88
    queryText->completer()->setCaseSensitivity(Qt::CaseSensitive);
88
    m_displayingCompletions = false;
89
    m_displayingCompletions = false;
89
    m_escape = false;
90
    m_escape = false;
...
...
94
    m_keystroke = false;
95
    m_keystroke = false;
95
}
96
}
96
97
97
void SSearch::takeFocus()
98
void SSearch::takeFocus()
98
{
99
{
99
    LOGDEB2("SSearch: take focus\n" );
100
    LOGDEB2("SSearch: take focus\n");
100
    queryText->setFocus(Qt::ShortcutFocusReason);
101
    queryText->setFocus(Qt::ShortcutFocusReason);
101
    // If the focus was already in the search entry, the text is not selected.
102
    // If the focus was already in the search entry, the text is not selected.
102
    // Do it for consistency
103
    // Do it for consistency
103
    queryText->lineEdit()->selectAll();
104
    queryText->lineEdit()->selectAll();
104
}
105
}
105
106
106
void SSearch::timerDone()
107
void SSearch::timerDone()
107
{
108
{
108
    QString qs = queryText->currentText();
109
    QString qs = queryText->currentText();
109
    LOGDEB1("SSearch::timerDone: qs ["  << (qs2utf8s(qs)) << "]\n" );
110
    LOGDEB1("SSearch::timerDone: qs [" << qs2utf8s(qs) << "]\n");
110
    searchTextChanged(qs);
111
    searchTextChanged(qs);
111
}
112
}
112
113
113
void SSearch::searchTextChanged(const QString& text)
114
void SSearch::searchTextChanged(const QString& text)
114
{
115
{
115
    QString qs = queryText->currentText();
116
    QString qs = queryText->currentText();
116
    LOGDEB1("SSearch::searchTextChanged. ks "  << (m_keystroke) << " qs ["  << (qs2utf8s(text)) << "]\n" );
117
    LOGDEB1("SSearch::searchTextChanged. ks " << m_keystroke << " qs [" <<
118
            qs2utf8s(text) << "]\n");
117
    if (text.isEmpty()) {
119
    if (text.isEmpty()) {
118
  searchPB->setEnabled(false);
120
        searchPB->setEnabled(false);
119
  clearqPB->setEnabled(false);
121
        clearqPB->setEnabled(false);
120
  queryText->setFocus();
122
        queryText->setFocus();
121
  emit clearSearch();
123
        emit clearSearch();
122
    } else {
124
    } else {
123
  searchPB->setEnabled(true);
125
        searchPB->setEnabled(true);
124
  clearqPB->setEnabled(true);
126
        clearqPB->setEnabled(true);
125
  if (m_keystroke) {
127
        if (m_keystroke) {
126
      m_tstartqs = qs;
128
            m_tstartqs = qs;
127
  }
129
        }
128
  if (prefs.ssearchAsYouType && !m_disableAutosearch && 
130
        if (prefs.ssearchAsYouType && !m_disableAutosearch && 
129
      !m_keystroke && m_tstartqs == qs) {
131
            !m_keystroke && m_tstartqs == qs) {
130
      m_disableAutosearch = true;
132
            m_disableAutosearch = true;
131
      string s;
133
            string s;
132
      int cs = partialWord(s);
134
            int cs = partialWord(s);
133
      LOGDEB1("SSearch::searchTextChanged: autosearch. cs "  << (cs) << " s ["  << (s) << "]\n" );
135
            LOGDEB1("SSearch::searchTextChanged: autosearch. cs " << cs <<
136
                    " s [" << s << "]\n");
134
      if (cs < 0) {
137
            if (cs < 0) {
135
      startSimpleSearch();
138
                startSimpleSearch();
136
      } else if (!m_stroketimeout->isActive() && s.size() >= 2) {
139
            } else if (!m_stroketimeout->isActive() && s.size() >= 2) {
137
      s = qs2utf8s(queryText->currentText());
140
                s = qs2utf8s(queryText->currentText());
138
      s += "*";
141
                s += "*";
139
      startSimpleSearch(s, 20);
142
                startSimpleSearch(s, 20);
140
      }
143
            }
141
  }
144
        }
142
    }
145
    }
143
    m_keystroke = false;
146
    m_keystroke = false;
144
}
147
}
145
148
146
void SSearch::searchTypeChanged(int typ)
149
void SSearch::searchTypeChanged(int typ)
147
{
150
{
148
    LOGDEB("Search type now "  << (typ) << "\n" );
151
    LOGDEB("Search type now " << typ << "\n");
149
    // Adjust context help
152
    // Adjust context help
150
    if (typ == SST_LANG)
153
    if (typ == SST_LANG) {
151
  HelpClient::installMap((const char *)this->objectName().toUtf8(), 
154
        HelpClient::installMap((const char *)this->objectName().toUtf8(), 
152
                 "RCL.SEARCH.LANG");
155
                               "RCL.SEARCH.LANG");
153
    else 
156
    } else {
154
  HelpClient::installMap((const char *)this->objectName().toUtf8(), 
157
        HelpClient::installMap((const char *)this->objectName().toUtf8(), 
155
                 "RCL.SEARCH.GUI.SIMPLE");
158
                               "RCL.SEARCH.GUI.SIMPLE");
156
159
    }
157
    // Also fix tooltips
160
    // Also fix tooltips
158
    switch (typ) {
161
    switch (typ) {
159
    case SST_LANG:
162
    case SST_LANG:
160
        queryText->setToolTip(tr(
163
        queryText->setToolTip(
164
            tr(
161
"Enter query language expression. Cheat sheet:<br>\n"
165
"Enter query language expression. Cheat sheet:<br>\n"
162
"<i>term1 term2</i> : 'term1' and 'term2' in any field.<br>\n"
166
"<i>term1 term2</i> : 'term1' and 'term2' in any field.<br>\n"
163
"<i>field:term1</i> : 'term1' in field 'field'.<br>\n"
167
"<i>field:term1</i> : 'term1' in field 'field'.<br>\n"
164
" Standard field names/synonyms:<br>\n"
168
" Standard field names/synonyms:<br>\n"
165
"  title/subject/caption, author/from, recipient/to, filename, ext.<br>\n"
169
"  title/subject/caption, author/from, recipient/to, filename, ext.<br>\n"
...
...
168
"<i>term1 term2 OR term3</i> : term1 AND (term2 OR term3).<br>\n"
172
"<i>term1 term2 OR term3</i> : term1 AND (term2 OR term3).<br>\n"
169
"  You can use parentheses to make things clearer.<br>\n"
173
"  You can use parentheses to make things clearer.<br>\n"
170
"<i>\"term1 term2\"</i> : phrase (must occur exactly). Possible modifiers:<br>\n"
174
"<i>\"term1 term2\"</i> : phrase (must occur exactly). Possible modifiers:<br>\n"
171
"<i>\"term1 term2\"p</i> : unordered proximity search with default distance.<br>\n"
175
"<i>\"term1 term2\"p</i> : unordered proximity search with default distance.<br>\n"
172
"Use <b>Show Query</b> link when in doubt about result and see manual (&lt;F1>) for more detail.\n"
176
"Use <b>Show Query</b> link when in doubt about result and see manual (&lt;F1>) for more detail.\n"
173
                ));
177
                ));
174
        break;
178
        break;
175
    case SST_FNM:
179
    case SST_FNM:
176
        queryText->setToolTip(tr("Enter file name wildcard expression."));
180
        queryText->setToolTip(tr("Enter file name wildcard expression."));
177
        break;
181
        break;
178
    case SST_ANY:
182
    case SST_ANY:
179
    case SST_ALL:
183
    case SST_ALL:
180
    default:
184
    default:
181
        queryText->setToolTip(tr(
185
        queryText->setToolTip(
186
            tr(
182
      "Enter search terms here. Type ESC SPC for completions of current term."
187
        "Enter search terms here. Type ESC SPC for completions of current term."
183
                ));
188
                ));
184
    }
189
    }
185
}
190
}
186
191
187
void SSearch::startSimpleSearch()
192
void SSearch::startSimpleSearch()
188
{
193
{
189
    QString qs = queryText->currentText();
194
    QString qs = queryText->currentText();
190
    LOGDEB("SSearch::startSimpleSearch(): qs ["  << (qs2utf8s(qs)) << "]\n" );
195
    LOGDEB("SSearch::startSimpleSearch(): qs [" << qs2utf8s(qs) << "]\n");
191
    if (qs.length() == 0)
196
    if (qs.length() == 0)
192
  return;
197
        return;
193
198
194
    string u8 = (const char *)queryText->currentText().toUtf8();
199
    string u8 = (const char *)queryText->currentText().toUtf8();
195
200
196
    trimstring(u8);
201
    trimstring(u8);
197
    if (u8.length() == 0)
202
    if (u8.length() == 0)
198
  return;
203
        return;
199
204
200
    if (!startSimpleSearch(u8))
205
    if (!startSimpleSearch(u8))
201
  return;
206
        return;
202
207
203
    LOGDEB("startSimpleSearch: updating history\n" );
208
    LOGDEB("startSimpleSearch: updating history\n");
204
    // Search terms history:
209
    // Search terms history:
205
    // We want to have the new text at the top and any older identical
210
    // We want to have the new text at the top and any older identical
206
    // entry to be erased. There is no standard qt policy to do this ? 
211
    // entry to be erased. There is no standard qt policy to do this ? 
207
    // So do it by hand.
212
    // So do it by hand.
208
    QString txt = queryText->currentText();
213
    QString txt = queryText->currentText();
209
    QString txtt = txt.trimmed();
214
    QString txtt = txt.trimmed();
210
    int index = queryText->findText(txtt);
215
    int index = queryText->findText(txtt);
211
    if (index > 0) {
216
    if (index > 0) {
212
  queryText->removeItem(index);
217
        queryText->removeItem(index);
213
    }
218
    }
214
    if (index != 0) {
219
    if (index != 0) {
215
  queryText->insertItem(0, txtt);
220
        queryText->insertItem(0, txtt);
216
  queryText->setEditText(txt);
221
        queryText->setEditText(txt);
217
    }
222
    }
218
    m_disableAutosearch = true;
223
    m_disableAutosearch = true;
219
    m_stroketimeout->stop();
224
    m_stroketimeout->stop();
220
225
221
    // Save the current state of the listbox list to the prefs (will
226
    // Save the current state of the listbox list to the prefs (will
222
    // go to disk)
227
    // go to disk)
223
    prefs.ssearchHistory.clear();
228
    prefs.ssearchHistory.clear();
224
    for (int index = 0; index < queryText->count(); index++) {
229
    for (int index = 0; index < queryText->count(); index++) {
225
  prefs.ssearchHistory.push_back(queryText->itemText(index));
230
        prefs.ssearchHistory.push_back(queryText->itemText(index));
226
    }
231
    }
227
}
232
}
228
void SSearch::setPrefs()
233
void SSearch::setPrefs()
229
{
234
{
230
    if (prefs.ssearchNoComplete) {
235
    if (prefs.ssearchNoComplete) {
231
  queryText->completer()->setModel(0);
236
        queryText->completer()->setModel(0);
232
    } else {
237
    } else {
233
  queryText->completer()->setModel(m_savedModel);
238
        queryText->completer()->setModel(m_savedModel);
234
    }
239
    }
235
}
240
}
236
241
237
string SSearch::asXML()
242
string SSearch::asXML()
238
{
243
{
239
    return m_xml;
244
    return m_xml;
240
}
245
}
241
246
242
bool SSearch::startSimpleSearch(const string& u8, int maxexp)
247
bool SSearch::startSimpleSearch(const string& u8, int maxexp)
243
{
248
{
244
    LOGDEB("SSearch::startSimpleSearch("  << (u8) << ")\n" );
249
    LOGDEB("SSearch::startSimpleSearch(" << u8 << ")\n");
245
    string stemlang = prefs.stemlang();
250
    string stemlang = prefs.stemlang();
246
251
247
    ostringstream xml;
252
    ostringstream xml;
248
    xml << "<SD type='ssearch'>\n";
253
    xml << "<SD type='ssearch'>\n";
249
    xml << "  <SL>" << stemlang << "</SL>\n";
254
    xml << "  <SL>" << stemlang << "</SL>\n";
...
...
252
    SSearchType tp = (SSearchType)searchTypCMB->currentIndex();
257
    SSearchType tp = (SSearchType)searchTypCMB->currentIndex();
253
    Rcl::SearchData *sdata = 0;
258
    Rcl::SearchData *sdata = 0;
254
259
255
    if (tp == SST_LANG) {
260
    if (tp == SST_LANG) {
256
        xml << "  <SM>QL</SM>\n";
261
        xml << "  <SM>QL</SM>\n";
257
  string reason;
262
        string reason;
258
        if (prefs.autoSuffsEnable) {
263
        if (prefs.autoSuffsEnable) {
259
            sdata = wasaStringToRcl(theconfig, stemlang, u8, reason, 
264
            sdata = wasaStringToRcl(theconfig, stemlang, u8, reason, 
260
                  (const char *)prefs.autoSuffs.toUtf8());
265
                                    (const char *)prefs.autoSuffs.toUtf8());
261
            if (!prefs.autoSuffs.isEmpty()) {
266
            if (!prefs.autoSuffs.isEmpty()) {
262
                xml <<  "  <AS>" << qs2utf8s(prefs.autoSuffs) << "</AS>\n";
267
                xml <<  "  <AS>" << qs2utf8s(prefs.autoSuffs) << "</AS>\n";
263
            }
268
            }
264
        } else {
269
        } else {
265
            sdata = wasaStringToRcl(theconfig, stemlang, u8, reason);
270
            sdata = wasaStringToRcl(theconfig, stemlang, u8, reason);
266
        }
271
        }
267
  if (sdata == 0) {
272
        if (sdata == 0) {
268
      QMessageBox::warning(0, "Recoll", tr("Bad query string") + ": " +
273
            QMessageBox::warning(0, "Recoll", tr("Bad query string") + ": " +
269
               QString::fromUtf8(reason.c_str()));
274
                                 QString::fromUtf8(reason.c_str()));
270
      return false;
275
            return false;
271
  }
276
        }
272
    } else {
277
    } else {
273
  sdata = new Rcl::SearchData(Rcl::SCLT_OR, stemlang);
278
        sdata = new Rcl::SearchData(Rcl::SCLT_OR, stemlang);
274
  if (sdata == 0) {
279
        if (sdata == 0) {
275
      QMessageBox::warning(0, "Recoll", tr("Out of memory"));
280
            QMessageBox::warning(0, "Recoll", tr("Out of memory"));
276
      return false;
281
            return false;
277
  }
282
        }
278
  Rcl::SearchDataClause *clp = 0;
283
        Rcl::SearchDataClause *clp = 0;
279
  if (tp == SST_FNM) {
284
        if (tp == SST_FNM) {
280
            xml << "  <SM>FN</SM>\n";
285
            xml << "  <SM>FN</SM>\n";
281
      clp = new Rcl::SearchDataClauseFilename(u8);
286
            clp = new Rcl::SearchDataClauseFilename(u8);
282
  } else {
287
        } else {
283
      // ANY or ALL, several words.
288
            // ANY or ALL, several words.
284
      if (tp == SST_ANY) {
289
            if (tp == SST_ANY) {
285
                xml << "  <SM>OR</SM>\n";
290
                xml << "  <SM>OR</SM>\n";
286
      clp = new Rcl::SearchDataClauseSimple(Rcl::SCLT_OR, u8);
291
                clp = new Rcl::SearchDataClauseSimple(Rcl::SCLT_OR, u8);
287
      } else {
292
            } else {
288
                xml << "  <SM>AND</SM>\n";
293
                xml << "  <SM>AND</SM>\n";
289
      clp = new Rcl::SearchDataClauseSimple(Rcl::SCLT_AND, u8);
294
                clp = new Rcl::SearchDataClauseSimple(Rcl::SCLT_AND, u8);
290
      }
295
            }
291
  }
296
        }
292
  sdata->addClause(clp);
297
        sdata->addClause(clp);
293
    }
298
    }
294
299
295
    if (prefs.ssearchAutoPhrase && rcldb) {
300
    if (prefs.ssearchAutoPhrase && rcldb) {
296
        xml << "  <AP/>\n";
301
        xml << "  <AP/>\n";
297
  sdata->maybeAddAutoPhrase(*rcldb, 
302
        sdata->maybeAddAutoPhrase(*rcldb, 
298
                prefs.ssearchAutoPhraseThreshPC / 100.0);
303
                                  prefs.ssearchAutoPhraseThreshPC / 100.0);
299
    }
304
    }
300
    if (maxexp != -1) {
305
    if (maxexp != -1) {
301
  sdata->setMaxExpand(maxexp);
306
        sdata->setMaxExpand(maxexp);
302
    }
307
    }
303
308
304
    for (const auto& dbdir : prefs.activeExtraDbs) {
309
    for (const auto& dbdir : prefs.activeExtraDbs) {
305
        xml << "  <EX>" << base64_encode(dbdir) << "</EX>";
310
        xml << "  <EX>" << base64_encode(dbdir) << "</EX>";
306
    }
311
    }
307
312
308
    xml << "</SD>\n";
313
    xml << "</SD>\n";
309
    m_xml = xml.str();
314
    m_xml = xml.str();
310
    LOGDEB("SSearch::startSimpleSearch:xml:["  << (m_xml) << "]\n" );
315
    LOGDEB("SSearch::startSimpleSearch:xml:[" << m_xml << "]\n");
311
316
312
    std::shared_ptr<Rcl::SearchData> rsdata(sdata);
317
    std::shared_ptr<Rcl::SearchData> rsdata(sdata);
313
    emit startSearch(rsdata, true);
318
    emit startSearch(rsdata, true);
314
    return true;
319
    return true;
315
}
320
}
...
...
391
// instead of auto as for preview, needed because it's built by
396
// instead of auto as for preview, needed because it's built by
392
// fragments?).
397
// fragments?).
393
static const char* punct = " \t()<>\"'[]{}!^*.,:;\n\r";
398
static const char* punct = " \t()<>\"'[]{}!^*.,:;\n\r";
394
void SSearch::addTerm(QString term)
399
void SSearch::addTerm(QString term)
395
{
400
{
396
    LOGDEB("SSearch::AddTerm: ["  << ((const char *)term.toUtf8()) << "]\n" );
401
    LOGDEB("SSearch::AddTerm: [" << qs2utf8s(term) << "]\n");
397
    string t = (const char *)term.toUtf8();
402
    string t = (const char *)term.toUtf8();
398
    string::size_type pos = t.find_last_not_of(punct);
403
    string::size_type pos = t.find_last_not_of(punct);
399
    if (pos == string::npos)
404
    if (pos == string::npos)
400
  return;
405
        return;
401
    t = t.substr(0, pos+1);
406
    t = t.substr(0, pos+1);
402
    pos = t.find_first_not_of(punct);
407
    pos = t.find_first_not_of(punct);
403
    if (pos != string::npos)
408
    if (pos != string::npos)
404
  t = t.substr(pos);
409
        t = t.substr(pos);
405
    if (t.empty())
410
    if (t.empty())
406
  return;
411
        return;
407
    term = QString::fromUtf8(t.c_str());
412
    term = QString::fromUtf8(t.c_str());
408
413
409
    QString text = queryText->currentText();
414
    QString text = queryText->currentText();
410
    text += QString::fromLatin1(" ") + term;
415
    text += QString::fromLatin1(" ") + term;
411
    queryText->setEditText(text);
416
    queryText->setEditText(text);
...
...
413
    m_stroketimeout->stop();
418
    m_stroketimeout->stop();
414
}
419
}
415
420
416
void SSearch::onWordReplace(const QString& o, const QString& n)
421
void SSearch::onWordReplace(const QString& o, const QString& n)
417
{
422
{
418
    LOGDEB("SSearch::onWordReplace: o ["  << (qs2utf8s(o)) << "] n ["  << (qs2utf8s(n)) << "]\n" );
423
    LOGDEB("SSearch::onWordReplace: o [" << qs2utf8s(o) << "] n [" <<
424
           qs2utf8s(n) << "]\n");
419
    QString txt = queryText->currentText();
425
    QString txt = queryText->currentText();
420
    QRegExp exp = QRegExp(QString("\\b") + o + QString("\\b"));
426
    QRegExp exp = QRegExp(QString("\\b") + o + QString("\\b"));
421
    exp.setCaseSensitivity(Qt::CaseInsensitive);
427
    exp.setCaseSensitivity(Qt::CaseInsensitive);
422
    txt.replace(exp, n);
428
    txt.replace(exp, n);
423
    queryText->setEditText(txt);
429
    queryText->setEditText(txt);
424
    m_disableAutosearch = true;
430
    m_disableAutosearch = true;
425
    m_stroketimeout->stop();
431
    m_stroketimeout->stop();
426
    Qt::KeyboardModifiers mods = QApplication::keyboardModifiers ();
432
    Qt::KeyboardModifiers mods = QApplication::keyboardModifiers ();
427
    if (mods == Qt::NoModifier)
433
    if (mods == Qt::NoModifier)
428
  startSimpleSearch();
434
        startSimpleSearch();
429
}
435
}
430
436
431
void SSearch::setAnyTermMode()
437
void SSearch::setAnyTermMode()
432
{
438
{
433
    searchTypCMB->setCurrentIndex(SST_ANY);
439
    searchTypCMB->setCurrentIndex(SST_ANY);
...
...
439
{
445
{
440
    // Extract last word in text
446
    // Extract last word in text
441
    QString txt = queryText->currentText();
447
    QString txt = queryText->currentText();
442
    int cs = txt.lastIndexOf(" ");
448
    int cs = txt.lastIndexOf(" ");
443
    if (cs == -1)
449
    if (cs == -1)
444
  cs = 0;
450
        cs = 0;
445
    else
451
    else
446
  cs++;
452
        cs++;
447
    if (txt.size() == 0 || cs == txt.size()) {
453
    if (txt.size() == 0 || cs == txt.size()) {
448
  return -1;
454
        return -1;
449
    }
455
    }
450
    s = qs2utf8s(txt.right(txt.size() - cs));
456
    s = qs2utf8s(txt.right(txt.size() - cs));
451
    return cs;
457
    return cs;
452
}
458
}
453
459
454
// Create completion list for term by adding a joker at the end and calling
460
// Create completion list for term by adding a joker at the end and calling
455
// rcldb->termMatch().
461
// rcldb->termMatch().
456
int SSearch::completionList(string s, QStringList& lst, int max)
462
int SSearch::completionList(string s, QStringList& lst, int max)
457
{
463
{
458
    if (!rcldb)
464
    if (!rcldb)
459
  return -1;
465
        return -1;
460
    if (s.empty())
466
    if (s.empty())
461
  return 0;
467
        return 0;
462
   // Query database for completions
468
    // Query database for completions
463
    s += "*";
469
    s += "*";
464
    Rcl::TermMatchResult tmres;
470
    Rcl::TermMatchResult tmres;
465
    if (!rcldb->termMatch(Rcl::Db::ET_WILD, "", s, tmres, max) || 
471
    if (!rcldb->termMatch(Rcl::Db::ET_WILD, "", s, tmres, max) || 
466
  tmres.entries.size() == 0) {
472
        tmres.entries.size() == 0) {
467
  return 0;
473
        return 0;
468
    }
474
    }
469
    for (vector<Rcl::TermMatchEntry>::iterator it = tmres.entries.begin(); 
475
    for (const auto& entry: tmres.entries) {
470
   it != tmres.entries.end(); it++) {
476
        lst.push_back(u8s2qs(entry.term));
471
  lst.push_back(QString::fromUtf8(it->term.c_str()));
472
    }
477
    }
473
    return lst.size();
478
    return lst.size();
474
}
479
}
475
480
476
// Complete last word in input by querying db for all possible terms.
481
// Complete last word in input by querying db for all possible terms.
477
void SSearch::completion()
482
void SSearch::completion()
478
{
483
{
479
    LOGDEB("SSearch::completion\n" );
484
    LOGDEB("SSearch::completion\n");
480
485
481
    m_disableAutosearch = true;
486
    m_disableAutosearch = true;
482
    m_stroketimeout->stop();
487
    m_stroketimeout->stop();
483
488
484
    if (!rcldb)
489
    if (!rcldb)
485
  return;
490
        return;
486
    if (searchTypCMB->currentIndex() == SST_FNM) {
491
    if (searchTypCMB->currentIndex() == SST_FNM) {
487
  // Filename: no completion
492
        // Filename: no completion
488
  QApplication::beep();
493
        QApplication::beep();
489
  return;
494
        return;
490
    }
495
    }
491
496
492
    // Extract last word in text
497
    // Extract last word in text
493
    string s;
498
    string s;
494
    int cs = partialWord(s);
499
    int cs = partialWord(s);
495
    if (cs < 0) {
500
    if (cs < 0) {
496
  QApplication::beep();
501
        QApplication::beep();
497
  return;
502
        return;
498
    }
503
    }
499
504
500
    // Query database for completions
505
    // Query database for completions
501
    QStringList lst;
506
    QStringList lst;
502
    const int maxdpy = 80;
507
    const int maxdpy = 80;
503
    const int maxwalked = 10000;
508
    const int maxwalked = 10000;
504
    if (completionList(s, lst, maxwalked) <= 0) {
509
    if (completionList(s, lst, maxwalked) <= 0) {
505
  QApplication::beep();
510
        QApplication::beep();
506
  return;
511
        return;
507
    }
512
    }
508
    if (lst.size() >= maxdpy) {
513
    if (lst.size() >= maxdpy) {
509
  LOGDEB0("SSearch::completion(): truncating list\n" );
514
        LOGDEB0("SSearch::completion(): truncating list\n");
510
  lst = lst.mid(0, maxdpy);
515
        lst = lst.mid(0, maxdpy);
511
  lst.append("[...]");
516
        lst.append("[...]");
512
    }
517
    }
513
518
514
    // If list from db is single word, insert it, else popup the listview
519
    // If list from db is single word, insert it, else popup the listview
515
    if (lst.size() == 1) {
520
    if (lst.size() == 1) {
516
  QString txt = queryText->currentText();
521
        QString txt = queryText->currentText();
517
  txt.truncate(cs);
522
        txt.truncate(cs);
518
  txt.append(lst[0]);
523
        txt.append(lst[0]);
519
  queryText->setEditText(txt);
524
        queryText->setEditText(txt);
520
    } else {
525
    } else {
521
  m_savedEditText = queryText->currentText();
526
        m_savedEditText = queryText->currentText();
522
  m_displayingCompletions = true;
527
        m_displayingCompletions = true;
523
  m_chosenCompletion.clear();
528
        m_chosenCompletion.clear();
524
  m_completedWordStart = cs;
529
        m_completedWordStart = cs;
525
530
526
  queryText->clear();
531
        queryText->clear();
527
  queryText->addItems(lst);
532
        queryText->addItems(lst);
528
  queryText->showPopup();
533
        queryText->showPopup();
529
534
530
  connect(queryText, SIGNAL(activated(const QString&)), this,
535
        connect(queryText, SIGNAL(activated(const QString&)), this,
531
      SLOT(completionTermChosen(const QString&)));
536
                SLOT(completionTermChosen(const QString&)));
532
    }
537
    }
533
}
538
}
534
539
535
void SSearch::completionTermChosen(const QString& text)
540
void SSearch::completionTermChosen(const QString& text)
536
{
541
{
537
    if (text != "[...]")
542
    if (text != "[...]")
538
  m_chosenCompletion = text;
543
        m_chosenCompletion = text;
539
    else 
544
    else 
540
  m_chosenCompletion.clear();
545
        m_chosenCompletion.clear();
541
}
546
}
542
547
543
void SSearch::wrapupCompletion()
548
void SSearch::wrapupCompletion()
544
{
549
{
545
    LOGDEB("SSearch::wrapupCompletion\n" );
550
    LOGDEB("SSearch::wrapupCompletion\n");
546
551
547
    queryText->clear();
552
    queryText->clear();
548
    queryText->addItems(prefs.ssearchHistory);
553
    queryText->addItems(prefs.ssearchHistory);
549
    if (!m_chosenCompletion.isEmpty()) {
554
    if (!m_chosenCompletion.isEmpty()) {
550
  m_savedEditText.truncate(m_completedWordStart);
555
        m_savedEditText.truncate(m_completedWordStart);
551
  m_savedEditText.append(m_chosenCompletion);
556
        m_savedEditText.append(m_chosenCompletion);
552
    }
557
    }
553
    queryText->setEditText(m_savedEditText);
558
    queryText->setEditText(m_savedEditText);
554
    m_disableAutosearch = true;
559
    m_disableAutosearch = true;
555
    m_savedEditText.clear();
560
    m_savedEditText.clear();
556
    m_chosenCompletion.clear();
561
    m_chosenCompletion.clear();
557
    m_displayingCompletions = false;
562
    m_displayingCompletions = false;
558
    disconnect(queryText, SIGNAL(activated(const QString&)), this,
563
    disconnect(queryText, SIGNAL(activated(const QString&)), this,
559
         SLOT(completionTermChosen(const QString&)));
564
               SLOT(completionTermChosen(const QString&)));
560
}
565
}
561
566
562
#undef SHOWEVENTS
567
#undef SHOWEVENTS
563
#if defined(SHOWEVENTS)
568
#if defined(SHOWEVENTS)
564
const char *eventTypeToStr(int tp)
569
const char *eventTypeToStr(int tp)
...
...
600
    case  37: return "ApplicationLayoutDirectionChange";
605
    case  37: return "ApplicationLayoutDirectionChange";
601
    case  38: return "ApplicationPaletteChange";
606
    case  38: return "ApplicationPaletteChange";
602
    case  39: return "PaletteChange";
607
    case  39: return "PaletteChange";
603
    case  40: return "Clipboard";
608
    case  40: return "Clipboard";
604
    case  42: return "Speech";
609
    case  42: return "Speech";
605
    case   43: return "MetaCall";
610
    case  43: return "MetaCall";
606
    case  50: return "SockAct";
611
    case  50: return "SockAct";
607
    case  132: return "WinEventAct";
612
    case  132: return "WinEventAct";
608
    case  52: return "DeferredDelete";
613
    case  52: return "DeferredDelete";
609
    case  60: return "DragEnter";
614
    case  60: return "DragEnter";
610
    case  61: return "DragMove";
615
    case  61: return "DragMove";
...
...
702
707
703
bool SSearch::eventFilter(QObject *target, QEvent *event)
708
bool SSearch::eventFilter(QObject *target, QEvent *event)
704
{
709
{
705
#if defined(SHOWEVENTS)
710
#if defined(SHOWEVENTS)
706
    if (event->type() == QEvent::Timer || 
711
    if (event->type() == QEvent::Timer || 
707
  event->type() == QEvent::UpdateRequest ||
712
        event->type() == QEvent::UpdateRequest ||
708
  event->type() == QEvent::Paint)
713
        event->type() == QEvent::Paint)
709
  return false;
714
        return false;
710
    LOGDEB2("SSearch::eventFilter: target "  << (target) << " ("  << (queryText->lineEdit()) << ") type "  << (eventTypeToStr(event->type())) << "\n" );
715
    LOGDEB2("SSearch::eventFilter: target " << target << " (" <<
716
            queryText->lineEdit() << ") type " <<
717
            eventTypeToStr(event->type()) << "\n");
711
#endif
718
#endif
712
719
713
    if (target == (QObject*)(queryText->view())) {
720
    if (target == (QObject*)(queryText->view())) {
714
  if (event->type() == QEvent::Hide) {
721
        if (event->type() == QEvent::Hide) {
715
      // List was closed. If we were displaying completions, need
722
            // List was closed. If we were displaying completions, need
716
      // to reset state.
723
            // to reset state.
717
      if (m_displayingCompletions) {
724
            if (m_displayingCompletions) {
718
      QTimer::singleShot(0, this, SLOT(wrapupCompletion()));
725
                QTimer::singleShot(0, this, SLOT(wrapupCompletion()));
719
      }
726
            }
720
  }
727
        }
721
  return false;
728
        return false;
722
    }
729
    }
723
730
724
    if (event->type() == QEvent::KeyPress)  {
731
    if (event->type() == QEvent::KeyPress)  {
725
  QKeyEvent *ke = (QKeyEvent *)event;
732
        QKeyEvent *ke = (QKeyEvent *)event;
726
  LOGDEB1("SSearch::eventFilter: keyPress (m_escape "  << (m_escape) << ") key "  << (ke->key()) << "\n" );
733
        LOGDEB1("SSearch::eventFilter: keyPress (m_escape " << m_escape <<
734
                ") key " << ke->key() << "\n");
727
  if (ke->key() == Qt::Key_Escape) {
735
        if (ke->key() == Qt::Key_Escape) {
728
      LOGDEB("Escape\n" );
736
            LOGDEB("Escape\n");
729
      m_escape = true;
737
            m_escape = true;
730
      m_disableAutosearch = true;
738
            m_disableAutosearch = true;
731
      m_stroketimeout->stop();
739
            m_stroketimeout->stop();
732
      return true;
740
            return true;
733
  } else if (m_escape && ke->key() == Qt::Key_Space) {
741
        } else if (m_escape && ke->key() == Qt::Key_Space) {
734
      LOGDEB("Escape space\n" );
742
            LOGDEB("Escape space\n");
735
      ke->accept();
743
            ke->accept();
736
      completion();
744
            completion();
737
      m_escape = false;
745
            m_escape = false;
738
      m_disableAutosearch = true;
746
            m_disableAutosearch = true;
739
      m_stroketimeout->stop();
747
            m_stroketimeout->stop();
740
      return true;
748
            return true;
741
  } else if (ke->key() == Qt::Key_Space) {
749
        } else if (ke->key() == Qt::Key_Space) {
742
      if (prefs.ssearchOnWS)
750
            if (prefs.ssearchOnWS)
743
      startSimpleSearch();
751
                startSimpleSearch();
744
  } else {
752
        } else {
745
      m_escape = false;
753
            m_escape = false;
746
      m_keystroke = true;
754
            m_keystroke = true;
747
      if (prefs.ssearchAsYouType) {
755
            if (prefs.ssearchAsYouType) {
748
      m_disableAutosearch = false;
756
                m_disableAutosearch = false;
749
      QString qs = queryText->currentText();
757
                QString qs = queryText->currentText();
750
      LOGDEB0("SSearch::eventFilter: start timer, qs ["  << (qs2utf8s(qs)) << "]\n" );
758
                LOGDEB0("SSearch::eventFilter: start timer, qs [" <<
759
                        qs2utf8s(qs) << "]\n");
751
      m_stroketimeout->start(strokeTimeoutMS);
760
                m_stroketimeout->start(strokeTimeoutMS);
752
      }
761
            }
753
  }
762
        }
754
    }
763
    }
755
    return false;
764
    return false;
756
}
765
}
757