summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/src/examples/googlesuggest.qdoc148
-rw-r--r--doc/src/images/googlesuggest-example.pngbin18809 -> 9006 bytes
-rw-r--r--examples/network/googlesuggest/googlesuggest.cpp58
-rw-r--r--examples/network/googlesuggest/googlesuggest.h6
-rw-r--r--examples/network/googlesuggest/searchbox.cpp7
-rw-r--r--examples/network/googlesuggest/searchbox.h2
6 files changed, 191 insertions, 30 deletions
diff --git a/doc/src/examples/googlesuggest.qdoc b/doc/src/examples/googlesuggest.qdoc
index bec242d..f3693e9 100644
--- a/doc/src/examples/googlesuggest.qdoc
+++ b/doc/src/examples/googlesuggest.qdoc
@@ -43,10 +43,152 @@
\example network/googlesuggest
\title Google Suggest Example
- The Google Suggest example shows how to use the network access manager
- to get the list of suggested search terms from Google.
+ The Google Suggest example demonstrates how to use the QNetworkAccessManager
+ class to obtain a list of suggestions from the Google search engine as the
+ user types into a QLineEdit.
\image googlesuggest-example.png
- \note The Google Suggest suggestion service is a registered trademark of Google Inc.
+ The application makes use of the \c get function in
+QNetworkAccessManager to post a request and obtain the result of the search
+query sent to the Google search engine. The results returned are listed as
+clickable links appearing below the search box as a drop-down menu.
+
+The widget is built up by a QLineEdit as the search box, and a QTreeView
+used as a popup menu below the search box.
+
+\section1 GSuggestCompletion Class Declaration
+
+This class implements an event filter and a number of functions to display
+the search results and to determent when and how to perform the search.
+
+\snippet examples/network/googlesuggest/googlesuggest.h 1
+
+The class connects to a QLineEdit and uses a QTreeWidget to display the
+results. A QTimer controls the start of the network requests that are
+executed using a QNetworkAccessManager.
+
+\section1 GSuggestCompletion Class Implementation
+
+We start by defining a constant containing the URL to be used in the Google
+queries. This is the basis for the query. The letters typed into the search
+box will be added to the query to perform the search itself.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 1
+
+In the constructor, we set the parent of this GSuggestCompletion instance
+to be the QLineEdit passed in. For simplicity, the QLineEdit is also stored
+in the explicit \c editor member variable.
+
+We then create a QTreeWidget as a toplevel widget and configure the various
+properties to give it the look of a popup widget.
+
+The popup will be populated by the results returned from Google. We set
+the number of columns to be two, since we want to display both the
+suggested search term and the number of hits it will trigger in the search
+engine.
+
+Furthermore, we install the GSuggestCompletion instance as an event filter
+on the QTreeWidget, and connect the \c itemClicked() signal with the \c
+doneCompletion() slot.
+
+A single-shot QTimer is used to start the request when the user has stopped
+typing for 500 ms.
+
+Finally, we connect the networkManagers \c finished() signal with the \c
+handleNetworkData() slot to handle the incoming data.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 2
+
+Since the QTreeWidget popup has been instantiated as a toplevel widget, the
+destructor has to delete it explicitly from memory to avoid a memory leak.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 3
+
+The event filter handles mouse press and key press events that are
+delivered to the popup. For mouse press events we just hide the popup and
+return focus to the editor widget, and then return true to prevent further
+event processing.
+
+Key event handling is implemented so that Enter and Return execute the
+selected link, while the Escape key hides the popup. Sine we want to be
+able to navigate the list of suggestions using the different navigation
+keys on the keyboard we let Qt continue regular event processing for those
+by returning false from the eventFilter reimplementation.
+
+For all other keys, the event will be passed on to the editor widget and the
+popup is hidden. This way the user's typing will not be interrupted by the
+popping up of the completion list.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 4
+
+The \c showCompletion() function populates the QTreeWidget with the results
+returned from the query. It takes two QStringLists, one with the suggested
+search terms and the other with the corresponding number of hits.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 5
+
+A QTreeWidgetItem is created for each index in the list and inserted into
+the QTreeWidget. Finally, we adjust position and size of the popup to make
+sure that it pops up in the correct position below the editor, and show it.
+
+The \c doneCompletion() function, which is called by the event filter when
+either Enter or Return keys are pressed, stops the timer to prevent further
+requests and passes the text of the selected item to the editor. We then
+make the \c editor QLineEdit emit the returnPressed() signal, to which the
+application can connect to open the respective web page.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 6
+
+The \c autoSuggest() slot is called when the timer times out, and uses the
+text in the editor to build the complete search query. The query is then
+passed to the QNetworkAccessManager's \c get() function to start the
+request.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 7
+
+The function \c preventSuggest() stops the timer to prevent further
+requests from being started.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 8
+
+When the network request is finished, the QNetworkAccessManager delivers the
+data received from the server through the networkReply object.
+
+\snippet examples/network/googlesuggest/googlesuggest.cpp 9
+
+To extract the data from the reply we use the \c readAll() function, which
+is inherited from QIODevice and returns a QByteArray. Since this data is
+encoded in XML we can use a QXmlStreamReader to traverse the data and
+extract the search result as QStrings, which we can stream into two
+QStringLists used to populate the popup.
+
+Finally, we schedule the QNetworkReply object for deletion using the \c
+deleteLater function.
+
+\section1 SearchBox Class Declaration
+
+The SearchBox class inherits QLineEdit and adds the protected slot \c
+doSearch().
+
+A \c GSuggestCompletion member provides the SearchBox with the request
+functionality and the suggestions returned from the Google search engine.
+
+\snippet examples/network/googlesuggest/searchbox.h 1
+
+\section1 SearchBox Class Implementation
+
+The search box constructor instantiates the GSuggestCompletion object and
+connects the returnPressed() signal to the doSearch() slot.
+
+\snippet examples/network/googlesuggest/searchbox.cpp 1
+
+The function \c doSearch() stops the completer from sending any further
+queries to the search engine.
+
+Further, the function extracts the selected search phrase and opens it in
+the default web browser using QDesktopServices.
+
+\snippet examples/network/googlesuggest/searchbox.cpp 2
+
*/
diff --git a/doc/src/images/googlesuggest-example.png b/doc/src/images/googlesuggest-example.png
index 4ef072a..477d444 100644
--- a/doc/src/images/googlesuggest-example.png
+++ b/doc/src/images/googlesuggest-example.png
Binary files differ
diff --git a/examples/network/googlesuggest/googlesuggest.cpp b/examples/network/googlesuggest/googlesuggest.cpp
index e1588a6..a1075ec 100644
--- a/examples/network/googlesuggest/googlesuggest.cpp
+++ b/examples/network/googlesuggest/googlesuggest.cpp
@@ -39,17 +39,22 @@
**
****************************************************************************/
-#include <QtCore>
-#include <QtGui>
-#include <QtNetwork>
+//! [1]
#include "googlesuggest.h"
#define GSUGGEST_URL "http://google.com/complete/search?output=toolbar&q=%1"
+//! [1]
+//! [2]
GSuggestCompletion::GSuggestCompletion(QLineEdit *parent): QObject(parent), editor(parent)
{
popup = new QTreeWidget;
+ popup->setWindowFlags(Qt::Popup);
+ popup->setFocusPolicy(Qt::NoFocus);
+ popup->setFocusProxy(parent);
+ popup->setMouseTracking(true);
+
popup->setColumnCount(2);
popup->setUniformRowHeights(true);
popup->setRootIsDecorated(false);
@@ -57,18 +62,13 @@ GSuggestCompletion::GSuggestCompletion(QLineEdit *parent): QObject(parent), edit
popup->setSelectionBehavior(QTreeWidget::SelectRows);
popup->setFrameStyle(QFrame::Box | QFrame::Plain);
popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-
popup->header()->hide();
+
popup->installEventFilter(this);
- popup->setMouseTracking(true);
connect(popup, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
SLOT(doneCompletion()));
- popup->setWindowFlags(Qt::Popup);
- popup->setFocusPolicy(Qt::NoFocus);
- popup->setFocusProxy(parent);
-
timer = new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(500);
@@ -79,12 +79,16 @@ GSuggestCompletion::GSuggestCompletion(QLineEdit *parent): QObject(parent), edit
this, SLOT(handleNetworkData(QNetworkReply*)));
}
+//! [2]
+//! [3]
GSuggestCompletion::~GSuggestCompletion()
{
delete popup;
}
+//! [3]
+//! [4]
bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev)
{
if (obj != popup)
@@ -131,9 +135,12 @@ bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev)
return false;
}
+//! [4]
+//! [5]
void GSuggestCompletion::showCompletion(const QStringList &choices, const QStringList &hits)
{
+
if (choices.isEmpty() || choices.count() != hits.count())
return;
@@ -163,7 +170,9 @@ void GSuggestCompletion::showCompletion(const QStringList &choices, const QStrin
popup->setFocus();
popup->show();
}
+//! [5]
+//! [6]
void GSuggestCompletion::doneCompletion()
{
timer->stop();
@@ -172,26 +181,28 @@ void GSuggestCompletion::doneCompletion()
QTreeWidgetItem *item = popup->currentItem();
if (item) {
editor->setText(item->text(0));
- QKeyEvent *e;
- e = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
- QApplication::postEvent(editor, e);
- e = new QKeyEvent(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier);
- QApplication::postEvent(editor, e);
+ QMetaObject::invokeMethod(editor, "returnPressed");
}
}
+//! [6]
-void GSuggestCompletion::preventSuggest()
-{
- timer->stop();
-}
-
+//! [7]
void GSuggestCompletion::autoSuggest()
{
QString str = editor->text();
QString url = QString(GSUGGEST_URL).arg(str);
networkManager.get(QNetworkRequest(QString(url)));
}
+//! [7]
+
+//! [8]
+void GSuggestCompletion::preventSuggest()
+{
+ timer->stop();
+}
+//! [8]
+//! [9]
void GSuggestCompletion::handleNetworkData(QNetworkReply *networkReply)
{
QUrl url = networkReply->url();
@@ -199,20 +210,20 @@ void GSuggestCompletion::handleNetworkData(QNetworkReply *networkReply)
QStringList choices;
QStringList hits;
- QString response(networkReply->readAll());
+ QByteArray response(networkReply->readAll());
QXmlStreamReader xml(response);
while (!xml.atEnd()) {
xml.readNext();
- if (xml.isStartElement()) {
+ if (xml.tokenType() == QXmlStreamReader::StartElement)
if (xml.name() == "suggestion") {
QStringRef str = xml.attributes().value("data");
choices << str.toString();
}
- else if (xml.name() == "num_queries") {
+ if (xml.tokenType() == QXmlStreamReader::StartElement)
+ if (xml.name() == "num_queries") {
QStringRef str = xml.attributes().value("int");
hits << str.toString();
}
- }
}
showCompletion(choices, hits);
@@ -220,3 +231,4 @@ void GSuggestCompletion::handleNetworkData(QNetworkReply *networkReply)
networkReply->deleteLater();
}
+//! [9] \ No newline at end of file
diff --git a/examples/network/googlesuggest/googlesuggest.h b/examples/network/googlesuggest/googlesuggest.h
index 2a3c878..c33df36 100644
--- a/examples/network/googlesuggest/googlesuggest.h
+++ b/examples/network/googlesuggest/googlesuggest.h
@@ -42,8 +42,9 @@
#ifndef GOOGLESUGGEST_H
#define GOOGLESUGGEST_H
+#include <QtGui>
+#include <QtNetwork>
#include <QObject>
-#include <QNetworkAccessManager>
QT_BEGIN_NAMESPACE
class QLineEdit;
@@ -52,6 +53,7 @@ class QTimer;
class QTreeWidget;
QT_END_NAMESPACE
+//! [1]
class GSuggestCompletion : public QObject
{
Q_OBJECT
@@ -75,6 +77,6 @@ private:
QTimer *timer;
QNetworkAccessManager networkManager;
};
-
+//! [1]
#endif // GOOGLESUGGEST_H
diff --git a/examples/network/googlesuggest/searchbox.cpp b/examples/network/googlesuggest/searchbox.cpp
index 21599e0..ae08a75 100644
--- a/examples/network/googlesuggest/searchbox.cpp
+++ b/examples/network/googlesuggest/searchbox.cpp
@@ -47,12 +47,12 @@
#define GSEARCH_URL "http://www.google.com/search?q=%1"
-
+//! [1]
SearchBox::SearchBox(QWidget *parent): QLineEdit(parent)
{
completer = new GSuggestCompletion(this);
- connect(this, SIGNAL(returnPressed()), SLOT(doSearch()));
+ connect(this, SIGNAL(returnPressed()),this, SLOT(doSearch()));
setWindowTitle("Search with Google");
@@ -60,10 +60,13 @@ SearchBox::SearchBox(QWidget *parent): QLineEdit(parent)
resize(400, height());
setFocus();
}
+//! [1]
+//! [2]
void SearchBox::doSearch()
{
completer->preventSuggest();
QString url = QString(GSEARCH_URL).arg(text());
QDesktopServices::openUrl(QUrl(url));
}
+//! [2] \ No newline at end of file
diff --git a/examples/network/googlesuggest/searchbox.h b/examples/network/googlesuggest/searchbox.h
index 4b03dba..ec18bb0 100644
--- a/examples/network/googlesuggest/searchbox.h
+++ b/examples/network/googlesuggest/searchbox.h
@@ -42,6 +42,7 @@
#ifndef SEARCHBOX_H
#define SEARCHBOX_H
+//! [1]
#include <QLineEdit>
class GSuggestCompletion;
@@ -58,6 +59,7 @@ protected slots:
private:
GSuggestCompletion *completer;
+//! [1]
};