From e9d099f4c5efa41fafd16408f13400cb37616f18 Mon Sep 17 00:00:00 2001
From: lionelc <lionelc@lionelc.(none)>
Date: Thu, 12 Aug 2010 18:31:16 +0200
Subject: introduce a new SuggestionListItem introduce an opensearch engine

---
 src/CMakeLists.txt               |   7 +-
 src/search/opensearchengine.cpp  | 229 +++++++++++++++++++++++++++++++++++++++
 src/search/opensearchengine.h    |  93 ++++++++++++++++
 src/search/opensearchmanager.cpp | 175 ++++++++++++++++++++++++++++++
 src/search/opensearchmanager.h   |  88 +++++++++++++++
 src/search/opensearchreader.cpp  | 133 +++++++++++++++++++++++
 src/search/opensearchreader.h    |  39 +++++++
 src/search/opensearchwriter.cpp  | 110 +++++++++++++++++++
 src/search/opensearchwriter.h    |  41 +++++++
 src/search/searchengine.cpp      | 153 ++++++++++++++++++++++++++
 src/search/searchengine.h        |  62 +++++++++++
 src/searchengine.cpp             | 153 --------------------------
 src/searchengine.h               |  62 -----------
 src/settings/settingsdialog.cpp  |   2 +-
 src/urlbar/completionwidget.cpp  |   2 +-
 src/urlbar/listitem.cpp          |  30 ++++-
 src/urlbar/listitem.h            |  12 ++
 src/urlbar/urlresolver.cpp       |  21 +++-
 src/urlbar/urlresolver.h         |   4 +-
 src/webview.cpp                  |   2 +-
 20 files changed, 1193 insertions(+), 225 deletions(-)
 create mode 100644 src/search/opensearchengine.cpp
 create mode 100644 src/search/opensearchengine.h
 create mode 100644 src/search/opensearchmanager.cpp
 create mode 100644 src/search/opensearchmanager.h
 create mode 100644 src/search/opensearchreader.cpp
 create mode 100644 src/search/opensearchreader.h
 create mode 100644 src/search/opensearchwriter.cpp
 create mode 100644 src/search/opensearchwriter.h
 create mode 100644 src/search/searchengine.cpp
 create mode 100644 src/search/searchengine.h
 delete mode 100644 src/searchengine.cpp
 delete mode 100644 src/searchengine.h

