Delete googlesuggest

As a networking example it doesn't contribute much. But it has some
interesting uses of widget/events

Pick-to: 6.5
Change-Id: I194d32e6a304ae41819c20751e9f1ee1d9b5abdb
Reviewed-by: Konrad Kujawa <konrad.kujawa@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
This commit is contained in:
Mårten Nordheim 2023-01-25 11:56:21 +01:00
parent c20336fe03
commit 2145341071
12 changed files with 0 additions and 501 deletions

View File

@ -16,7 +16,6 @@ if(TARGET Qt6::Widgets)
qt_internal_add_example(http)
qt_internal_add_example(loopback)
qt_internal_add_example(threadedfortuneserver)
qt_internal_add_example(googlesuggest)
qt_internal_add_example(torrent)
qt_internal_add_example(multicastreceiver)
qt_internal_add_example(multicastsender)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,153 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example googlesuggest
\title Google Suggest Example
\ingroup examples-network
\brief Obtains the list of search recommendations by the Google search engine.
The example uses the QNetworkAccessManager to obtain the list of search
recommendations by Google as the user types into a QLineEdit.
\image googlesuggest-example.png
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 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 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 widget is populated
with the results by Google Suggest API request.
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 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 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. Since 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 googlesuggest/googlesuggest.cpp 4
The \c showCompletion() function populates the QTreeWidget with the results
returned from the query. It takes a QStringList of the suggested search
terms.
\snippet 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 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 googlesuggest/googlesuggest.cpp 7
The function \c preventSuggest() stops the timer to prevent further
requests from being started.
\snippet googlesuggest/googlesuggest.cpp 8
When the network request is finished, the QNetworkAccessManager delivers the
data received from the server through the networkReply object.
\snippet 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 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 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 googlesuggest/searchbox.cpp 2
*/

View File

