« Return to Thread: [PATCH] Google Suggest for Konqueror Searchbar

Re: [PATCH] Google Suggest for Konqueror Searchbar

by Fredy Yanardi :: Rate this Message:

Reply to Author | View in Thread

Hi all,

As suggested by Germain, I try to implement a generic search suggestion engine for konqueror searchbar instead of hard coding the suggestion engine only for google.

A little bit explanation on that:
1. I try to make use of existing search providers desktop file by adding one  more entry: [Suggest] that value should refer to suggestion request.
e.g: Suggest=http://www.google.com/complete/search?q=\\{@}&output=toolbar
2. Suggestion request (a KIO::TransferJob) is handled by SearchSuggestion class, that depends on SuggestionEngine (see pt. 3) to parse suggestion reply from the provider.
3. There is a parent class for all suggestion engines, called SuggestionEngine. This suggestion class gets the suggestion request URL from the desktop file mentioned in (1).
4. Actual parsing of suggestion reply is done by subclasses of SuggestionEngine, for the case of Google it is GoogleSuggestEngine class.
5. SearchSuggestion maintains a map of searchprovider name and SuggestionEngine, so if we want to implement a new SuggestionEngine, we can just put the new implementation into the map.

And here are the patches for those changes, one is against konq-plugins/searchbar, and one is against KDE/kdebase/runtime/kurifilter-plugins/ikws.

Any comments will be greatly appreciated.

Thanks,

Fredy Yanardi

On Friday 24 April 2009 Germain Garand <germain@...> wrote:

> Le jeudi 23 avril 2009, Fredy Yanardi a écrit :
> > Hi all,
> >
> > This patch implements a google suggest feature for Konqueroer's
> > Searchbar. It will only send request for suggestion to Google if
> > current search provider is google and the search is not a local
> > search.
> >
> > It is always enabled for google search provider, but I'll work on a
> > context menu entry to disable this feature.
>
> Hi Fredy,
>
> you did not attach the files 'GoogleSuggest.cpp' and 'GoogleSuggest.h'...
>
> Speaking of those, as a general question on the design of your patch, why did
> you specifically used the names "Google" for REST services that could be
> provided by many search engines beside this specific one?
>
> It seems this kind of service is simple to map, so why not abstract that
> functionality into a generic class, even if it only contains one provider at
> first?
>
> For instance, after just a cursory search, I can find at least one other
> similar REST api:
>
> http://developer.yahoo.com/search/web/V1/relatedSuggestion.html
>
> that could be used to extend your work...
>
> Greetings,
> Germain
>  

[konq_searchbar_google_suggest_2.diff]

Index: searchbar.h
===================================================================
--- searchbar.h (revision 943903)
+++ searchbar.h (working copy)
@@ -31,10 +31,12 @@
 #include <qpixmap.h>
 #include <qstring.h>
 #include <KProcess>
+#include <QtGui/QItemDelegate>
 
+class SearchSuggestion;
 class KHTMLPart;
-
 class QMenu;
+class QTimer;
 /**
  * Combo box which catches mouse clicks on the pixmap.
  */
@@ -75,6 +77,10 @@
      */
     void setPluginActive(bool pluginActive);
 
+    void setSuggestionItems(const QStringList &suggestions);
+
+    void clearSuggestions();
+
 public slots:
     virtual void show();
 
@@ -97,6 +103,7 @@
 private:
     QPixmap m_icon;
     bool    m_pluginActive;
+    QStringList m_suggestions;
 };
 
 /**
@@ -156,6 +163,13 @@
     void updateComboVisibility();
 
     void focusSearchbar();
+
+    void searchTextChanged(const QString &text);
+
+    void addSearchSuggestion(const QStringList &suggestion);
+
+    void requestSuggestion();
+
 private:
     void nextSearchEntry();
     void previousSearchEntry();
@@ -173,6 +187,19 @@
     QStringList            m_searchEngines;
     QChar                  m_delimiter;
     KProcess              *m_process;
+    SearchSuggestion *m_searchSuggestion;
+    QTimer *m_timer;
 };
 
+/**
+ * An item delegate for combo box completion items, to give some fancy stuff
+ * to the completion items
+ */
+class SearchBarItemDelegate : public QItemDelegate
+{
+public:
+    SearchBarItemDelegate(QObject *parent = 0);
+    virtual void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
+};
+
 #endif // SEARCHBAR_PLUGIN
