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

[PATCH] Google Suggest for Konqueror Searchbar

by Fredy Yanardi :: Rate this Message:

Reply to Author | View in Thread

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.

Best Regards,

Fredy Yanardi

[konq_searchbar_google_suggest.diff]

Index: searchbar.h
===================================================================
--- searchbar.h (revision 943903)
+++ searchbar.h (working copy)
@@ -1,5 +1,6 @@
 /* This file is part of the KDE project
    Copyright (C) 2004 Arend van Beelen jr. <arend@...>
+   Copyright (C) 2009 Fredy Yanardi <fyanardi@...>
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public
@@ -31,10 +32,12 @@
 #include <qpixmap.h>
 #include <qstring.h>
 #include <KProcess>
+#include <QtGui/QItemDelegate>
 
+class GoogleSuggest;
 class KHTMLPart;
-
 class QMenu;
+class QTimer;
 /**
  * Combo box which catches mouse clicks on the pixmap.
  */
@@ -75,6 +78,10 @@
      */
     void setPluginActive(bool pluginActive);
 
+    void setSuggestionItems(const QStringList &suggestions);
+
+    void clearSuggestions();
+
 public slots:
     virtual void show();
 
@@ -97,6 +104,7 @@
 private:
     QPixmap m_icon;
     bool    m_pluginActive;
+    QStringList m_suggestions;
 };
 
 /**
@@ -156,6 +164,13 @@
     void updateComboVisibility();
 
     void focusSearchbar();
+
+    void searchTextChanged(const QString &text);
+
+    void addGoogleSuggestion(const QStringList &suggestion);
+
+    void requestSuggestion();
+
 private:
     void nextSearchEntry();
     void previousSearchEntry();
@@ -173,6 +188,19 @@
     QStringList            m_searchEngines;
     QChar                  m_delimiter;
     KProcess              *m_process;
+    GoogleSuggest *m_googleSuggest;
+    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: searchbar.cpp
===================================================================
--- searchbar.cpp (revision 943903)
+++ searchbar.cpp (working copy)
@@ -1,5 +1,6 @@
 /* This file is part of the KDE project
    Copyright (C) 2004 Arend van Beelen jr. <arend@...>
+   Copyright (C) 2009 Fredy Yanardi <fyanardi@...>
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public
@@ -19,10 +20,13 @@
 
 #include "searchbar.h"
 
+#include "GoogleSuggest.h"
+
 #include <unistd.h>
 #include <QLineEdit>
 #include <QApplication>
 #include <kaction.h>
+#include <KCompletionBox>
 #include <kconfig.h>
 #include <ksharedconfig.h>
 #include <kdebug.h>
@@ -46,6 +50,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 +62,8 @@
     m_searchCombo(0),
     m_searchMode(UseSearchProvider),
     m_urlEnterLock(false),
-    m_process(0)
+    m_process(0),
+    m_googleSuggest(new GoogleSuggest(this))
 {
     m_searchCombo = new SearchBarCombo(0);
     m_searchCombo->lineEdit()->installEventFilter(this);
@@ -73,7 +80,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 +89,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_googleSuggest, SIGNAL(suggestionReceived(const QStringList &)),
+            SLOT(addGoogleSuggestion(const QStringList &)));
+    m_timer = new QTimer(this);
+    m_timer->setSingleShot(true);
+    connect(m_timer, SIGNAL(timeout()), SLOT(requestSuggestion()));
 }
 
 SearchBarPlugin::~SearchBarPlugin()
@@ -409,8 +421,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_googleSuggest->requestSuggestion(m_searchCombo->lineEdit()->text());
+    }
+}
+
+void SearchBarPlugin::addGoogleSuggestion(const QStringList &suggestions)
+{
+    m_searchCombo->setSuggestionItems(suggestions);
+}
+
 SearchBarCombo::SearchBarCombo(QWidget *parent) :
-    KHistoryComboBox(parent),
+    KHistoryComboBox(true, parent),
     m_pluginActive(true)
 {
     setDuplicatesEnabled(false);
@@ -421,9 +458,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 +519,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 +562,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,7 @@
 
 ########### next target ###############
 
-set(searchbarplugin_PART_SRCS searchbar.cpp )
+set(searchbarplugin_PART_SRCS searchbar.cpp GoogleSuggest.cpp)
 
 kde4_add_plugin(searchbarplugin ${searchbarplugin_PART_SRCS})
 

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