File indexing completed on 2024-05-12 04:58:11
0001 /* 0002 * Copyright 2009 Jakub Wieczorek <faw217@gmail.com> 0003 * 0004 * This program is free software; you can redistribute it and/or modify 0005 * it under the terms of the GNU General Public License as published by 0006 * the Free Software Foundation; either version 2 of the License, or 0007 * (at your option) any later version. 0008 * 0009 * This program is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 * GNU General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU General Public License 0015 * along with this program; if not, write to the Free Software 0016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301 USA 0018 */ 0019 /* ============================================================ 0020 * Falkon - Qt web browser 0021 * Copyright (C) 2010-2016 David Rosca <nowrep@gmail.com> 0022 * 0023 * This program is free software: you can redistribute it and/or modify 0024 * it under the terms of the GNU General Public License as published by 0025 * the Free Software Foundation, either version 3 of the License, or 0026 * (at your option) any later version. 0027 * 0028 * This program is distributed in the hope that it will be useful, 0029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0031 * GNU General Public License for more details. 0032 * 0033 * You should have received a copy of the GNU General Public License 0034 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0035 * ============================================================ */ 0036 0037 #include "opensearchengine.h" 0038 #include "opensearchenginedelegate.h" 0039 0040 #include <qbuffer.h> 0041 #include <qcoreapplication.h> 0042 #include <qlocale.h> 0043 #include <qnetworkrequest.h> 0044 #include <qnetworkreply.h> 0045 #include <qregularexpression.h> 0046 #include <qstringlist.h> 0047 0048 #include <QUrlQuery> 0049 #include <QJsonDocument> 0050 0051 0052 /*! 0053 \class OpenSearchEngine 0054 \brief A class representing a single search engine described in OpenSearch format 0055 0056 OpenSearchEngine is a class that represents a single search engine based on 0057 the OpenSearch format. 0058 For more information about the format, see http://www.opensearch.org/. 0059 0060 Instances of the class hold all the data associated with the corresponding search 0061 engines, such as name(), description() and also URL templates that are used 0062 to construct URLs, which can be used later to perform search queries. Search engine 0063 can also have an image, even an external one, in this case it will be downloaded 0064 automatically from the network. 0065 0066 OpenSearchEngine instances can be constructed from scratch but also read from 0067 external sources and written back to them. OpenSearchReader and OpenSearchWriter 0068 are the classes provided for reading and writing OpenSearch descriptions. 0069 0070 Default constructed engines need to be filled with the necessary information before 0071 they can be used to perform search requests. First of all, a search engine should have 0072 the metadata including the name and the description. 0073 However, the most important are URL templates, which are the construction of URLs 0074 but can also contain template parameters, that are replaced with corresponding values 0075 at the time of constructing URLs. 0076 0077 There are two types of URL templates: search URL template and suggestions URL template. 0078 Search URL template is needed for constructing search URLs, which point directly to 0079 search results. Suggestions URL template is necessary to construct suggestion queries 0080 URLs, which are then used for requesting contextual suggestions, a popular service 0081 offered along with search results that provides search terms related to what has been 0082 supplied by the user. 0083 0084 Both types of URLs are constructed by the class, by searchUrl() and suggestionsUrl() 0085 functions respectively. However, search requests are supposed to be performed outside 0086 the class, while suggestion queries can be executed using the requestSuggestions() 0087 method. The class will take care of performing the network request and parsing the 0088 JSON response. 0089 0090 Both the image request and suggestion queries need network access. The class can 0091 perform network requests on its own, though the client application needs to provide 0092 a network access manager, which then will to be used for network operations. 0093 Without that, both images delivered from remote locations and contextual suggestions 0094 will be disabled. 0095 0096 \sa OpenSearchReader, OpenSearchWriter 0097 */ 0098 0099 /*! 0100 Constructs an engine with a given \a parent. 0101 */ 0102 OpenSearchEngine::OpenSearchEngine(QObject* parent) 0103 : QObject(parent) 0104 , m_searchMethod(QLatin1String("get")) 0105 , m_suggestionsMethod(QLatin1String("get")) 0106 , m_networkAccessManager(nullptr) 0107 , m_suggestionsReply(nullptr) 0108 , m_delegate(nullptr) 0109 { 0110 m_requestMethods.insert(QLatin1String("get"), QNetworkAccessManager::GetOperation); 0111 m_requestMethods.insert(QLatin1String("post"), QNetworkAccessManager::PostOperation); 0112 } 0113 0114 /*! 0115 A destructor. 0116 */ 0117 OpenSearchEngine::~OpenSearchEngine() 0118 = default; 0119 0120 QString OpenSearchEngine::parseTemplate(const QString &searchTerm, const QString &searchTemplate) 0121 { 0122 QString language = QLocale().name(); 0123 // Simple conversion to RFC 3066. 0124 language.replace(QLatin1Char('_'), QLatin1Char('-')); 0125 0126 QString result = searchTemplate; 0127 result.replace(QLatin1String("{count}"), QLatin1String("20")); 0128 result.replace(QLatin1String("{startIndex}"), QLatin1String("0")); 0129 result.replace(QLatin1String("{startPage}"), QLatin1String("0")); 0130 result.replace(QLatin1String("{language}"), language); 0131 result.replace(QLatin1String("{inputEncoding}"), QLatin1String("UTF-8")); 0132 result.replace(QLatin1String("{outputEncoding}"), QLatin1String("UTF-8")); 0133 result.replace(QRegularExpression(QSL("\\{([^\\}]*:|)source\\??\\}")), QCoreApplication::applicationName()); 0134 result.replace(QLatin1String("{searchTerms}"), QLatin1String(QUrl::toPercentEncoding(searchTerm))); 0135 0136 return result; 0137 } 0138 0139 /*! 0140 \property OpenSearchEngine::name 0141 \brief the name of the engine 0142 0143 \sa description() 0144 */ 0145 QString OpenSearchEngine::name() const 0146 { 0147 return m_name; 0148 } 0149 0150 void OpenSearchEngine::setName(const QString &name) 0151 { 0152 m_name = name; 0153 } 0154 0155 /*! 0156 \property OpenSearchEngine::description 0157 \brief the description of the engine 0158 0159 \sa name() 0160 */ 0161 QString OpenSearchEngine::description() const 0162 { 0163 return m_description; 0164 } 0165 0166 void OpenSearchEngine::setDescription(const QString &description) 0167 { 0168 m_description = description; 0169 } 0170 0171 /*! 0172 \property OpenSearchEngine::searchUrlTemplate 0173 \brief the template of the search URL 0174 0175 \sa searchUrl(), searchParameters(), suggestionsUrlTemplate() 0176 */ 0177 QString OpenSearchEngine::searchUrlTemplate() const 0178 { 0179 return m_searchUrlTemplate; 0180 } 0181 0182 void OpenSearchEngine::setSearchUrlTemplate(const QString &searchUrlTemplate) 0183 { 0184 if (!searchUrlTemplate.startsWith(QL1S("http://")) && !searchUrlTemplate.startsWith(QL1S("https://"))) { 0185 return; 0186 } 0187 0188 m_searchUrlTemplate = searchUrlTemplate; 0189 } 0190 0191 /*! 0192 Constructs and returns a search URL with a given \a searchTerm. 0193 0194 The URL template is processed according to the specification: 0195 http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax 0196 0197 A list of template parameters currently supported and what they are replaced with: 0198 \table 0199 \header \o parameter 0200 \o value 0201 \row \o "{count}" 0202 \o "20" 0203 \row \o "{startIndex}" 0204 \o "0" 0205 \row \o "{startPage}" 0206 \o "0" 0207 \row \o "{language}" 0208 \o "the default language code (RFC 3066)" 0209 \row \o "{inputEncoding}" 0210 \o "UTF-8" 0211 \row \o "{outputEncoding}" 0212 \o "UTF-8" 0213 \row \o "{*:source}" 0214 \o "application name, QCoreApplication::applicationName()" 0215 \row \o "{searchTerms}" 0216 \o "the string supplied by the user" 0217 \endtable 0218 0219 \sa searchUrlTemplate(), searchParameters(), suggestionsUrl() 0220 */ 0221 QUrl OpenSearchEngine::searchUrl(const QString &searchTerm) const 0222 { 0223 if (m_searchUrlTemplate.isEmpty()) { 0224 return {}; 0225 } 0226 0227 QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_searchUrlTemplate).toUtf8()); 0228 0229 QUrlQuery query(retVal); 0230 if (m_searchMethod != QLatin1String("post")) { 0231 Parameters::const_iterator end = m_searchParameters.constEnd(); 0232 Parameters::const_iterator i = m_searchParameters.constBegin(); 0233 for (; i != end; ++i) { 0234 query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); 0235 } 0236 retVal.setQuery(query); 0237 } 0238 0239 return retVal; 0240 } 0241 0242 QByteArray OpenSearchEngine::getPostData(const QString &searchTerm) const 0243 { 0244 if (m_searchMethod != QLatin1String("post")) { 0245 return {}; 0246 } 0247 0248 QUrl retVal = QUrl(QSL("http://foo.bar")); 0249 0250 QUrlQuery query(retVal); 0251 Parameters::const_iterator end = m_searchParameters.constEnd(); 0252 Parameters::const_iterator i = m_searchParameters.constBegin(); 0253 for (; i != end; ++i) { 0254 query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); 0255 } 0256 retVal.setQuery(query); 0257 0258 QByteArray data = retVal.toEncoded(QUrl::RemoveScheme); 0259 return data.contains('?') ? data.mid(data.lastIndexOf('?') + 1) : QByteArray(); 0260 } 0261 0262 /*! 0263 \property providesSuggestions 0264 \brief indicates whether the engine supports contextual suggestions 0265 */ 0266 bool OpenSearchEngine::providesSuggestions() const 0267 { 0268 return (!m_suggestionsUrlTemplate.isEmpty() || !m_preparedSuggestionsUrl.isEmpty()); 0269 } 0270 0271 /*! 0272 \property OpenSearchEngine::suggestionsUrlTemplate 0273 \brief the template of the suggestions URL 0274 0275 \sa suggestionsUrl(), suggestionsParameters(), searchUrlTemplate() 0276 */ 0277 QString OpenSearchEngine::suggestionsUrlTemplate() const 0278 { 0279 return m_suggestionsUrlTemplate; 0280 } 0281 0282 void OpenSearchEngine::setSuggestionsUrlTemplate(const QString &suggestionsUrlTemplate) 0283 { 0284 if (!suggestionsUrlTemplate.startsWith(QL1S("http://")) && !suggestionsUrlTemplate.startsWith(QL1S("https://"))) { 0285 return; 0286 } 0287 0288 m_suggestionsUrlTemplate = suggestionsUrlTemplate; 0289 } 0290 0291 /*! 0292 Constructs a suggestions URL with a given \a searchTerm. 0293 0294 The URL template is processed according to the specification: 0295 http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax 0296 0297 See searchUrl() for more information about processing template parameters. 0298 0299 \sa suggestionsUrlTemplate(), suggestionsParameters(), searchUrl() 0300 */ 0301 QUrl OpenSearchEngine::suggestionsUrl(const QString &searchTerm) const 0302 { 0303 if (!m_preparedSuggestionsUrl.isEmpty()) { 0304 QString s = m_preparedSuggestionsUrl; 0305 s.replace(QLatin1String("%s"), searchTerm); 0306 return QUrl(s); 0307 } 0308 0309 if (m_suggestionsUrlTemplate.isEmpty()) { 0310 return {}; 0311 } 0312 0313 QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_suggestionsUrlTemplate).toUtf8()); 0314 0315 QUrlQuery query(retVal); 0316 if (m_suggestionsMethod != QLatin1String("post")) { 0317 Parameters::const_iterator end = m_suggestionsParameters.constEnd(); 0318 Parameters::const_iterator i = m_suggestionsParameters.constBegin(); 0319 for (; i != end; ++i) { 0320 query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); 0321 } 0322 retVal.setQuery(query); 0323 } 0324 0325 return retVal; 0326 } 0327 0328 /*! 0329 \property searchParameters 0330 \brief additional parameters that will be included in the search URL 0331 0332 For more information see: 0333 http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0 0334 */ 0335 OpenSearchEngine::Parameters OpenSearchEngine::searchParameters() const 0336 { 0337 return m_searchParameters; 0338 } 0339 0340 void OpenSearchEngine::setSearchParameters(const Parameters &searchParameters) 0341 { 0342 m_searchParameters = searchParameters; 0343 } 0344 0345 /*! 0346 \property suggestionsParameters 0347 \brief additional parameters that will be included in the suggestions URL 0348 0349 For more information see: 0350 http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0 0351 */ 0352 OpenSearchEngine::Parameters OpenSearchEngine::suggestionsParameters() const 0353 { 0354 return m_suggestionsParameters; 0355 } 0356 0357 void OpenSearchEngine::setSuggestionsParameters(const Parameters &suggestionsParameters) 0358 { 0359 m_suggestionsParameters = suggestionsParameters; 0360 } 0361 0362 /*! 0363 \property searchMethod 0364 \brief HTTP request method that will be used to perform search requests 0365 */ 0366 QString OpenSearchEngine::searchMethod() const 0367 { 0368 return m_searchMethod; 0369 } 0370 0371 void OpenSearchEngine::setSearchMethod(const QString &method) 0372 { 0373 QString requestMethod = method.toLower(); 0374 if (!m_requestMethods.contains(requestMethod)) { 0375 return; 0376 } 0377 0378 m_searchMethod = requestMethod; 0379 } 0380 0381 /*! 0382 \property suggestionsMethod 0383 \brief HTTP request method that will be used to perform suggestions requests 0384 */ 0385 QString OpenSearchEngine::suggestionsMethod() const 0386 { 0387 return m_suggestionsMethod; 0388 } 0389 0390 void OpenSearchEngine::setSuggestionsMethod(const QString &method) 0391 { 0392 QString requestMethod = method.toLower(); 0393 if (!m_requestMethods.contains(requestMethod)) { 0394 return; 0395 } 0396 0397 m_suggestionsMethod = requestMethod; 0398 } 0399 0400 /*! 0401 \property imageUrl 0402 \brief the image URL of the engine 0403 0404 When setting a new image URL, it won't be loaded immediately. The first request will be 0405 deferred until image() is called for the first time. 0406 0407 \note To be able to request external images, you need to provide a network access manager, 0408 which will be used for network operations. 0409 0410 \sa image(), networkAccessManager() 0411 */ 0412 QString OpenSearchEngine::imageUrl() const 0413 { 0414 return m_imageUrl; 0415 } 0416 0417 void OpenSearchEngine::setImageUrl(const QString &imageUrl) 0418 { 0419 m_imageUrl = imageUrl; 0420 } 0421 0422 void OpenSearchEngine::loadImage() const 0423 { 0424 if (!m_networkAccessManager || m_imageUrl.isEmpty()) { 0425 return; 0426 } 0427 0428 QNetworkReply* reply = m_networkAccessManager->get(QNetworkRequest(QUrl::fromEncoded(m_imageUrl.toUtf8()))); 0429 connect(reply, &QNetworkReply::finished, this, &OpenSearchEngine::imageObtained); 0430 } 0431 0432 void OpenSearchEngine::imageObtained() 0433 { 0434 auto* reply = qobject_cast<QNetworkReply*>(sender()); 0435 0436 if (!reply) { 0437 return; 0438 } 0439 0440 QByteArray response = reply->readAll(); 0441 0442 reply->close(); 0443 reply->deleteLater(); 0444 0445 if (response.isEmpty()) { 0446 return; 0447 } 0448 0449 m_image.loadFromData(response); 0450 Q_EMIT imageChanged(); 0451 } 0452 0453 /*! 0454 \property image 0455 \brief the image of the engine 0456 0457 When no image URL has been set and an image will be set explicitly, a new data URL 0458 will be constructed, holding the image data encoded with Base64. 0459 0460 \sa imageUrl() 0461 */ 0462 QImage OpenSearchEngine::image() const 0463 { 0464 if (m_image.isNull()) { 0465 loadImage(); 0466 } 0467 return m_image; 0468 } 0469 0470 void OpenSearchEngine::setImage(const QImage &image) 0471 { 0472 if (m_imageUrl.isEmpty()) { 0473 QBuffer imageBuffer; 0474 imageBuffer.open(QBuffer::ReadWrite); 0475 if (image.save(&imageBuffer, "PNG")) { 0476 m_imageUrl = QString(QLatin1String("data:image/png;base64,%1")) 0477 .arg(QLatin1String(imageBuffer.buffer().toBase64())); 0478 } 0479 } 0480 0481 m_image = image; 0482 Q_EMIT imageChanged(); 0483 } 0484 0485 /*! 0486 \property valid 0487 \brief indicates whether the engine is valid i.e. the description was properly formed and included all necessary information 0488 */ 0489 bool OpenSearchEngine::isValid() const 0490 { 0491 return (!m_name.isEmpty() && !m_searchUrlTemplate.isEmpty()); 0492 } 0493 0494 bool OpenSearchEngine::operator==(const OpenSearchEngine &other) const 0495 { 0496 return (m_name == other.m_name 0497 && m_description == other.m_description 0498 && m_imageUrl == other.m_imageUrl 0499 && m_searchUrlTemplate == other.m_searchUrlTemplate 0500 && m_suggestionsUrlTemplate == other.m_suggestionsUrlTemplate 0501 && m_searchParameters == other.m_searchParameters 0502 && m_suggestionsParameters == other.m_suggestionsParameters); 0503 } 0504 0505 bool OpenSearchEngine::operator<(const OpenSearchEngine &other) const 0506 { 0507 return (m_name < other.m_name); 0508 } 0509 0510 /*! 0511 Requests contextual suggestions on the search engine, for a given \a searchTerm. 0512 0513 If succeeded, suggestions() signal will be emitted once the suggestions are received. 0514 0515 \note To be able to request suggestions, you need to provide a network access manager, 0516 which will be used for network operations. 0517 0518 \sa requestSearchResults() 0519 */ 0520 0521 void OpenSearchEngine::setSuggestionsParameters(const QByteArray ¶meters) 0522 { 0523 m_preparedSuggestionsParameters = parameters; 0524 } 0525 0526 void OpenSearchEngine::setSuggestionsUrl(const QString &string) 0527 { 0528 m_preparedSuggestionsUrl = string; 0529 } 0530 0531 QString OpenSearchEngine::getSuggestionsUrl() 0532 { 0533 return suggestionsUrl(QSL("searchstring")).toString().replace(QLatin1String("searchstring"), QLatin1String("%s")); 0534 } 0535 0536 QByteArray OpenSearchEngine::getSuggestionsParameters() 0537 { 0538 QStringList parameters; 0539 Parameters::const_iterator end = m_suggestionsParameters.constEnd(); 0540 Parameters::const_iterator i = m_suggestionsParameters.constBegin(); 0541 for (; i != end; ++i) { 0542 parameters.append(i->first + QLatin1Char('=') + i->second); 0543 } 0544 0545 QByteArray data = parameters.join(QLatin1String("&")).toUtf8(); 0546 0547 return data; 0548 } 0549 0550 void OpenSearchEngine::requestSuggestions(const QString &searchTerm) 0551 { 0552 if (searchTerm.isEmpty() || !providesSuggestions()) { 0553 return; 0554 } 0555 0556 Q_ASSERT(m_networkAccessManager); 0557 0558 if (!m_networkAccessManager) { 0559 return; 0560 } 0561 0562 if (m_suggestionsReply) { 0563 m_suggestionsReply->disconnect(this); 0564 m_suggestionsReply->abort(); 0565 m_suggestionsReply->deleteLater(); 0566 m_suggestionsReply = nullptr; 0567 } 0568 0569 Q_ASSERT(m_requestMethods.contains(m_suggestionsMethod)); 0570 if (m_suggestionsMethod == QLatin1String("get")) { 0571 m_suggestionsReply = m_networkAccessManager->get(QNetworkRequest(suggestionsUrl(searchTerm))); 0572 } 0573 else { 0574 QStringList parameters; 0575 Parameters::const_iterator end = m_suggestionsParameters.constEnd(); 0576 Parameters::const_iterator i = m_suggestionsParameters.constBegin(); 0577 for (; i != end; ++i) { 0578 parameters.append(i->first + QLatin1Char('=') + i->second); 0579 } 0580 0581 QByteArray data = parameters.join(QLatin1String("&")).toUtf8(); 0582 m_suggestionsReply = m_networkAccessManager->post(QNetworkRequest(suggestionsUrl(searchTerm)), data); 0583 } 0584 0585 connect(m_suggestionsReply, &QNetworkReply::finished, this, &OpenSearchEngine::suggestionsObtained); 0586 } 0587 0588 /*! 0589 Requests search results on the search engine, for a given \a searchTerm. 0590 0591 The default implementation does nothing, to supply your own you need to create your own 0592 OpenSearchEngineDelegate subclass and supply it to the engine. Then the function will call 0593 the performSearchRequest() method of the delegate, which can then handle the request 0594 in a custom way. 0595 0596 \sa requestSuggestions(), delegate() 0597 */ 0598 void OpenSearchEngine::requestSearchResults(const QString &searchTerm) 0599 { 0600 if (!m_delegate || searchTerm.isEmpty()) { 0601 return; 0602 } 0603 0604 Q_ASSERT(m_requestMethods.contains(m_searchMethod)); 0605 0606 QNetworkRequest request(QUrl(searchUrl(searchTerm))); 0607 QByteArray data; 0608 QNetworkAccessManager::Operation operation = m_requestMethods.value(m_searchMethod); 0609 0610 if (operation == QNetworkAccessManager::PostOperation) { 0611 QStringList parameters; 0612 Parameters::const_iterator end = m_searchParameters.constEnd(); 0613 Parameters::const_iterator i = m_searchParameters.constBegin(); 0614 for (; i != end; ++i) { 0615 parameters.append(i->first + QLatin1Char('=') + i->second); 0616 } 0617 0618 data = parameters.join(QLatin1String("&")).toUtf8(); 0619 } 0620 0621 m_delegate->performSearchRequest(request, operation, data); 0622 } 0623 0624 void OpenSearchEngine::suggestionsObtained() 0625 { 0626 const QByteArray response = m_suggestionsReply->readAll(); 0627 0628 m_suggestionsReply->close(); 0629 m_suggestionsReply->deleteLater(); 0630 m_suggestionsReply = nullptr; 0631 0632 QJsonParseError err; 0633 QJsonDocument json = QJsonDocument::fromJson(response, &err); 0634 const QVariant res = json.toVariant(); 0635 0636 if (err.error != QJsonParseError::NoError || res.typeId() != QMetaType::QVariantList) 0637 return; 0638 0639 const QVariantList list = res.toList(); 0640 0641 if (list.size() < 2) 0642 return; 0643 0644 QStringList out; 0645 0646 const auto items = list.at(1).toList(); 0647 for (const QVariant &v : items) { 0648 out.append(v.toString()); 0649 } 0650 0651 Q_EMIT suggestions(out); 0652 } 0653 0654 /*! 0655 \property networkAccessManager 0656 \brief the network access manager that is used to perform network requests 0657 0658 It is required for network operations: loading external images and requesting 0659 contextual suggestions. 0660 */ 0661 QNetworkAccessManager* OpenSearchEngine::networkAccessManager() const 0662 { 0663 return m_networkAccessManager; 0664 } 0665 0666 void OpenSearchEngine::setNetworkAccessManager(QNetworkAccessManager* networkAccessManager) 0667 { 0668 m_networkAccessManager = networkAccessManager; 0669 } 0670 0671 /*! 0672 \property delegate 0673 \brief the delegate that is used to perform specific tasks. 0674 0675 It can be currently supplied to provide a custom behaviour ofthe requetSearchResults() method. 0676 The default implementation does nothing. 0677 */ 0678 OpenSearchEngineDelegate* OpenSearchEngine::delegate() const 0679 { 0680 return m_delegate; 0681 } 0682 0683 void OpenSearchEngine::setDelegate(OpenSearchEngineDelegate* delegate) 0684 { 0685 m_delegate = delegate; 0686 } 0687 0688 /*! 0689 \fn void OpenSearchEngine::imageChanged() 0690 0691 This signal is emitted whenever the image of the engine changes. 0692 0693 \sa image(), imageUrl() 0694 */ 0695 0696 /*! 0697 \fn void OpenSearchEngine::suggestions(const QStringList &suggestions) 0698 0699 This signal is emitted whenever new contextual suggestions have been provided 0700 by the search engine. To request suggestions, use requestSuggestions(). 0701 The suggestion set is specified by \a suggestions. 0702 0703 \sa requestSuggestions() 0704 */