Index: SearchSuggestion.h
===================================================================
--- SearchSuggestion.h (revision 0)
+++ SearchSuggestion.h (revision 0)
@@ -0,0 +1,54 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2009 Fredy Yanardi <fyanardi@...>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SEARCHSUGGESTION_H
+#define SEARCHSUGGESTION_H
+
+#include <QtCore/QObject>
+#include <kio/jobclasses.h>
+
+class SuggestionEngine;
+
+class SearchSuggestion : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit SearchSuggestion(QObject *parent = 0);
+    bool isEngAvailable(const QString &searchProvider);
+
+public slots:
+    void requestSuggestion(const QString &searchProvider, const QString &searchText);
+
+private slots:
+    void jobFinished(KJob *job);
+    void dataReceived(KIO::Job *job, const QByteArray &data);
+
+signals:
+    void suggestionReceived(const QStringList &suggestion);
+
+private:
+    // QString substitutueSearchText(const QString &searchText, const QString &requestURL) const;
+    QByteArray m_jobData;
+    QMap<QString, SuggestionEngine*> m_enginesMap;
+    SuggestionEngine *m_activeEngine;
+};
+
+#endif // SEARCHSUGGESTION_H
+
Index: SuggestionEngine.h
===================================================================
--- SuggestionEngine.h (revision 0)
+++ SuggestionEngine.h (revision 0)
@@ -0,0 +1,42 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2009 Fredy Yanardi <fyanardi@...>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SUGGESTIONENGINE_H
+#define SUGGESTIONENGINE_H
+
+#include <QtCore/QObject>
+
+class SuggestionEngine : public QObject
+{
+    Q_OBJECT
+
+public:
+    SuggestionEngine(const QString &engineName, QObject *parent = 0);
+
+    QString requestURL() const;
+    QString engineName() const;
+    virtual QStringList parseSuggestion(const QByteArray &response) const=0;
+
+protected:
+    QString m_engineName;
+    QString m_requestURL;
+};
+
+#endif // SUGGESTIONENGINE_H
+
Index: engines/GoogleSuggestEngine.cpp
===================================================================
--- engines/GoogleSuggestEngine.cpp (revision 0)
+++ engines/GoogleSuggestEngine.cpp (revision 0)
@@ -0,0 +1,54 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2009 Fredy Yanardi <fyanardi@...>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "GoogleSuggestEngine.h"
+
+#include <KDebug>
+#include <KUrl>
+
+#include <QtCore/QStringList>
+#include <QtXml/QXmlStreamReader>
+
+GoogleSuggestEngine::GoogleSuggestEngine(QObject *parent)
+    : SuggestionEngine("google", parent)
+{
+}
+
+QStringList GoogleSuggestEngine::parseSuggestion(const QByteArray &response) const
+{
+    /* This XML parsing code is taken from Arora's Google Suggest implementation
+     * (C) 2009 by Benjamin C. Meyer */
+    QXmlStreamReader xml(response);
+    
+    QStringList suggestionsList;
+    while (!xml.atEnd()) {
+        xml.readNext();
+        if (xml.tokenType() == QXmlStreamReader::StartElement) {
+            if (xml.name() == QLatin1String("suggestion")) {
+                QStringRef str = xml.attributes().value(QLatin1String("data"));
+                suggestionsList << str.toString();
+            }
+        }
+    }
+
+    return suggestionsList;
+}
+
+#include "GoogleSuggestEngine.moc"
+
Index: engines/GoogleSuggestEngine.h
===================================================================
--- engines/GoogleSuggestEngine.h (revision 0)
+++ engines/GoogleSuggestEngine.h (revision 0)
@@ -0,0 +1,36 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2009 Fredy Yanardi <fyanardi@...>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GOOGLESUGGESTENGINE_H
+#define GOOGLESUGGESTENGINE_H
+
+#include "SuggestionEngine.h"
+
+class GoogleSuggestEngine : public SuggestionEngine
+{
+    Q_OBJECT
+
+public:
+    explicit GoogleSuggestEngine(QObject *parent = 0);
+
+    QStringList parseSuggestion(const QByteArray &response) const;
+};
+
+#endif // GOOLESUGGESTENGINE_H
+
Index: searchbar.cpp
===================================================================
--- searchbar.cpp (revision 943903)
+++ searchbar.cpp (working copy)
@@ -19,10 +19,13 @@
 
 #include "searchbar.h"
 