(limited to 'src')

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 46e9240c..a6658ed0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -29,7 +29,6 @@ SET( rekonq_KDEINIT_SRCS
     websnap.cpp
     webview.cpp
     webtab.cpp
-    searchengine.cpp
     #----------------------------------------
     history/autosaver.cpp 
     history/historymanager.cpp
@@ -63,6 +62,12 @@ SET( rekonq_KDEINIT_SRCS
     #----------------------------------------
     analyzer/analyzerpanel.cpp
     analyzer/networkanalyzer.cpp
+    #----------------------------------------
+    search/searchengine.cpp
+    search/opensearchwriter.cpp
+    search/opensearchreader.cpp
+    search/opensearchmanager.cpp
+    search/opensearchengine.cpp
 )
 
 
diff --git a/src/search/opensearchengine.cpp b/src/search/opensearchengine.cpp
new file mode 100644
index 00000000..a7bcf11e
--- /dev/null
+++ b/src/search/opensearchengine.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2009 Jakub Wieczorek <faw217@gmail.com>
+ * Copyright 2009 Christian Franke <cfchris6@ts2server.com>
+ * Copyright 2009 Fredy Yanardi <fyanardi@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "opensearchengine.h"
+
+#include <QtCore/QRegExp>
+#include <QtCore/QStringList>
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptValue>
+
+OpenSearchEngine::OpenSearchEngine(QObject *)
+    : m_scriptEngine(0)
+{
+}
+
+OpenSearchEngine::~OpenSearchEngine()
+{
+    if (m_scriptEngine) {
+        delete m_scriptEngine;
+    }
+}
+
+QString OpenSearchEngine::parseTemplate(const QString &searchTerm, const QString &searchTemplate)
+{
+    QString result = searchTemplate;
+    result.replace(QLatin1String("{count}"), QLatin1String("20"));
+    result.replace(QLatin1String("{startIndex}"), QLatin1String("0"));
+    result.replace(QLatin1String("{startPage}"), QLatin1String("0"));
+    // TODO - get setting from KDE
+    result.replace(QLatin1String("{language}"), QLatin1String("en-US"));
+    result.replace(QLatin1String("{inputEncoding}"), QLatin1String("UTF-8"));
+    result.replace(QLatin1String("{outputEncoding}"), QLatin1String("UTF-8"));
+    result.replace(QLatin1String("{searchTerms}"), searchTerm);
+
+    return result;
+}
+
+QString OpenSearchEngine::name() const
+{
+    return m_name;
+}
+
+void OpenSearchEngine::setName(const QString &name)
+{
+    m_name = name;
+}
+
+QString OpenSearchEngine::description() const
+{
+    return m_description;
+}
+
+void OpenSearchEngine::setDescription(const QString &description)
+{
+    m_description = description;
+}
+
+QString OpenSearchEngine::searchUrlTemplate() const
+{
+    return m_searchUrlTemplate;
+}
+
+void OpenSearchEngine::setSearchUrlTemplate(const QString &searchUrlTemplate)
+{
+    m_searchUrlTemplate = searchUrlTemplate;
+}
+
+KUrl OpenSearchEngine::searchUrl(const QString &searchTerm) const
+{
+    if (m_searchUrlTemplate.isEmpty()) {
+        return KUrl();
+    }
+
+    KUrl retVal = KUrl::fromEncoded(parseTemplate(searchTerm, m_searchUrlTemplate).toUtf8());
+
+    QList<Parameter>::const_iterator end = m_searchParameters.constEnd();
+    QList<Parameter>::const_iterator i = m_searchParameters.constBegin();
+    for (; i != end; ++i) {
+        retVal.addQueryItem(i->first, parseTemplate(searchTerm, i->second));
+    }
+
+    return retVal;
+}
+
+bool OpenSearchEngine::providesSuggestions() const
+{
+    return !m_suggestionsUrlTemplate.isEmpty();
+}
+
+QString OpenSearchEngine::suggestionsUrlTemplate() const
+{
+    return m_suggestionsUrlTemplate;
+}
+
+void OpenSearchEngine::setSuggestionsUrlTemplate(const QString &suggestionsUrlTemplate)
+{
+    m_suggestionsUrlTemplate = suggestionsUrlTemplate;
+}
+
+KUrl OpenSearchEngine::suggestionsUrl(const QString &searchTerm) const
+{
+    if (m_suggestionsUrlTemplate.isEmpty()) {
+        return KUrl();
+    }
+
+    KUrl retVal = KUrl::fromEncoded(parseTemplate(searchTerm, m_suggestionsUrlTemplate).toUtf8());
+
+    QList<Parameter>::const_iterator end = m_suggestionsParameters.constEnd();
+    QList<Parameter>::const_iterator i = m_suggestionsParameters.constBegin();
+    for (; i != end; ++i) {
+        retVal.addQueryItem(i->first, parseTemplate(searchTerm, i->second));
+    }
+
+    return retVal;
+}
+
+QList<OpenSearchEngine::Parameter> OpenSearchEngine::searchParameters() const
+{
+    return m_searchParameters;
+}
+
+void OpenSearchEngine::setSearchParameters(const QList<Parameter> &searchParameters)
+{
+    m_searchParameters = searchParameters;
+}
+
+QList<OpenSearchEngine::Parameter> OpenSearchEngine::suggestionsParameters() const
+{
+    return m_suggestionsParameters;
+}
+
+void OpenSearchEngine::setSuggestionsParameters(const QList<Parameter> &suggestionsParameters)
+{
+    m_suggestionsParameters = suggestionsParameters;
+}
+
+QString OpenSearchEngine::imageUrl() const
+{
+    return m_imageUrl;
+}
+
+void OpenSearchEngine::setImageUrl(const QString &imageUrl)
+{
+    m_imageUrl = imageUrl;
+}
+
+QImage OpenSearchEngine::image() const
+{
+    return m_image;
+}
+
+void OpenSearchEngine::setImage(const QImage &image)
+{
+    m_image = image;
+}
+
+bool OpenSearchEngine::isValid() const
+{
+    return (!m_name.isEmpty() && !m_searchUrlTemplate.isEmpty());
+}
+
+bool OpenSearchEngine::operator==(const OpenSearchEngine &other) const
+{
+    return (m_name == other.m_name
+            && m_description == other.m_description
+            && m_imageUrl == other.m_imageUrl
+            && m_searchUrlTemplate == other.m_searchUrlTemplate
+            && m_suggestionsUrlTemplate == other.m_suggestionsUrlTemplate
+            && m_searchParameters == other.m_searchParameters
+            && m_suggestionsParameters == other.m_suggestionsParameters);
+}
+
+bool OpenSearchEngine::operator<(const OpenSearchEngine &other) const
+{
+    return (m_name < other.m_name);
+}
+
+QStringList OpenSearchEngine::parseSuggestion(const QByteArray &resp)
+{
+    QString response(resp);
+    response = response.trimmed();
+
+    if (response.isEmpty()) {
+        return QStringList();
+    }
+
+    if (!response.startsWith(QLatin1Char('[')) || !response.endsWith(QLatin1Char(']'))) {
+        return QStringList();
+    }
+
+    if (!m_scriptEngine) {
+        m_scriptEngine = new QScriptEngine();
+    }
+
+    // Evaluate the JSON response using QtScript.
+    if (!m_scriptEngine->canEvaluate(response)) {
+        return QStringList();
+    }
+
+    QScriptValue responseParts = m_scriptEngine->evaluate(response);
+
+    if (!responseParts.property(1).isArray()) {
+        return QStringList();
+    }
+
+    QStringList suggestionsList;
+    qScriptValueToSequence(responseParts.property(1), suggestionsList);
+
+    return suggestionsList;
+}
+
diff --git a/src/search/opensearchengine.h b/src/search/opensearchengine.h
new file mode 100644
index 00000000..c981f443
--- /dev/null
+++ b/src/search/opensearchengine.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2009 Jakub Wieczorek <faw217@gmail.com>
+ * Copyright 2009 Christian Franke <cfchris6@ts2server.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef OPENSEARCHENGINE_H
+#define OPENSEARCHENGINE_H
+
+#include <QtCore/QPair>
+#include <QtGui/QImage>
+
+#include <KUrl>
+
+class QNetworkAccessManager;
+class QNetworkReply;
+class QScriptEngine;
+
+class OpenSearchEngine
+{
+public:
+    typedef QPair<QString, QString> Parameter;
+
+    OpenSearchEngine(QObject *parent = 0);
+    ~OpenSearchEngine();
+
+    QString name() const;
+    void setName(const QString &name);
+
+    QString description() const;
+    void setDescription(const QString &description);
+
+    QString searchUrlTemplate() const;
+    void setSearchUrlTemplate(const QString &searchUrl);
+    KUrl searchUrl(const QString &searchTerm) const;
+
+    bool providesSuggestions() const;
+
+    QString suggestionsUrlTemplate() const;
+    void setSuggestionsUrlTemplate(const QString &suggestionsUrl);
+    KUrl suggestionsUrl(const QString &searchTerm) const;
+
+    QList<Parameter> searchParameters() const;
+    void setSearchParameters(const QList<Parameter> &searchParameters);
+
+    QList<Parameter> suggestionsParameters() const;
+    void setSuggestionsParameters(const QList<Parameter> &suggestionsParameters);
+
+    QString imageUrl() const;
+    void setImageUrl(const QString &url);
+
+    QImage image() const;
+    void setImage(const QImage &image);
+
+    bool isValid() const;
+
+    bool operator==(const OpenSearchEngine &other) const;
+    bool operator<(const OpenSearchEngine &other) const;
+
+    QStringList parseSuggestion(const QByteArray &response);
+
+    static QString parseTemplate(const QString &searchTerm, const QString &searchTemplate);
+
+private:
+    QString m_name;
+    QString m_description;
+
+    QString m_imageUrl;
+    QImage m_image;
+
+    QString m_searchUrlTemplate;
+    QString m_suggestionsUrlTemplate;
+    QList<Parameter> m_searchParameters;
+    QList<Parameter> m_suggestionsParameters;
+
+    QScriptEngine *m_scriptEngine;
+};
+
+#endif // OPENSEARCHENGINE_H
diff --git a/src/search/opensearchmanager.cpp b/src/search/opensearchmanager.cpp
new file mode 100644
index 00000000..6e37db77
--- /dev/null
+++ b/src/search/opensearchmanager.cpp
@@ -0,0 +1,175 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2009 Fredy Yanardi <fyanardi@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 "opensearchmanager.h"
+
+#include <QtCore/QFile>
+
+#include <KDebug>
+#include <KGlobal>
+#include <KStandardDirs>
+#include <KUrl>
+#include <kio/scheduler.h>
+
+#include "opensearchengine.h"
+#include "opensearchreader.h"
+#include "opensearchwriter.h"
+
+OpenSearchManager::OpenSearchManager(QObject *parent)
+    : QObject(parent)
+    , m_activeEngine(0)
+{
+    m_state = IDLE;
+}
+
+OpenSearchManager::~OpenSearchManager() {
+    qDeleteAll(m_enginesMap.values());
+    m_enginesMap.clear();
+}
+
+void OpenSearchManager::setSearchProvider(const QString &searchProvider)
+{
+    m_activeEngine = 0;
+
+    if (!m_enginesMap.contains(searchProvider)) {
+        const QString fileName = KGlobal::dirs()->findResource("data", "konqueror/opensearch/" + searchProvider + ".xml");
+        if (fileName.isEmpty()) {
+            return;
+        }
+        QFile file(fileName);
+
+        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+            kWarning(1202) << "Cannot open opensearch description file: " + fileName;
+            return;
+        }
+
+        OpenSearchReader reader;
+        OpenSearchEngine *engine = reader.read(&file);
+
+        if (engine) {
+            m_enginesMap.insert(searchProvider, engine);
+        }
+        else {
+            return;
+        }
+    }
+
+    m_activeEngine = m_enginesMap.value(searchProvider);
+}
+
+bool OpenSearchManager::isSuggestionAvailable()
+{
+    return m_activeEngine != 0;
+}
+
+void OpenSearchManager::addOpenSearchEngine(const KUrl &url, const QString &title)
+{
+    Q_UNUSED(title);
+
+    m_jobData.clear();
+
+    if (m_state != IDLE) {
+        // TODO: cancel job
+    }
+
+    m_state = REQ_DESCRIPTION;
+    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 OpenSearchManager::requestSuggestion(const QString &searchText)
+{
+    if (!m_activeEngine) {
+        return;
+    }
+
+    if (m_state != IDLE) {
+        // TODO: cancel job
+    }
+    m_state = REQ_SUGGESTION;
+
+    KUrl url = m_activeEngine->suggestionsUrl(searchText);
+    kDebug(1202) << "Requesting for suggestions: " << url.url();
+    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 OpenSearchManager::dataReceived(KIO::Job *job, const QByteArray &data)
+{
+    Q_UNUSED(job);
+    m_jobData.append(data);
+}
+
+void OpenSearchManager::jobFinished(KJob *job)
+{
+    if (job->error()) {
+        return; // just silently return
+    }
+
+    if (m_state == REQ_SUGGESTION) {
+        const QStringList suggestionsList = m_activeEngine->parseSuggestion(m_jobData);
+        kDebug(1202) << "Received suggestion from " << m_activeEngine->name() << ": " << suggestionsList;
+
+        emit suggestionReceived(suggestionsList);
+    }
+    else if (m_state == REQ_DESCRIPTION) {
+        OpenSearchReader reader;
+        OpenSearchEngine *engine = reader.read(m_jobData);
+        if (engine) {
+            m_enginesMap.insert(engine->name(), engine);
+            QString path = KGlobal::dirs()->findResource("data", "konqueror/opensearch/");
+            QString fileName = trimmedEngineName(engine->name());
+            QFile file(path + fileName + ".xml");
+            OpenSearchWriter writer;
+            writer.write(&file, engine);
+
+            QString searchUrl = OpenSearchEngine::parseTemplate("\\{@}", engine->searchUrlTemplate());
+            emit openSearchEngineAdded(engine->name(), searchUrl, fileName);
+        }
+        else {
+            kFatal() << "Error while adding new open search engine";
+        }
+    }
+}
+
+QString OpenSearchManager::trimmedEngineName(const QString &engineName) const
+{
+    QString trimmed;
+    QString::ConstIterator constIter = engineName.constBegin();
+    while (constIter != engineName.constEnd()) {
+        if (constIter->isSpace()) {
+            trimmed.append('-');
+        }
+        else if (*constIter != '.') {
+            trimmed.append(constIter->toLower());
+        }
+        constIter++;
+    }
+
+    return trimmed;
+}
+
+#include "opensearchmanager.moc"
+
+ 
diff --git a/src/search/opensearchmanager.h b/src/search/opensearchmanager.h
new file mode 100644
index 00000000..59e7e6b2
--- /dev/null
+++ b/src/search/opensearchmanager.h
@@ -0,0 +1,88 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2009 Fredy Yanardi <fyanardi@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 OPENSEARCHMANAGER_H
+#define OPENSEARCHMANAGER_H
+
+#include <QtCore/QObject>
+#include <kio/jobclasses.h>
+
+class SuggestionEngine;
+
+class OpenSearchEngine;
+
+/**
+ * This class acts as a proxy between the SearchBar plugin and the individual suggestion engine.
+ * This class has a map of all available engines, and route the suggestion request to the correct engine
+ */
+class OpenSearchManager : public QObject
+{
+    Q_OBJECT
+
+    enum STATE {
+        REQ_SUGGESTION,
+        REQ_DESCRIPTION,
+        IDLE
+    };
+public:
+    /**
+     * Constructor
+     */
+    explicit OpenSearchManager(QObject *parent = 0);
+
+    virtual ~OpenSearchManager();
+
+    void setSearchProvider(const QString &searchProvider);
+
+    /**
+     * Check whether a search suggestion engine is available for the given search provider
+     * @param searchProvider the queried search provider
+     */
+    bool isSuggestionAvailable();
+
+    void addOpenSearchEngine(const KUrl &url, const QString &title);
+
+public slots:
+    /**
+     * Ask the specific suggestion engine to request for suggestion for the search text
+     * @param searchProvider the search provider that provides the suggestion service
+     * @param searchText the text to be queried to the suggestion service
+     */
+    void requestSuggestion(const QString &searchProvider);
+
+private slots:
+    void dataReceived(KIO::Job *job, const QByteArray &data);
+    void jobFinished(KJob *job);
+
+signals:
+    void suggestionReceived(const QStringList &suggestion);
+    void openSearchEngineAdded(const QString &name, const QString &searchUrl, const QString &fileName);
+
+private:
+    QString trimmedEngineName(const QString &engineName) const;
+
+    // QString substitutueSearchText(const QString &searchText, const QString &requestURL) const;
+    QByteArray m_jobData;
+    QMap<QString, OpenSearchEngine*> m_enginesMap;
+    OpenSearchEngine *m_activeEngine;
+    STATE m_state;
+};
+
+#endif // OPENSEARCHMANAGER_H
+
diff --git a/src/search/opensearchreader.cpp b/src/search/opensearchreader.cpp
new file mode 100644
index 00000000..0aa0f91f
--- /dev/null
+++ b/src/search/opensearchreader.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2009 Jakub Wieczorek <faw217@gmail.com>
+ * Copyright 2009 Fredy Yanardi <fyanardi@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "opensearchreader.h"
+
+#include "opensearchengine.h"
+
+#include <QtCore/QIODevice>
+
+OpenSearchReader::OpenSearchReader()
+    : QXmlStreamReader()
+{
+}
+
+OpenSearchEngine *OpenSearchReader::read(const QByteArray &data)
+{
+    clear();
+
+    addData(data);
+
+    return read();
+}
+
+OpenSearchEngine *OpenSearchReader::read(QIODevice *device)
+{
+    clear();
+
+    if (!device->isOpen()) {
+        device->open(QIODevice::ReadOnly);
+    }
+
+    setDevice(device);
+    return read();
+}
+
+OpenSearchEngine *OpenSearchReader::read()
+{
+    OpenSearchEngine *engine = new OpenSearchEngine();
+
+    while (!isStartElement() && !atEnd()) {
+        readNext();
+    }
+
+    if (name() != QLatin1String("OpenSearchDescription")
+        || namespaceUri() != QLatin1String("http://a9.com/-/spec/opensearch/1.1/")) {
+        raiseError(QObject::tr("The file is not an OpenSearch 1.1 file."));
+        return engine;
+    }
+
+    while (!(isEndElement() && name() == QLatin1String("OpenSearchDescription")) && !atEnd()) {
+        readNext();
+
+        if (!isStartElement()) {
+            continue;
+        }
+
+        if (name() == QLatin1String("ShortName")) {
+            engine->setName(readElementText());
+        }
+        else if (name() == QLatin1String("Description")) {
+            engine->setDescription(readElementText());
+        }
+        else if (name() == QLatin1String("Url")) {
+            QString type = attributes().value(QLatin1String("type")).toString();
+            QString url = attributes().value(QLatin1String("template")).toString();
+
+            if (url.isEmpty())
+                continue;
+
+            QList<OpenSearchEngine::Parameter> parameters;
+
+            readNext();
+
+            while (!(isEndElement() && name() == QLatin1String("Url"))) {
+                if (!isStartElement() || (name() != QLatin1String("Param") && name() != QLatin1String("Parameter"))) {
+                    readNext();
+                    continue;
+                }
+
+                QString key = attributes().value(QLatin1String("name")).toString();
+                QString value = attributes().value(QLatin1String("value")).toString();
+
+                if (!key.isEmpty() && !value.isEmpty()) {
+                    parameters.append(OpenSearchEngine::Parameter(key, value));
+                }
+
+                while (!isEndElement()) {
+                    readNext();
+                }
+            }
+
+            if (type == QLatin1String("application/x-suggestions+json")) {
+                engine->setSuggestionsUrlTemplate(url);
+                engine->setSuggestionsParameters(parameters);
+            }
+            else {
+                engine->setSearchUrlTemplate(url);
+                engine->setSearchParameters(parameters);
+            }
+        }
+        else if (name() == QLatin1String("Image")) {
+             engine->setImageUrl(readElementText());
+        }
+
+        if (!engine->name().isEmpty()
+            && !engine->description().isEmpty()
+            && !engine->suggestionsUrlTemplate().isEmpty()
+            && !engine->searchUrlTemplate().isEmpty()
+            && !engine->imageUrl().isEmpty()) {
+            break;
+        }
+    }
+
+    return engine;
+}
+
diff --git a/src/search/opensearchreader.h b/src/search/opensearchreader.h
new file mode 100644
index 00000000..5481881a
--- /dev/null
+++ b/src/search/opensearchreader.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2009 Jakub Wieczorek <faw217@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef OPENSEARCHREADER_H
+#define OPENSEARCHREADER_H
+
+#include <QtCore/QXmlStreamReader>
+
+class OpenSearchEngine;
+
+class OpenSearchReader : public QXmlStreamReader
+{
+public:
+    OpenSearchReader();
+
+    OpenSearchEngine *read(const QByteArray &data);
+    OpenSearchEngine *read(QIODevice *device);
+
+private:
+    OpenSearchEngine *read();
+};
+
+#endif // OPENSEARCHREADER_H
diff --git a/src/search/opensearchwriter.cpp b/src/search/opensearchwriter.cpp
new file mode 100644
index 00000000..a18ce0e2
--- /dev/null
+++ b/src/search/opensearchwriter.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2009 Jakub Wieczorek <faw217@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "opensearchwriter.h"
+
+#include "opensearchengine.h"
+
+#include <QtCore/QIODevice>
+
+#include <KDebug>
+
+OpenSearchWriter::OpenSearchWriter()
+    : QXmlStreamWriter()
+{
+    setAutoFormatting(true);
+}
+
+bool OpenSearchWriter::write(QIODevice *device, OpenSearchEngine *engine)
+{
+    if (!engine)
+        return false;
+
+    if (!device->isOpen())
+        device->open(QIODevice::WriteOnly);
+
+    setDevice(device);
+    write(engine);
+    return true;
+}
+
+void OpenSearchWriter::write(OpenSearchEngine *engine)
+{
+    writeStartDocument();
+    writeStartElement(QLatin1String("OpenSearchDescription"));
+    writeDefaultNamespace(QLatin1String("http://a9.com/-/spec/opensearch/1.1/"));
+
+    if (!engine->name().isEmpty()) {
+        writeTextElement(QLatin1String("ShortName"), engine->name());
+    }
+
+    if (!engine->description().isEmpty()) {
+        writeTextElement(QLatin1String("Description"), engine->description());
+    }
+
+    if (!engine->searchUrlTemplate().isEmpty()) {
+        writeStartElement(QLatin1String("Url"));
+        writeAttribute(QLatin1String("method"), QLatin1String("get"));
+        writeAttribute(QLatin1String("template"), engine->searchUrlTemplate());
+
+        if (!engine->searchParameters().empty()) {
+            writeNamespace(QLatin1String("http://a9.com/-/spec/opensearch/extensions/parameters/1.0/"), QLatin1String("p"));
+
+            QList<OpenSearchEngine::Parameter>::const_iterator end = engine->searchParameters().constEnd();
+            QList<OpenSearchEngine::Parameter>::const_iterator i = engine->searchParameters().constBegin();
+            for (; i != end; ++i) {
+                writeStartElement(QLatin1String("p:Parameter"));
+                writeAttribute(QLatin1String("name"), i->first);
+                writeAttribute(QLatin1String("value"), i->second);
+                writeEndElement();
+            }
+        }
+
+        writeEndElement();
+    }
+
+    if (!engine->suggestionsUrlTemplate().isEmpty()) {
+        writeStartElement(QLatin1String("Url"));
+        writeAttribute(QLatin1String("method"), QLatin1String("get"));
+        writeAttribute(QLatin1String("type"), QLatin1String("application/x-suggestions+json"));
+        writeAttribute(QLatin1String("template"), engine->suggestionsUrlTemplate());
+
+        if (!engine->suggestionsParameters().empty()) {
+            writeNamespace(QLatin1String("http://a9.com/-/spec/opensearch/extensions/parameters/1.0/"), QLatin1String("p"));
+
+            QList<OpenSearchEngine::Parameter>::const_iterator end = engine->suggestionsParameters().constEnd();
+            QList<OpenSearchEngine::Parameter>::const_iterator i = engine->suggestionsParameters().constBegin();
+            for (; i != end; ++i) {
+                writeStartElement(QLatin1String("p:Parameter"));
+                writeAttribute(QLatin1String("name"), i->first);
+                writeAttribute(QLatin1String("value"), i->second);
+                writeEndElement();
+            }
+        }
+
+        writeEndElement();
+    }
+
+    if (!engine->imageUrl().isEmpty())
+        writeTextElement(QLatin1String("Image"), engine->imageUrl());
+
+    writeEndElement();
+    writeEndDocument();
+}
+
diff --git a/src/search/opensearchwriter.h b/src/search/opensearchwriter.h
new file mode 100644
index 00000000..b089c4bb
--- /dev/null
+++ b/src/search/opensearchwriter.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2009 Jakub Wieczorek <faw217@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef OPENSEARCHWRITER_H
+#define OPENSEARCHWRITER_H
+
+#include <QtCore/QXmlStreamWriter>
+
+class QIODevice;
+
+class OpenSearchEngine;
+
+class OpenSearchWriter : public QXmlStreamWriter
+{
+public:
+    OpenSearchWriter();
+
+    bool write(QIODevice *device, OpenSearchEngine *engine);
+
+private:
+    void write(OpenSearchEngine *engine);
+};
+
+#endif
+
diff --git a/src/search/searchengine.cpp b/src/search/searchengine.cpp
new file mode 100644
index 00000000..0a66bb64
--- /dev/null
+++ b/src/search/searchengine.cpp
@@ -0,0 +1,153 @@
+/* ============================================================
+*
+* This file is a part of the rekonq project
+*
+* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com>
+* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr>
+*
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation; either version 2 of
+* the License or (at your option) version 3 or any later version
+* accepted by the membership of KDE e.V. (or its successor approved
+* by the membership of KDE e.V.), which shall act as a proxy
+* defined in Section 14 of version 3 of the license.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*
+* ============================================================ */
+
+
+//local includes
+#include "searchengine.h"
+
+// Auto Includes
+#include "rekonq.h"
+
+//KDE includes
+#include <KConfigGroup>
+#include <KServiceTypeTrader>
+
+
+QString SearchEngine::m_delimiter = "";
+
+
+QString SearchEngine::delimiter()
+{
+    if (m_delimiter == "") loadDelimiter();
+    return m_delimiter;
+}
+
+
+void SearchEngine::loadDelimiter()
+{
+    KConfig config("kuriikwsfilterrc"); //Share with konqueror
+    KConfigGroup cg = config.group("General");
+    m_delimiter = cg.readEntry("KeywordDelimiter", ":");
+}
+
+
+KService::Ptr SearchEngine::m_defaultWS;
+
+
+KService::Ptr SearchEngine::defaultWS()
+{
+    if (!m_defaultWS) loadDefaultWS();
+    return m_defaultWS;
+}
+
+
+void SearchEngine::loadDefaultWS()
+{
+    KConfig config("kuriikwsfilterrc"); //Share with konqueror
+    KConfigGroup cg = config.group("General");
+    QString d = cg.readEntry("DefaultSearchEngine", "google");
+    m_defaultWS = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(d));
+}
+
+
+KService::Ptr SearchEngine::fromString(QString text)
+{
+    KService::List providers = KServiceTypeTrader::self()->query("SearchProvider");
+    int i = 0;
+    bool found = false;
+    KService::Ptr service;
+    while (!found && i < providers.size())
+    {
+        QStringList list = providers.at(i)->property("Keys").toStringList();
+        foreach(const QString &key, list)
+        {
+            const QString searchPrefix = key + delimiter();
+            if (text.startsWith(searchPrefix))
+            {
+                service = providers.at(i);
+                found = true;
+            }
+        }
+        i++;
+    }
+
+    return service;
+}
+
+
+QString SearchEngine::buildQuery(KService::Ptr engine, QString text)
+{
+    QString query = engine->property("Query").toString();
+    query = query.replace("\\{@}", KUrl::toPercentEncoding(text));
+    return query;
+}
+
+
+KService::List SearchEngine::m_favorites;
+
+
+KService::List SearchEngine::favorites()
+{
+    if (m_favorites.isEmpty()) loadFavorites();
+    return m_favorites;
+}
+
+void SearchEngine::loadFavorites()
+{
+  KConfig config("kuriikwsfilterrc"); //Share with konqueror
+  KConfigGroup cg = config.group("General");
+  QStringList favoriteEngines;
+  favoriteEngines << "google"; //defaults
+  favoriteEngines = cg.readEntry("FavoriteSearchEngines", favoriteEngines);
+  
+  KService::List favorites;
+  KService::Ptr service;
+  foreach(const QString &engine, favoriteEngines)
+  {
+    service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(engine));
+    if (service)
+      favorites << service;
+  }
+  
+  m_favorites = favorites;
+}
+
+
+KService::Ptr SearchEngine::defaultEngine()
+{
+  KConfig config("kuriikwsfilterrc"); //Share with konqueror
+  KConfigGroup cg = config.group("General");
+  QString d = cg.readEntry("DefaultSearchEngine");
+  KService::Ptr service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(d));
+  if (!service)
+  {
+    d = QL1S("google");
+    service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(d));
+  }
+  
+  return service;
+  
+}
diff --git a/src/search/searchengine.h b/src/search/searchengine.h
new file mode 100644
index 00000000..2e30e056
--- /dev/null
+++ b/src/search/searchengine.h
@@ -0,0 +1,62 @@
+/* ============================================================
+*
+* This file is a part of the rekonq project
+*
+* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com>
+* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr>
+*
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation; either version 2 of
+* the License or (at your option) version 3 or any later version
+* accepted by the membership of KDE e.V. (or its successor approved
+* by the membership of KDE e.V.), which shall act as a proxy
+* defined in Section 14 of version 3 of the license.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*
+* ============================================================ */
+
+#ifndef SEARCHENGINE_H
+#define SEARCHENGINE_H
+
+
+// Rekonq Includes
+#include "rekonq_defines.h"
+
+// KDE Includes
+#include <KService>
+
+//Qt Includes
+#include <QString>
+
+
+class SearchEngine
+{
+public:
+
+    static QString delimiter();
+    static KService::Ptr defaultEngine();
+    static KService::List favorites();
+    static KService::Ptr fromString(QString text);
+    static QString buildQuery(KService::Ptr engine, QString text);
+    static KService::Ptr defaultWS();
+
+    static void loadDelimiter();
+    static void loadFavorites();
+    static void loadDefaultWS();
+
+private:
+    static QString m_delimiter;
+    static KService::List m_favorites;
+    static KService::Ptr m_defaultWS;
+};
+
+#endif
diff --git a/src/searchengine.cpp b/src/searchengine.cpp
deleted file mode 100644
index 0a66bb64..00000000
--- a/src/searchengine.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/* ============================================================
-*
-* This file is a part of the rekonq project
-*
-* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com>
-* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr>
-*
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License as
-* published by the Free Software Foundation; either version 2 of
-* the License or (at your option) version 3 or any later version
-* accepted by the membership of KDE e.V. (or its successor approved
-* by the membership of KDE e.V.), which shall act as a proxy
-* defined in Section 14 of version 3 of the license.
-*
-* This program 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 General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*
-* ============================================================ */
-
-
-//local includes
-#include "searchengine.h"
-
-// Auto Includes
-#include "rekonq.h"
-
-//KDE includes
-#include <KConfigGroup>
-#include <KServiceTypeTrader>
-
-
-QString SearchEngine::m_delimiter = "";
-
-
-QString SearchEngine::delimiter()
-{
-    if (m_delimiter == "") loadDelimiter();
-    return m_delimiter;
-}
-
-
-void SearchEngine::loadDelimiter()
-{
-    KConfig config("kuriikwsfilterrc"); //Share with konqueror
-    KConfigGroup cg = config.group("General");
-    m_delimiter = cg.readEntry("KeywordDelimiter", ":");
-}
-
-
-KService::Ptr SearchEngine::m_defaultWS;
-
-
-KService::Ptr SearchEngine::defaultWS()
-{
-    if (!m_defaultWS) loadDefaultWS();
-    return m_defaultWS;
-}
-
-
-void SearchEngine::loadDefaultWS()
-{
-    KConfig config("kuriikwsfilterrc"); //Share with konqueror
-    KConfigGroup cg = config.group("General");
-    QString d = cg.readEntry("DefaultSearchEngine", "google");
-    m_defaultWS = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(d));
-}
-
-
-KService::Ptr SearchEngine::fromString(QString text)
-{
-    KService::List providers = KServiceTypeTrader::self()->query("SearchProvider");
-    int i = 0;
-    bool found = false;
-    KService::Ptr service;
-    while (!found && i < providers.size())
-    {
-        QStringList list = providers.at(i)->property("Keys").toStringList();
-        foreach(const QString &key, list)
-        {
-            const QString searchPrefix = key + delimiter();
-            if (text.startsWith(searchPrefix))
-            {
-                service = providers.at(i);
-                found = true;
-            }
-        }
-        i++;
-    }
-
-    return service;
-}
-
-
-QString SearchEngine::buildQuery(KService::Ptr engine, QString text)
-{
-    QString query = engine->property("Query").toString();
-    query = query.replace("\\{@}", KUrl::toPercentEncoding(text));
-    return query;
-}
-
-
-KService::List SearchEngine::m_favorites;
-
-
-KService::List SearchEngine::favorites()
-{
-    if (m_favorites.isEmpty()) loadFavorites();
-    return m_favorites;
-}
-
-void SearchEngine::loadFavorites()
-{
-  KConfig config("kuriikwsfilterrc"); //Share with konqueror
-  KConfigGroup cg = config.group("General");
-  QStringList favoriteEngines;
-  favoriteEngines << "google"; //defaults
-  favoriteEngines = cg.readEntry("FavoriteSearchEngines", favoriteEngines);
-  
-  KService::List favorites;
-  KService::Ptr service;
-  foreach(const QString &engine, favoriteEngines)
-  {
-    service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(engine));
-    if (service)
-      favorites << service;
-  }
-  
-  m_favorites = favorites;
-}
-
-
-KService::Ptr SearchEngine::defaultEngine()
-{
-  KConfig config("kuriikwsfilterrc"); //Share with konqueror
-  KConfigGroup cg = config.group("General");
-  QString d = cg.readEntry("DefaultSearchEngine");
-  KService::Ptr service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(d));
-  if (!service)
-  {
-    d = QL1S("google");
-    service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(d));
-  }
-  
-  return service;
-  
-}
diff --git a/src/searchengine.h b/src/searchengine.h
deleted file mode 100644
index 2e30e056..00000000
--- a/src/searchengine.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ============================================================
-*
-* This file is a part of the rekonq project
-*
-* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com>
-* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr>
-*
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License as
-* published by the Free Software Foundation; either version 2 of
-* the License or (at your option) version 3 or any later version
-* accepted by the membership of KDE e.V. (or its successor approved
-* by the membership of KDE e.V.), which shall act as a proxy
-* defined in Section 14 of version 3 of the license.
-*
-* This program 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 General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*
-* ============================================================ */
-
-#ifndef SEARCHENGINE_H
-#define SEARCHENGINE_H
-
-
-// Rekonq Includes
-#include "rekonq_defines.h"
-
-// KDE Includes
-#include <KService>
-
-//Qt Includes
-#include <QString>
-
-
-class SearchEngine
-{
-public:
-
-    static QString delimiter();
-    static KService::Ptr defaultEngine();
-    static KService::List favorites();
-    static KService::Ptr fromString(QString text);
-    static QString buildQuery(KService::Ptr engine, QString text);
-    static KService::Ptr defaultWS();
-
-    static void loadDelimiter();
-    static void loadFavorites();
-    static void loadDefaultWS();
-
-private:
-    static QString m_delimiter;
-    static KService::List m_favorites;
-    static KService::Ptr m_defaultWS;
-};
-
-#endif
diff --git a/src/settings/settingsdialog.cpp b/src/settings/settingsdialog.cpp
index cd64f434..d53b1900 100644
--- a/src/settings/settingsdialog.cpp
+++ b/src/settings/settingsdialog.cpp
@@ -36,7 +36,7 @@
 #include "application.h"
 #include "mainwindow.h"
 #include "webtab.h"