@ -1,39 +0,0 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(googlesuggest LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/network/googlesuggest")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets)
qt_standard_project_setup()
qt_add_executable(googlesuggest
googlesuggest.cpp googlesuggest.h
main.cpp
searchbox.cpp searchbox.h
)
set_target_properties(googlesuggest PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(googlesuggest PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Network
Qt6::Widgets
)
install(TARGETS googlesuggest
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -1,184 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "googlesuggest.h"
//! [1]
const QString gsuggestUrl(QStringLiteral("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(1);
popup->setUniformRowHeights(true);
popup->setRootIsDecorated(false);
popup->setEditTriggers(QTreeWidget::NoEditTriggers);
popup->setSelectionBehavior(QTreeWidget::SelectRows);
popup->setFrameStyle(QFrame::Box | QFrame::Plain);
popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
popup->header()->hide();
popup->installEventFilter(this);
connect(popup, &QTreeWidget::itemClicked,
this, &GSuggestCompletion::doneCompletion);
timer.setSingleShot(true);
timer.setInterval(500);
connect(&timer, &QTimer::timeout,
this, &GSuggestCompletion::autoSuggest);
connect(editor, &QLineEdit::textEdited,
&timer, QOverload<>::of(&QTimer::start));
connect(&networkManager, &QNetworkAccessManager::finished,
this, &GSuggestCompletion::handleNetworkData);
}
//! [2]
//! [3]
GSuggestCompletion::~GSuggestCompletion()
{
delete popup;
}
//! [3]
//! [4]
bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev)
{
if (obj != popup)
return false;
if (ev->type() == QEvent::MouseButtonPress) {
popup->hide();
editor->setFocus();
return true;
}
if (ev->type() == QEvent::KeyPress) {
bool consumed = false;
int key = static_cast<QKeyEvent*>(ev)->key();
switch (key) {
case Qt::Key_Enter:
case Qt::Key_Return:
doneCompletion();
consumed = true;
break;
case Qt::Key_Escape:
editor->setFocus();
popup->hide();
consumed = true;
break;
case Qt::Key_Up:
case Qt::Key_Down:
case Qt::Key_Home:
case Qt::Key_End:
case Qt::Key_PageUp:
case Qt::Key_PageDown:
break;
default:
editor->setFocus();
editor->event(ev);
popup->hide();
break;
}
return consumed;
}
return false;
}
//! [4]
//! [5]
void GSuggestCompletion::showCompletion(const QList<QString> &choices)
{
if (choices.isEmpty())
return;
const QPalette &pal = editor->palette();
QColor color = pal.color(QPalette::Disabled, QPalette::WindowText);
popup->setUpdatesEnabled(false);
popup->clear();
for (const auto &choice : choices) {
auto item = new QTreeWidgetItem(popup);
item->setText(0, choice);
item->setForeground(0, color);
}
popup->setCurrentItem(popup->topLevelItem(0));
popup->resizeColumnToContents(0);
popup->setUpdatesEnabled(true);
popup->move(editor->mapToGlobal(QPoint(0, editor->height())));
popup->setFocus();
popup->show();
}
//! [5]
//! [6]
void GSuggestCompletion::doneCompletion()
{
timer.stop();
popup->hide();
editor->setFocus();
QTreeWidgetItem *item = popup->currentItem();
if (item) {
editor->setText(item->text(0));
QMetaObject::invokeMethod(editor, "returnPressed");
}
}
//! [6]
//! [7]
void GSuggestCompletion::autoSuggest()
{
QString str = editor->text();
QString url = gsuggestUrl.arg(str);
networkManager.get(QNetworkRequest(url));
}
//! [7]
//! [8]
void GSuggestCompletion::preventSuggest()
{
timer.stop();
}
//! [8]
//! [9]
void GSuggestCompletion::handleNetworkData(QNetworkReply *networkReply)
{
QUrl url = networkReply->url();
if (networkReply->error() == QNetworkReply::NoError) {
QList<QString> choices;
QByteArray response(networkReply->readAll());
QXmlStreamReader xml(response);
while (!xml.atEnd()) {
xml.readNext();
if (xml.tokenType() == QXmlStreamReader::StartElement)
if (xml.name() == u"suggestion") {
auto str = xml.attributes().value("data");
choices << str.toString();
}
}
showCompletion(choices);
}
networkReply->deleteLater();
}
//! [9]

View File

@ -1,37 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef GOOGLESUGGEST_H
#define GOOGLESUGGEST_H
#include <QtWidgets>
#include <QtNetwork>
#include <QtCore>
//! [1]
class GSuggestCompletion : public QObject
{
Q_OBJECT
public:
explicit GSuggestCompletion(QLineEdit *parent = nullptr);
~GSuggestCompletion();
bool eventFilter(QObject *obj, QEvent *ev) override;
void showCompletion(const QList<QString> &choices);
public slots:
void doneCompletion();
void preventSuggest();
void autoSuggest();
void handleNetworkData(QNetworkReply *networkReply);
private:
QLineEdit *editor = nullptr;
QTreeWidget *popup = nullptr;
QTimer timer;
QNetworkAccessManager networkManager;
};
//! [1]
#endif // GOOGLESUGGEST_H

View File

@ -1,8 +0,0 @@
QT += network widgets
requires(qtConfig(itemviews))
SOURCES = main.cpp searchbox.cpp googlesuggest.cpp
HEADERS = searchbox.h googlesuggest.h
# install
target.path = $$[QT_INSTALL_EXAMPLES]/network/googlesuggest
INSTALLS += target

View File

@ -1,14 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include "searchbox.h"
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
SearchBox searchEdit;
searchEdit.show();
return app.exec();
}

View File

@ -1,35 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QDesktopServices>
#include <QUrl>
#include "searchbox.h"
#include "googlesuggest.h"
const QString gsearchUrl = QStringLiteral("http://www.google.com/search?q=%1");
//! [1]
SearchBox::SearchBox(QWidget *parent)
: QLineEdit(parent)
, completer(new GSuggestCompletion(this))
{
connect(this, &SearchBox::returnPressed, this, &SearchBox::doSearch);
setWindowTitle("Search with Google");
adjustSize();
resize(400, height());
setFocus();
}
//! [1]
//! [2]
void SearchBox::doSearch()
{
completer->preventSuggest();
QString url = gsearchUrl.arg(text());
QDesktopServices::openUrl(url);
}
//! [2]

View File

@ -1,28 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef SEARCHBOX_H
#define SEARCHBOX_H
//! [1]
#include <QLineEdit>
class GSuggestCompletion;
class SearchBox: public QLineEdit
{
Q_OBJECT
public:
explicit SearchBox(QWidget *parent = nullptr);
protected slots:
void doSearch();
private:
GSuggestCompletion *completer = nullptr;
//! [1]
};
#endif // SEARCHBOX_H

View File

@ -14,7 +14,6 @@ qtHaveModule(widgets) {
http \
loopback \
threadedfortuneserver \
googlesuggest \
torrent \
multicastreceiver \
multicastsender

View File

@ -31,7 +31,6 @@
\li \l{network/loopback}{Loopback}
\li \l{network/threadedfortuneserver}{Threaded Fortune Server}\raisedaster
\li \l{network/torrent}{Torrent}
\li \l{network/googlesuggest}{Google Suggest}
\li \l{network/bearercloud}{Bearer Cloud}\raisedaster
\li \l{network/bearermonitor}{Bearer Monitor}
\li \l{network/securesocketclient}{Secure Socket Client}