+#include "SearchSuggestion.h"
+
 #include <unistd.h>
 #include <QLineEdit>
 #include <QApplication>
 #include <kaction.h>
+#include <KCompletionBox>
 #include <kconfig.h>
 #include <ksharedconfig.h>
 #include <kdebug.h>
@@ -46,6 +49,8 @@
 #include <qstyle.h>
 #include <QPixmap>
 #include <QMouseEvent>
+#include <QtGui/QCompleter>
+#include <QtCore/QTimer>
 
 K_PLUGIN_FACTORY(SearchBarPluginFactory, registerPlugin<SearchBarPlugin>();)
 K_EXPORT_PLUGIN(SearchBarPluginFactory("searchbarplugin"))
@@ -56,7 +61,8 @@
     m_searchCombo(0),
     m_searchMode(UseSearchProvider),
     m_urlEnterLock(false),
-    m_process(0)
+    m_process(0),
+    m_searchSuggestion(new SearchSuggestion(this))
 {
     m_searchCombo = new SearchBarCombo(0);
     m_searchCombo->lineEdit()->installEventFilter(this);
@@ -73,7 +79,6 @@
     m_searchComboAction->setDefaultWidget(m_searchCombo);
     m_searchComboAction->setShortcutConfigurable(false);
 
-
     KAction *a = actionCollection()->addAction("focus_search_bar");
     a->setText(i18n("Focus Searchbar"));
     a->setShortcut(Qt::CTRL+Qt::Key_S);
@@ -83,6 +88,12 @@
 
     // parent is the KonqMainWindow and we want to listen to PartActivateEvent events.
     parent->installEventFilter(this);
+    connect(m_searchCombo->lineEdit(), SIGNAL(textEdited(const QString &)), SLOT(searchTextChanged(const QString &)));
+    connect(m_searchSuggestion, SIGNAL(suggestionReceived(const QStringList &)),
+            SLOT(addSearchSuggestion(const QStringList &)));
+    m_timer = new QTimer(this);
+    m_timer->setSingleShot(true);
+    connect(m_timer, SIGNAL(timeout()), SLOT(requestSuggestion()));
 }
 
 SearchBarPlugin::~SearchBarPlugin()
@@ -409,8 +420,33 @@
     m_searchCombo->setFocus(Qt::ShortcutFocusReason);
 }
 
+void SearchBarPlugin::searchTextChanged(const QString &text)
+{
+    m_searchCombo->clearSuggestions();
+
+    if (m_searchMode != FindInThisPage && m_currentEngine == "google" && !text.isEmpty()) {
+        if (m_timer->isActive()) {
+            m_timer->stop();
+        }
+
+        // 400 ms delay before requesting for suggestions, so we don't flood google with suggestion request
+        m_timer->start(400);
+    }
+}
+
+void SearchBarPlugin::requestSuggestion() {
+    if (!m_searchCombo->lineEdit()->text().isEmpty()) {
+        m_searchSuggestion->requestSuggestion(m_currentEngine, m_searchCombo->lineEdit()->text());
+    }
+}
+
+void SearchBarPlugin::addSearchSuggestion(const QStringList &suggestions)
+{
+    m_searchCombo->setSuggestionItems(suggestions);
+}
+
 SearchBarCombo::SearchBarCombo(QWidget *parent) :
-    KHistoryComboBox(parent),
+    KHistoryComboBox(true, parent),
     m_pluginActive(true)
 {
     setDuplicatesEnabled(false);
@@ -421,9 +457,11 @@
 
     KConfigGroup config(KGlobal::config(), "SearchBar");
     QStringList list = config.readEntry( "History list", QStringList() );
-    list.prepend(QString()); // empty item
     setHistoryItems(list, true);
     Q_ASSERT(currentText().isEmpty()); // KHistoryComboBox calls clearEditText
+
+    // use our own item delegate to display our fancy stuff :D
+    completionBox()->setItemDelegate(new SearchBarItemDelegate(this));
 }
 
 const QPixmap &SearchBarCombo::icon() const
@@ -480,6 +518,36 @@
     m_pluginActive = pluginActive;
 }
 