-#include "searchengine.h"
+#include "search/searchengine.h"
 
 // Widget Includes
 #include "adblockwidget.h"
diff --git a/src/urlbar/completionwidget.cpp b/src/urlbar/completionwidget.cpp
index b77e2d7c..8e72b26b 100644
--- a/src/urlbar/completionwidget.cpp
+++ b/src/urlbar/completionwidget.cpp
@@ -34,7 +34,7 @@
 // Local Includes
 #include "application.h"
 #include "urlresolver.h"
-#include "searchengine.h"
+#include "search/searchengine.h"
 #include "urlbar.h"
 
 // KDE Includes
diff --git a/src/urlbar/listitem.cpp b/src/urlbar/listitem.cpp
index f10cefd7..c9946257 100644
--- a/src/urlbar/listitem.cpp
+++ b/src/urlbar/listitem.cpp
@@ -36,7 +36,7 @@
 #include "application.h"
 #include "websnap.h"
 #include "completionwidget.h"
-#include "searchengine.h"
+#include "search/searchengine.h"
 
 // KDE Includes
 #include <KIcon>
@@ -161,6 +161,7 @@ TypeIconLabel::TypeIconLabel(int type, QWidget *parent)
     if (type & UrlSearchItem::Browse) hLayout->addWidget(getIcon("applications-internet"));
     if (type & UrlSearchItem::Bookmark) hLayout->addWidget(getIcon("rating"));
     if (type & UrlSearchItem::History) hLayout->addWidget(getIcon("view-history"));
