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})