+void SearchBarCombo::setSuggestionItems(const QStringList &suggestions)
+{
+    if (m_suggestions.count() > 0) {
+        clearSuggestions();
+    }
+
+    m_suggestions = suggestions;
+    if (suggestions.count() > 0) {
+        int size = completionBox()->count();
+        QListWidgetItem *item = new QListWidgetItem(suggestions.at(0));
+        item->setData(Qt::UserRole, "suggestion");
+        completionBox()->insertItem(size + 1, item);
+        for (int i = 1; i < suggestions.count(); i++) {
+            completionBox()->insertItem(size + 1 + i, suggestions.at(i));
+        }
+        completionBox()->popup();
+    }
+}
+
+void SearchBarCombo::clearSuggestions()
+{
+    int size = completionBox()->count();
+    if (!m_suggestions.isEmpty() && size >= m_suggestions.count()) {
+        for (int i = size - 1; i >= size - m_suggestions.size(); i--) {
+            completionBox()->takeItem(i);
+        }
+    }
+    m_suggestions.clear();
+}
+
 void SearchBarCombo::show()
 {
     if (m_pluginActive) {
@@ -493,4 +561,47 @@
     config.writeEntry( "History list", historyItems() );
 }
 
+SearchBarItemDelegate::SearchBarItemDelegate(QObject *parent)
+    : QItemDelegate(parent)
+{
+}
+
+void SearchBarItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    QString userText = index.data(Qt::UserRole).toString();
+    QString text = index.data(Qt::DisplayRole).toString();
+
+    //Get item data
+    if (!userText.isEmpty()) {
+        // This font is for the "information" text, small size + italic + gray in color
+        QFont usrTxtFont = option.font;
+        usrTxtFont.setItalic(true);
+        usrTxtFont.setPointSize(6);
+
+        QFontMetrics usrTxtFontMetrics(usrTxtFont);
+        int width = usrTxtFontMetrics.width(userText);
+        QRect rect(option.rect.x(), option.rect.y(), option.rect.width() - width, option.rect.height());
+        QFontMetrics textFontMetrics(option.font);
+        QString elidedText = textFontMetrics.elidedText(text,
+                Qt::ElideRight, option.rect.width() - width - option.decorationSize.width());
+
+        QAbstractItemModel *itemModel = const_cast<QAbstractItemModel *>(index.model());
+        itemModel->setData(index, elidedText, Qt::DisplayRole);
+        QItemDelegate::paint(painter, option, index);
+        itemModel->setData(index, text, Qt::DisplayRole);
+
+        painter->setFont(usrTxtFont);
+        painter->setPen(QPen(QColor(Qt::gray)));
+        painter->drawText(option.rect, Qt::AlignRight, userText);
+
+        // Draw a separator above this item
+        if (index.row() > 0) {
+            painter->drawLine(option.rect.x(), option.rect.y(), option.rect.x() + option.rect.width(), option.rect.y());
+        }
+    }
+    else {
+        QItemDelegate::paint(painter, option, index);
+    }
+}
+
 #include "searchbar.moc"
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt (revision 943903)
+++ CMakeLists.txt (working copy)
@@ -4,7 +4,11 @@
 
 ########### next target ###############
 
-set(searchbarplugin_PART_SRCS searchbar.cpp )
+set(searchbarplugin_PART_SRCS
+    searchbar.cpp
+    SearchSuggestion.cpp
+    SuggestionEngine.cpp
+    engines/GoogleSuggestEngine.cpp)
 
 kde4_add_plugin(searchbarplugin ${searchbarplugin_PART_SRCS})
 