+    if (type & UrlSearchItem::Suggestion) hLayout->addWidget(getIcon("help-hint"));
 }
 
 
@@ -390,6 +391,23 @@ void EngineBar::selectNextEngine()
 // ---------------------------------------------------------------
 
 
+SuggestionListItem::SuggestionListItem(const UrlSearchItem &item, const QString &text, QWidget *parent)
+        : ListItem(item, parent)
+{
+    QHBoxLayout *hLayout = new QHBoxLayout;
+    hLayout->setSpacing(4);
+
+    hLayout->addWidget(new IconLabel(item.url, this));
+    hLayout->addWidget(new TextLabel(item.title, text, this));
+    hLayout->addWidget(new TypeIconLabel(item.type, this));
+
+    setLayout(hLayout);
+}
+
+
+// ---------------------------------------------------------------
+
+
 BrowseListItem::BrowseListItem(const UrlSearchItem &item, const QString &text, QWidget *parent)
         : ListItem(item, parent)
 {
@@ -427,7 +445,15 @@ ListItem *ListItemFactory::create(const UrlSearchItem &item, const QString &text
         }
         else
         {
-            newItem = new PreviewListItem(item, text, parent);
+
+            if (item.type & UrlSearchItem::Suggestion)
+            {
+                newItem = new SuggestionListItem(item, text, parent);
+            }
+            else
+            {
+                newItem = new PreviewListItem(item, text, parent);
+            }
         }
     }
 
