41#include <qcoreapplication.h>
43#include <qnetworkrequest.h>
44#include <qnetworkreply.h>
45#include <qregularexpression.h>
46#include <qstringlist.h>
49#include <QJsonDocument>
104 , m_searchMethod(QLatin1String(
"get"))
105 , m_suggestionsMethod(QLatin1String(
"get"))
106 , m_networkAccessManager(nullptr)
107 , m_suggestionsReply(nullptr)
108 , m_delegate(nullptr)
110 m_requestMethods.insert(QLatin1String(
"get"), QNetworkAccessManager::GetOperation);
111 m_requestMethods.insert(QLatin1String(
"post"), QNetworkAccessManager::PostOperation);
122 QString language = QLocale().name();
124 language.replace(QLatin1Char(
'_'), QLatin1Char(
'-'));
126 QString result = searchTemplate;
127 result.replace(QLatin1String(
"{count}"), QLatin1String(
"20"));
128 result.replace(QLatin1String(
"{startIndex}"), QLatin1String(
"0"));
129 result.replace(QLatin1String(
"{startPage}"), QLatin1String(
"0"));
130 result.replace(QLatin1String(
"{language}"), language);
131 result.replace(QLatin1String(
"{inputEncoding}"), QLatin1String(
"UTF-8"));
132 result.replace(QLatin1String(
"{outputEncoding}"), QLatin1String(
"UTF-8"));
133 result.replace(QRegularExpression(
QSL(
"\\{([^\\}]*:|)source\\??\\}")), QCoreApplication::applicationName());
134 result.replace(QLatin1String(
"{searchTerms}"), QLatin1String(QUrl::toPercentEncoding(searchTerm)));
163 return m_description;
179 return m_searchUrlTemplate;
223 if (m_searchUrlTemplate.isEmpty()) {
227 QUrl retVal = QUrl::fromEncoded(
parseTemplate(searchTerm, m_searchUrlTemplate).toUtf8());
229 QUrlQuery query(retVal);
230 if (m_searchMethod != QLatin1String(
"post")) {
231 Parameters::const_iterator end = m_searchParameters.constEnd();
232 Parameters::const_iterator
i = m_searchParameters.constBegin();
233 for (;
i != end; ++
i) {
236 retVal.setQuery(query);
244 if (m_searchMethod != QLatin1String(
"post")) {
248 QUrl retVal = QUrl(
QSL(
"http://foo.bar"));
250 QUrlQuery query(retVal);
251 Parameters::const_iterator end = m_searchParameters.constEnd();
252 Parameters::const_iterator
i = m_searchParameters.constBegin();
253 for (;
i != end; ++
i) {
256 retVal.setQuery(query);
258 QByteArray data = retVal.toEncoded(QUrl::RemoveScheme);
259 return data.contains(
'?') ? data.mid(data.lastIndexOf(
'?') + 1) : QByteArray();
268 return (!m_suggestionsUrlTemplate.isEmpty() || !m_preparedSuggestionsUrl.isEmpty());
279 return m_suggestionsUrlTemplate;
303 if (!m_preparedSuggestionsUrl.isEmpty()) {
304 QString s = m_preparedSuggestionsUrl;
305 s.replace(QLatin1String(
"%s"), searchTerm);
309 if (m_suggestionsUrlTemplate.isEmpty()) {
313 QUrl retVal = QUrl::fromEncoded(
parseTemplate(searchTerm, m_suggestionsUrlTemplate).toUtf8());
315 QUrlQuery query(retVal);
316 if (m_suggestionsMethod != QLatin1String(
"post")) {
317 Parameters::const_iterator end = m_suggestionsParameters.constEnd();
318 Parameters::const_iterator
i = m_suggestionsParameters.constBegin();
319 for (;
i != end; ++
i) {
322 retVal.setQuery(query);
337 return m_searchParameters;
354 return m_suggestionsParameters;
368 return m_searchMethod;
373 QString requestMethod = method.toLower();
374 if (!m_requestMethods.contains(requestMethod)) {
378 m_searchMethod = requestMethod;
387 return m_suggestionsMethod;
392 QString requestMethod = method.toLower();
393 if (!m_requestMethods.contains(requestMethod)) {
397 m_suggestionsMethod = requestMethod;
424 if (!m_networkAccessManager || m_imageUrl.isEmpty()) {
428 QNetworkReply* reply = m_networkAccessManager->get(QNetworkRequest(QUrl::fromEncoded(m_imageUrl.toUtf8())));
429 connect(reply, &QNetworkReply::finished,
this, &OpenSearchEngine::imageObtained);
432void OpenSearchEngine::imageObtained()
434 auto* reply = qobject_cast<QNetworkReply*>(sender());
440 QByteArray response = reply->readAll();
443 reply->deleteLater();
445 if (response.isEmpty()) {
449 m_image.loadFromData(response);
464 if (m_image.isNull()) {
472 if (m_imageUrl.isEmpty()) {
474 imageBuffer.open(QBuffer::ReadWrite);
475 if (
image.save(&imageBuffer,
"PNG")) {
476 m_imageUrl = QString(QLatin1String(
"data:image/png;base64,%1"))
477 .arg(QLatin1String(imageBuffer.buffer().toBase64()));
491 return (!m_name.isEmpty() && !m_searchUrlTemplate.isEmpty());
496 return (m_name == other.m_name
497 && m_description == other.m_description
498 && m_imageUrl == other.m_imageUrl
499 && m_searchUrlTemplate == other.m_searchUrlTemplate
500 && m_suggestionsUrlTemplate == other.m_suggestionsUrlTemplate
501 && m_searchParameters == other.m_searchParameters
502 && m_suggestionsParameters == other.m_suggestionsParameters);
507 return (m_name < other.m_name);
523 m_preparedSuggestionsParameters = parameters;
528 m_preparedSuggestionsUrl = string;
533 return suggestionsUrl(
QSL(
"searchstring")).toString().replace(QLatin1String(
"searchstring"), QLatin1String(
"%s"));
538 QStringList parameters;
539 Parameters::const_iterator end = m_suggestionsParameters.constEnd();
540 Parameters::const_iterator
i = m_suggestionsParameters.constBegin();
541 for (;
i != end; ++
i) {
542 parameters.append(
i->first + QLatin1Char(
'=') +
i->second);
545 QByteArray data = parameters.join(QLatin1String(
"&")).toUtf8();
556 Q_ASSERT(m_networkAccessManager);
558 if (!m_networkAccessManager) {
562 if (m_suggestionsReply) {
563 m_suggestionsReply->disconnect(
this);
564 m_suggestionsReply->abort();
565 m_suggestionsReply->deleteLater();
566 m_suggestionsReply =
nullptr;
569 Q_ASSERT(m_requestMethods.contains(m_suggestionsMethod));
570 if (m_suggestionsMethod == QLatin1String(
"get")) {
571 m_suggestionsReply = m_networkAccessManager->get(QNetworkRequest(
suggestionsUrl(searchTerm)));
574 QStringList parameters;
575 Parameters::const_iterator end = m_suggestionsParameters.constEnd();
576 Parameters::const_iterator
i = m_suggestionsParameters.constBegin();
577 for (;
i != end; ++
i) {
578 parameters.append(
i->first + QLatin1Char(
'=') +
i->second);
581 QByteArray data = parameters.join(QLatin1String(
"&")).toUtf8();
582 m_suggestionsReply = m_networkAccessManager->post(QNetworkRequest(
suggestionsUrl(searchTerm)), data);
585 connect(m_suggestionsReply, &QNetworkReply::finished,
this, &OpenSearchEngine::suggestionsObtained);
600 if (!m_delegate || searchTerm.isEmpty()) {
604 Q_ASSERT(m_requestMethods.contains(m_searchMethod));
606 QNetworkRequest request(QUrl(
searchUrl(searchTerm)));
608 QNetworkAccessManager::Operation operation = m_requestMethods.value(m_searchMethod);
610 if (operation == QNetworkAccessManager::PostOperation) {
611 QStringList parameters;
612 Parameters::const_iterator end = m_searchParameters.constEnd();
613 Parameters::const_iterator
i = m_searchParameters.constBegin();
614 for (;
i != end; ++
i) {
615 parameters.append(
i->first + QLatin1Char(
'=') +
i->second);
618 data = parameters.join(QLatin1String(
"&")).toUtf8();
624void OpenSearchEngine::suggestionsObtained()
626 const QByteArray response = m_suggestionsReply->readAll();
628 m_suggestionsReply->close();
629 m_suggestionsReply->deleteLater();
630 m_suggestionsReply =
nullptr;
633 QJsonDocument json = QJsonDocument::fromJson(response, &err);
634 const QVariant res = json.toVariant();
636 if (err.error != QJsonParseError::NoError || res.typeId() != QMetaType::QVariantList)
639 const QVariantList list = res.toList();
646 const auto items = list.at(1).toList();
647 for (
const QVariant &v : items) {
648 out.append(v.toString());
663 return m_networkAccessManager;
An abstract class providing custom processing of specific activities.
virtual void performSearchRequest(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, const QByteArray &data)=0
A class representing a single search engine described in OpenSearch format.
void requestSearchResults(const QString &searchTerm)
QUrl searchUrl(const QString &searchTerm) const
OpenSearchEngineDelegate * delegate() const
void setSearchParameters(const Parameters &searchParameters)
void setSuggestionsMethod(const QString &method)
void setSearchMethod(const QString &method)
Parameters searchParameters
Parameters suggestionsParameters
void setImage(const QImage &image)
QNetworkAccessManager * networkAccessManager
QUrl suggestionsUrl(const QString &searchTerm) const
QByteArray getSuggestionsParameters()
QString suggestionsMethod
void requestSuggestions(const QString &searchTerm)
void setImageUrl(const QString &url)
void setSearchUrlTemplate(const QString &searchUrl)
void setNetworkAccessManager(QNetworkAccessManager *networkAccessManager)
QString suggestionsUrlTemplate
the template of the suggestions URL
void setName(const QString &name)
QByteArray getPostData(const QString &searchTerm) const
QString getSuggestionsUrl()
bool operator==(const OpenSearchEngine &other) const
QList< Parameter > Parameters
QString description
the description of the engine
void setSuggestionsParameters(const Parameters &suggestionsParameters)
void setDelegate(OpenSearchEngineDelegate *delegate)
void setDescription(const QString &description)
static QString parseTemplate(const QString &searchTerm, const QString &searchTemplate)
void setSuggestionsUrlTemplate(const QString &suggestionsUrl)
QString searchUrlTemplate
the template of the search URL
bool operator<(const OpenSearchEngine &other) const
QString name
the name of the engine
void suggestions(const QStringList &suggestions)
void setSuggestionsUrl(const QString &string)
OpenSearchEngine(QObject *parent=nullptr)