Index: SearchSuggestion.cpp
===================================================================
--- SearchSuggestion.cpp (revision 0)
+++ SearchSuggestion.cpp (revision 0)
@@ -0,0 +1,89 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2009 Fredy Yanardi <fyanardi@...>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "SearchSuggestion.h"
+
+#include <KDebug>
+#include <KUrl>
+#include <kio/scheduler.h>
+
+#include "engines/GoogleSuggestEngine.h"
+
+SearchSuggestion::SearchSuggestion(QObject *parent)
+    : QObject(parent)
+{
+    // Register all available Suggestion Engines here
+    GoogleSuggestEngine *googleEng = new GoogleSuggestEngine(this);
+    m_enginesMap.insert(googleEng->engineName(), googleEng);
+}
+
+bool SearchSuggestion::isEngAvailable(const QString &searchProvider)
+{
+    return m_enginesMap.contains(searchProvider);
+}
+
+void SearchSuggestion::requestSuggestion(const QString &searchProvider, const QString &searchText)
+{
+    if (!m_enginesMap.contains(searchProvider)) {
+        // There is no such engine registered
+        return;
+    }
+    m_activeEngine = m_enginesMap.value(searchProvider);
+
+    QString requestURL = m_activeEngine->requestURL();
+
+    QString encodedText = QUrl::toPercentEncoding(searchText);
+    QString subsReqURL = requestURL;
+    subsReqURL.replace("\\{@}", encodedText);
+
+    KUrl url(subsReqURL);
+    m_jobData.clear();
+    KIO::TransferJob *job = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo);
+    connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
+            this, SLOT(dataReceived(KIO::Job *, const QByteArray &)));
+    connect(job, SIGNAL(result(KJob *)), SLOT(jobFinished(KJob *)));
+}
+
+void SearchSuggestion::jobFinished(KJob *job)
+{
+    if (job->error()) {
+        return; // just silently return
+    }
+
+    QStringList suggestionsList = m_activeEngine->parseSuggestion(m_jobData);
+    kDebug() << "Received suggestion from " << m_activeEngine->engineName() << ": " << suggestionsList;
+
+    emit suggestionReceived(suggestionsList);
+}
+
+void SearchSuggestion::dataReceived(KIO::Job *job, const QByteArray &data)
+{
+    Q_UNUSED(job);
+    m_jobData.append(data);
+}
+
+/* QString SearchSuggestion::substitutueSearchText(const QString &searchText, const QString &requestURL) const
+{
+    QString encodedText = QUrl::toPercentEncoding(searchText);
+
+    return QString();
+} */
+
+#include "SearchSuggestion.moc"
+
Index: SuggestionEngine.cpp
===================================================================
--- SuggestionEngine.cpp (revision 0)
+++ SuggestionEngine.cpp (revision 0)
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2009 Fredy Yanardi <fyanardi@...>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "SuggestionEngine.h"
+
+#include <KDebug>
+#include <KUrl>
+#include <kservice.h>
+
+#include <QtXml/QXmlStreamReader>
+
+SuggestionEngine::SuggestionEngine(const QString &engineName, QObject *parent)
+    : QObject(parent),
+    m_engineName(engineName)
+{
+    // First get the suggestion request URL for this engine
+    KService::Ptr service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(m_engineName));
+
+    if (service) {
+        QStringList properties = service->property("Suggest").toStringList();
+        if (!properties.isEmpty()) {
+            m_requestURL = properties.first();
+        }
+        else {
+            kWarning() << "Missing property [Suggest] for suggestion engine: " + m_engineName;
+        }
+    }
+}
+
+QString SuggestionEngine::requestURL() const
+{
+    return m_requestURL;
+}
+
+QString SuggestionEngine::engineName() const
+{
+    return m_engineName;
+}
+
+#include "SuggestionEngine.moc"
+


[searchprovider_suggestion.diff]

Index: searchprovider.desktop
===================================================================
--- searchprovider.desktop (revision 967971)
+++ searchprovider.desktop (working copy)
@@ -90,5 +90,8 @@
 [PropertyDef::Query]
 Type=QString
 
+[PropertyDef::Suggest]
+Type=QString
+
 [PropertyDef::Charset]
 Type=QString
Index: searchproviders/google.desktop
===================================================================
--- searchproviders/google.desktop (revision 967971)
+++ searchproviders/google.desktop (working copy)
@@ -35,4 +35,5 @@
 Query[pt]=http://www.google.pt/search?q=\\{@}&ie=UTF-8&oe=UTF-8
 Query[x-test]=xxhttp://www.google.com/search?q=\\{@}&ie=UTF-8&oe=UTF-8xx
 Query[zh_TW]=http://www.google.com.tw/search?q=\\{@}&ie=UTF-8&oe=UTF-8&hl=zh-TW
+Suggest=http://www.google.com/complete/search?q=\\{@}&output=toolbar
 Charset=utf8

 « Return to Thread: [PATCH] Google Suggest for Konqueror Searchbar