diff --git a/src/urlbar/listitem.h b/src/urlbar/listitem.h
index dcb4f76d..0e1a7ad5 100644
--- a/src/urlbar/listitem.h
+++ b/src/urlbar/listitem.h
@@ -174,6 +174,18 @@ private:
 // -------------------------------------------------------------------------
 
 
+class SuggestionListItem : public ListItem
+{
+    Q_OBJECT
+
+public:
+    SuggestionListItem(const UrlSearchItem &item, const QString &text, QWidget *parent = 0);
+};
+
+
+// -------------------------------------------------------------------------
+
+
 class PreviewListItem : public ListItem
 {
     Q_OBJECT
diff --git a/src/urlbar/urlresolver.cpp b/src/urlbar/urlresolver.cpp
index f0fd257b..157e26a2 100644
--- a/src/urlbar/urlresolver.cpp
+++ b/src/urlbar/urlresolver.cpp
@@ -31,7 +31,7 @@
 #include "application.h"
 #include "historymanager.h"
 #include "bookmarksmanager.h"
-#include "searchengine.h"
+#include "search/searchengine.h"
 
 // KDE Includes
 #include <KUriFilter>
@@ -243,11 +243,14 @@ UrlSearchList UrlResolver::orderedSearchItems()
         
         availableEntries -= commonList.count();
     }
