source: trunk/tools/assistant/lib/qhelpsearchquerywidget.cpp@ 966

Last change on this file since 966 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 18.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the Qt Assistant of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qhelpsearchquerywidget.h"
43
44#include <QtCore/QAbstractListModel>
45#include <QtCore/QObject>
46#include <QtCore/QStringList>
47#include <QtCore/QtGlobal>
48
49#include <QtGui/QCompleter>
50#include <QtGui/QLabel>
51#include <QtGui/QLayout>
52#include <QtGui/QLineEdit>
53#include <QtGui/QFocusEvent>
54#include <QtGui/QPushButton>
55#include <QtGui/QToolButton>
56
57QT_BEGIN_NAMESPACE
58
59class QHelpSearchQueryWidgetPrivate : public QObject
60{
61 Q_OBJECT
62
63private:
64 struct QueryHistory {
65 explicit QueryHistory() : curQuery(-1) {}
66 QList<QList<QHelpSearchQuery> > queries;
67 int curQuery;
68 };
69
70 class CompleterModel : public QAbstractListModel
71 {
72 public:
73 explicit CompleterModel(QObject *parent)
74 : QAbstractListModel(parent) {}
75
76 int rowCount(const QModelIndex &parent = QModelIndex()) const
77 {
78 return parent.isValid() ? 0 : termList.size();
79 }
80
81 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
82 {
83 if (!index.isValid() || index.row() >= termList.count()||
84 (role != Qt::EditRole && role != Qt::DisplayRole))
85 return QVariant();
86 return termList.at(index.row());
87 }
88
89 void addTerm(const QString &term)
90 {
91 if (!termList.contains(term)) {
92 termList.append(term);
93 reset();
94 }
95 }
96
97 private:
98 QStringList termList;
99 };
100
101 QHelpSearchQueryWidgetPrivate()
102 : QObject()
103 , simpleSearch(true)
104 , searchCompleter(new CompleterModel(this), this)
105 {
106 searchButton = 0;
107 advancedSearchWidget = 0;
108 showHideAdvancedSearchButton = 0;
109 defaultQuery = 0;
110 exactQuery = 0;
111 similarQuery = 0;
112 withoutQuery = 0;
113 allQuery = 0;
114 atLeastQuery = 0;
115 }
116
117 ~QHelpSearchQueryWidgetPrivate()
118 {
119 // nothing todo
120 }
121
122 void retranslate()
123 {
124 simpleSearchLabel->setText(QHelpSearchQueryWidget::tr("Search for:"));
125 prevQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Previous search"));
126 nextQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Next search"));
127 searchButton->setText(QHelpSearchQueryWidget::tr("Search"));
128#ifdef QT_CLUCENE_SUPPORT
129 advancedSearchLabel->setText(QHelpSearchQueryWidget::tr("Advanced search"));
130 similarLabel->setText(QHelpSearchQueryWidget::tr("words <B>similar</B> to:"));
131 withoutLabel->setText(QHelpSearchQueryWidget::tr("<B>without</B> the words:"));
132 exactLabel->setText(QHelpSearchQueryWidget::tr("with <B>exact phrase</B>:"));
133 allLabel->setText(QHelpSearchQueryWidget::tr("with <B>all</B> of the words:"));
134 atLeastLabel->setText(QHelpSearchQueryWidget::tr("with <B>at least one</B> of the words:"));
135#endif
136 }
137
138 QStringList buildTermList(const QString query)
139 {
140 bool s = false;
141 QString phrase;
142 QStringList wordList;
143 QString searchTerm = query;
144
145 for (int i = 0; i < searchTerm.length(); ++i) {
146 if (searchTerm[i] == QLatin1Char('\"') && !s) {
147 s = true;
148 phrase = searchTerm[i];
149 continue;
150 }
151 if (searchTerm[i] != QLatin1Char('\"') && s)
152 phrase += searchTerm[i];
153 if (searchTerm[i] == QLatin1Char('\"') && s) {
154 s = false;
155 phrase += searchTerm[i];
156 wordList.append(phrase);
157 searchTerm.remove(phrase);
158 }
159 }
160 if (s)
161 searchTerm.replace(phrase, phrase.mid(1));
162
163 const QRegExp exp(QLatin1String("\\s+"));
164 wordList += searchTerm.split(exp, QString::SkipEmptyParts);
165 return wordList;
166 }
167
168 void saveQuery(const QList<QHelpSearchQuery> &query, QueryHistory &queryHist)
169 {
170 // We only add the query to the list if it is different from the last one.
171 bool insert = false;
172 if (queryHist.queries.empty())
173 insert = true;
174 else {
175 const QList<QHelpSearchQuery> &lastQuery = queryHist.queries.last();
176 if (lastQuery.size() != query.size()) {
177 insert = true;
178 } else {
179 for (int i = 0; i < query.size(); ++i) {
180 if (query.at(i).fieldName != lastQuery.at(i).fieldName
181 || query.at(i).wordList != lastQuery.at(i).wordList) {
182 insert = true;
183 break;
184 }
185 }
186 }
187 }
188 if (insert) {
189 queryHist.queries.append(query);
190 foreach (const QHelpSearchQuery &queryPart, query) {
191 static_cast<CompleterModel *>(searchCompleter.model())->
192 addTerm(queryPart.wordList.join(" "));
193 }
194 }
195 }
196
197 void nextOrPrevQuery(int maxOrMinIndex, int addend, QToolButton *thisButton,
198 QToolButton *otherButton)
199 {
200 QueryHistory *queryHist;
201 QList<QLineEdit *> lineEdits;
202 if (simpleSearch) {
203 queryHist = &simpleQueries;
204 lineEdits << defaultQuery;
205 } else {
206 queryHist = &complexQueries;
207 lineEdits << allQuery << atLeastQuery << similarQuery
208 << withoutQuery << exactQuery;
209 }
210 foreach (QLineEdit *lineEdit, lineEdits)
211 lineEdit->clear();
212
213 // Otherwise, the respective button would be disabled.
214 Q_ASSERT(queryHist->curQuery != maxOrMinIndex);
215
216 queryHist->curQuery += addend;
217 const QList<QHelpSearchQuery> &query =
218 queryHist->queries.at(queryHist->curQuery);
219 foreach (const QHelpSearchQuery &queryPart, query) {
220 QLineEdit *lineEdit = 0;
221 switch (queryPart.fieldName) {
222 case QHelpSearchQuery::DEFAULT:
223 lineEdit = defaultQuery;
224 break;
225 case QHelpSearchQuery::ALL:
226 lineEdit = allQuery;
227 break;
228 case QHelpSearchQuery::ATLEAST:
229 lineEdit = atLeastQuery;
230 break;
231 case QHelpSearchQuery::FUZZY:
232 lineEdit = similarQuery;
233 break;
234 case QHelpSearchQuery::WITHOUT:
235 lineEdit = withoutQuery;
236 break;
237 case QHelpSearchQuery::PHRASE:
238 lineEdit = exactQuery;
239 break;
240 default:
241 Q_ASSERT(0);
242 }
243 lineEdit->setText(queryPart.wordList.join(" "));
244 }
245
246 if (queryHist->curQuery == maxOrMinIndex)
247 thisButton->setEnabled(false);
248 otherButton->setEnabled(true);
249 }
250
251 void enableOrDisableToolButtons()
252 {
253 const QueryHistory &queryHist = simpleSearch ? simpleQueries
254 : complexQueries;
255 prevQueryButton->setEnabled(queryHist.curQuery > 0);
256 nextQueryButton->setEnabled(queryHist.curQuery
257 < queryHist.queries.size() - 1);
258 }
259
260private slots:
261 void showHideAdvancedSearch()
262 {
263 if (simpleSearch) {
264 advancedSearchWidget->show();
265 showHideAdvancedSearchButton->setText((QLatin1String("-")));
266 } else {
267 advancedSearchWidget->hide();
268 showHideAdvancedSearchButton->setText((QLatin1String("+")));
269 }
270
271 simpleSearch = !simpleSearch;
272 defaultQuery->setEnabled(simpleSearch);
273 enableOrDisableToolButtons();
274 }
275
276 void searchRequested()
277 {
278 QList<QHelpSearchQuery> queryList;
279#if !defined(QT_CLUCENE_SUPPORT)
280 queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT,
281 QStringList(defaultQuery->text())));
282
283#else
284 if (defaultQuery->isEnabled()) {
285 queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT,
286 buildTermList(defaultQuery->text())));
287 } else {
288 const QRegExp exp(QLatin1String("\\s+"));
289 QStringList lst = similarQuery->text().split(exp,
290 QString::SkipEmptyParts);
291 if (!lst.isEmpty()) {
292 QStringList fuzzy;
293 foreach (const QString &term, lst)
294 fuzzy += buildTermList(term);
295 queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY,
296 fuzzy));
297 }
298
299 lst = withoutQuery->text().split(exp, QString::SkipEmptyParts);
300 if (!lst.isEmpty()) {
301 QStringList without;
302 foreach (const QString &term, lst)
303 without.append(term);
304 queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT,
305 without));
306 }
307
308 if (!exactQuery->text().isEmpty()) {
309 QString phrase = exactQuery->text().remove(QLatin1Char('\"'));
310 phrase = phrase.simplified();
311 queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE,
312 QStringList(phrase)));
313 }
314
315 lst = allQuery->text().split(exp, QString::SkipEmptyParts);
316 if (!lst.isEmpty()) {
317 QStringList all;
318 foreach (const QString &term, lst)
319 all.append(term);
320 queryList.append(QHelpSearchQuery(QHelpSearchQuery::ALL, all));
321 }
322
323 lst = atLeastQuery->text().split(exp, QString::SkipEmptyParts);
324 if (!lst.isEmpty()) {
325 QStringList atLeast;
326 foreach (const QString &term, lst)
327 atLeast += buildTermList(term);
328 queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST,
329 atLeast));
330 }
331 }
332#endif
333 QueryHistory &queryHist = simpleSearch ? simpleQueries : complexQueries;
334 saveQuery(queryList, queryHist);
335 queryHist.curQuery = queryHist.queries.size() - 1;
336 if (queryHist.curQuery > 0)
337 prevQueryButton->setEnabled(true);
338 nextQueryButton->setEnabled(false);
339 }
340
341 void nextQuery()
342 {
343 nextOrPrevQuery((simpleSearch ? simpleQueries
344 : complexQueries).queries.size() - 1, 1, nextQueryButton,
345 prevQueryButton);
346 }
347
348 void prevQuery()
349 {
350 nextOrPrevQuery(0, -1, prevQueryButton, nextQueryButton);
351 }
352
353private:
354 friend class QHelpSearchQueryWidget;
355
356 bool simpleSearch;
357 QLabel *simpleSearchLabel;
358 QLabel *advancedSearchLabel;
359 QLabel *similarLabel;
360 QLabel *withoutLabel;
361 QLabel *exactLabel;
362 QLabel *allLabel;
363 QLabel *atLeastLabel;
364 QPushButton *searchButton;
365 QWidget* advancedSearchWidget;
366 QToolButton *showHideAdvancedSearchButton;
367 QLineEdit *defaultQuery;
368 QLineEdit *exactQuery;
369 QLineEdit *similarQuery;
370 QLineEdit *withoutQuery;
371 QLineEdit *allQuery;
372 QLineEdit *atLeastQuery;
373 QToolButton *nextQueryButton;
374 QToolButton *prevQueryButton;
375 QueryHistory simpleQueries;
376 QueryHistory complexQueries;
377 QCompleter searchCompleter;
378};
379
380#include "qhelpsearchquerywidget.moc"
381
382
383/*!
384 \class QHelpSearchQueryWidget
385 \since 4.4
386 \inmodule QtHelp
387 \brief The QHelpSearchQueryWidget class provides a simple line edit or
388 an advanced widget to enable the user to input a search term in a
389 standardized input mask.
390*/
391
392/*!
393 \fn void QHelpSearchQueryWidget::search()
394
395 This signal is emitted when a the user has the search button invoked.
396 After reciving the signal you can ask the QHelpSearchQueryWidget for the
397 build list of QHelpSearchQuery's that you may pass to the QHelpSearchEngine's
398 search() function.
399*/
400
401/*!
402 Constructs a new search query widget with the given \a parent.
403*/
404QHelpSearchQueryWidget::QHelpSearchQueryWidget(QWidget *parent)
405 : QWidget(parent)
406{
407 d = new QHelpSearchQueryWidgetPrivate();
408
409 QVBoxLayout *vLayout = new QVBoxLayout(this);
410 vLayout->setMargin(0);
411
412 QHBoxLayout* hBoxLayout = new QHBoxLayout();
413 d->simpleSearchLabel = new QLabel(this);
414 d->defaultQuery = new QLineEdit(this);
415 d->defaultQuery->setCompleter(&d->searchCompleter);
416 d->prevQueryButton = new QToolButton(this);
417 d->prevQueryButton->setArrowType(Qt::LeftArrow);
418 d->prevQueryButton->setEnabled(false);
419 d->nextQueryButton = new QToolButton(this);
420 d->nextQueryButton->setArrowType(Qt::RightArrow);
421 d->nextQueryButton->setEnabled(false);
422 d->searchButton = new QPushButton(this);
423 hBoxLayout->addWidget(d->simpleSearchLabel);
424 hBoxLayout->addWidget(d->defaultQuery);
425 hBoxLayout->addWidget(d->prevQueryButton);
426 hBoxLayout->addWidget(d->nextQueryButton);
427 hBoxLayout->addWidget(d->searchButton);
428
429 vLayout->addLayout(hBoxLayout);
430
431 connect(d->prevQueryButton, SIGNAL(clicked()), d, SLOT(prevQuery()));
432 connect(d->nextQueryButton, SIGNAL(clicked()), d, SLOT(nextQuery()));
433 connect(d->searchButton, SIGNAL(clicked()), this, SIGNAL(search()));
434 connect(d->defaultQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
435
436#if defined(QT_CLUCENE_SUPPORT)
437 hBoxLayout = new QHBoxLayout();
438 d->showHideAdvancedSearchButton = new QToolButton(this);
439 d->showHideAdvancedSearchButton->setText(QLatin1String("+"));
440 d->showHideAdvancedSearchButton->setMinimumSize(25, 20);
441
442 d->advancedSearchLabel = new QLabel(this);
443 QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
444 sizePolicy.setHeightForWidth(d->advancedSearchLabel->sizePolicy().hasHeightForWidth());
445 d->advancedSearchLabel->setSizePolicy(sizePolicy);
446
447 QFrame* hLine = new QFrame(this);
448 hLine->setFrameStyle(QFrame::HLine);
449 hBoxLayout->addWidget(d->showHideAdvancedSearchButton);
450 hBoxLayout->addWidget(d->advancedSearchLabel);
451 hBoxLayout->addWidget(hLine);
452
453 vLayout->addLayout(hBoxLayout);
454
455 // setup advanced search layout
456 d->advancedSearchWidget = new QWidget(this);
457 QGridLayout *gLayout = new QGridLayout(d->advancedSearchWidget);
458 gLayout->setMargin(0);
459
460 d->similarLabel = new QLabel(this);
461 gLayout->addWidget(d->similarLabel, 0, 0);
462 d->similarQuery = new QLineEdit(this);
463 d->similarQuery->setCompleter(&d->searchCompleter);
464 gLayout->addWidget(d->similarQuery, 0, 1);
465
466 d->withoutLabel = new QLabel(this);
467 gLayout->addWidget(d->withoutLabel, 1, 0);
468 d->withoutQuery = new QLineEdit(this);
469 d->withoutQuery->setCompleter(&d->searchCompleter);
470 gLayout->addWidget(d->withoutQuery, 1, 1);
471
472 d->exactLabel = new QLabel(this);
473 gLayout->addWidget(d->exactLabel, 2, 0);
474 d->exactQuery = new QLineEdit(this);
475 d->exactQuery->setCompleter(&d->searchCompleter);
476 gLayout->addWidget(d->exactQuery, 2, 1);
477
478 d->allLabel = new QLabel(this);
479 gLayout->addWidget(d->allLabel, 3, 0);
480 d->allQuery = new QLineEdit(this);
481 d->allQuery->setCompleter(&d->searchCompleter);
482 gLayout->addWidget(d->allQuery, 3, 1);
483
484 d->atLeastLabel = new QLabel(this);
485 gLayout->addWidget(d->atLeastLabel, 4, 0);
486 d->atLeastQuery = new QLineEdit(this);
487 d->atLeastQuery->setCompleter(&d->searchCompleter);
488 gLayout->addWidget(d->atLeastQuery, 4, 1);
489
490 vLayout->addWidget(d->advancedSearchWidget);
491 d->advancedSearchWidget->hide();
492
493 d->retranslate();
494
495 connect(d->exactQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
496 connect(d->similarQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
497 connect(d->withoutQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
498 connect(d->allQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
499 connect(d->atLeastQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
500 connect(d->showHideAdvancedSearchButton, SIGNAL(clicked()),
501 d, SLOT(showHideAdvancedSearch()));
502#endif
503 connect(this, SIGNAL(search()), d, SLOT(searchRequested()));
504}
505
506/*!
507 Destroys the search query widget.
508*/
509QHelpSearchQueryWidget::~QHelpSearchQueryWidget()
510{
511 delete d;
512}
513
514/*!
515 Returns a list of queries to use in combination with the search engines
516 search(QList<QHelpSearchQuery> &query) function.
517*/
518QList<QHelpSearchQuery> QHelpSearchQueryWidget::query() const
519{
520 const QHelpSearchQueryWidgetPrivate::QueryHistory &queryHist =
521 d->simpleSearch ? d->simpleQueries : d->complexQueries;
522 return queryHist.queries.isEmpty() ?
523 QList<QHelpSearchQuery>() : queryHist.queries.last();
524}
525
526/*!
527 \reimp
528*/
529void QHelpSearchQueryWidget::focusInEvent(QFocusEvent *focusEvent)
530{
531 if (focusEvent->reason() != Qt::MouseFocusReason) {
532 d->defaultQuery->selectAll();
533 d->defaultQuery->setFocus();
534 }
535}
536
537/*! \reimp
538*/
539void QHelpSearchQueryWidget::changeEvent(QEvent *event)
540{
541 if (event->type() == QEvent::LanguageChange)
542 d->retranslate();
543 else
544 QWidget::changeEvent(event);
545}
546
547QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.