+
+    UrlSearchList suggestionsList = suggestionResolution();
     
     historyResults = historyList.count();
     bookmarksResults = bookmarksList.count();
     commonResutls = commonList.count();
-    
+    //TODO: count suggestions entries
+
     //now fill the list to MAX_ELEMENTS
     if(availableEntries > 0)
     {
@@ -275,7 +278,7 @@ UrlSearchList UrlResolver::orderedSearchItems()
         }
     }
     
-    list = list + historyList + commonList + bookmarksList;
+    list = list + historyList + commonList + bookmarksList + suggestionsList;
     qWarning() << "orderedSearchItems leave: " << " elapsed: " << myTime.elapsed();
     
     return list;
@@ -343,6 +346,18 @@ UrlSearchList UrlResolver::bookmarksResolution()
 }
 
 
+// STEP 4 = suggestion completion
+UrlSearchList UrlResolver::suggestionResolution()
+{
+    
+    UrlSearchList list;
+    UrlSearchItem gItem(UrlSearchItem::Suggestion, "a", "a");
+    list << gItem;
+
+    return list;
+}
+
+
 UrlSearchItem UrlResolver::privilegedItem(UrlSearchList* list)
 {
     UrlSearchItem item;
diff --git a/src/urlbar/urlresolver.h b/src/urlbar/urlresolver.h
index c79ce184..d41e3f1a 100644
--- a/src/urlbar/urlresolver.h
+++ b/src/urlbar/urlresolver.h
@@ -50,6 +50,7 @@ public:
         Browse          = 0x00000010,
         History         = 0x00000100,
         Bookmark        = 0x00001000,
+        Suggestion      = 0x00010000,
     };
 
     int type;
@@ -108,7 +109,8 @@ private:
     UrlSearchList qurlFromUserInputResolution();
     UrlSearchList bookmarksResolution();
     UrlSearchItem privilegedItem(UrlSearchList* list);
-     
+    UrlSearchList suggestionResolution();
+
     static QRegExp _browseRegexp;
     static QRegExp _searchEnginesRegexp;
 };
diff --git a/src/webview.cpp b/src/webview.cpp
index 441225af..195f38af 100644
--- a/src/webview.cpp
+++ b/src/webview.cpp
@@ -37,7 +37,7 @@
 #include "mainview.h"
 #include "webpage.h"
 #include "bookmarksmanager.h"
-#include "searchengine.h"
+#include "search/searchengine.h"
 #include "websnap.h"
 
 // KDE Includes
-- 
cgit v1.2.1