diff --git a/CMakeLists.txt b/CMakeLists.txt
index f2a12dcea..5ee953754 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,8 +65,8 @@ project(rssguard)
set(APP_NAME "RSS Guard")
set(APP_LOW_NAME "rssguard")
-set(APP_VERSION "2.4.0")
-set(FILE_VERSION "2,4,0,0")
+set(APP_VERSION "2.4.1")
+set(FILE_VERSION "2,4,1,0")
set(APP_AUTHOR "Martin Rotter")
set(APP_URL "http://bitbucket.org/skunkos/rssguard")
set(APP_URL_ISSUES "http://bitbucket.org/skunkos/rssguard/issues")
@@ -417,6 +417,7 @@ set(APP_SOURCES
src/network-web/downloader.cpp
src/network-web/downloadmanager.cpp
src/network-web/discoverfeedsbutton.cpp
+ src/network-web/googlesuggest.cpp
# MAIN sources.
src/main.cpp
@@ -503,6 +504,7 @@ set(APP_HEADERS
src/network-web/downloader.h
src/network-web/downloadmanager.h
src/network-web/discoverfeedsbutton.h
+ src/network-web/googlesuggest.h
)
# APP form files.
diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG
index 117b1be7b..dec73ab4c 100644
--- a/resources/text/CHANGELOG
+++ b/resources/text/CHANGELOG
@@ -1,4 +1,16 @@
+2.4.1
+Added:
+
+- Added support for Google auto-suggest API. Just type your phrase in internal web browser location text box and Google will help you out.
+
+
+Fixed:
+
+
+
2.4.0
Added:
diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in
index c0895794c..28336dfc6 100755
--- a/src/definitions/definitions.h.in
+++ b/src/definitions/definitions.h.in
@@ -83,6 +83,7 @@
#define MIME_TYPE_ITEM_POINTER "@APP_LOW_NAME@/itempointer"
#define DOWNLOADER_ICON_SIZE 48
#define GOOGLE_SEARCH_URL "https://www.google.com/search?q=%1&ie=utf-8&oe=utf-8"
+#define GOOGLE_SUGGEST_URL "http://suggestqueries.google.com/complete/search?output=toolbar&hl=en&q=%1"
#define FEED_INITIAL_OPML_PATTERN "feeds-%1.opml"
diff --git a/src/gui/baselineedit.cpp b/src/gui/baselineedit.cpp
old mode 100644
new mode 100755
index ad42a3851..76f7a65f5
--- a/src/gui/baselineedit.cpp
+++ b/src/gui/baselineedit.cpp
@@ -26,6 +26,11 @@ BaseLineEdit::BaseLineEdit(QWidget *parent) : QLineEdit(parent) {
BaseLineEdit::~BaseLineEdit() {
}
+void BaseLineEdit::submit(const QString &text) {
+ setText(text);
+ emit submitted(text);
+}
+
void BaseLineEdit::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
emit submitted(text());
diff --git a/src/gui/baselineedit.h b/src/gui/baselineedit.h
old mode 100644
new mode 100755
index 312aa223c..743369508
--- a/src/gui/baselineedit.h
+++ b/src/gui/baselineedit.h
@@ -29,6 +29,9 @@ class BaseLineEdit : public QLineEdit {
explicit BaseLineEdit(QWidget *parent = 0);
virtual ~BaseLineEdit();
+ public slots:
+ void submit(const QString &text);
+
protected:
void keyPressEvent(QKeyEvent *event);
diff --git a/src/gui/locationlineedit.cpp b/src/gui/locationlineedit.cpp
old mode 100644
new mode 100755
index 149ceadef..ffa9311bc
--- a/src/gui/locationlineedit.cpp
+++ b/src/gui/locationlineedit.cpp
@@ -17,15 +17,18 @@
#include "gui/locationlineedit.h"
+#include "network-web/googlesuggest.h"
+
#include
LocationLineEdit::LocationLineEdit(QWidget *parent)
- : BaseLineEdit(parent), m_mouseSelectsAllText(true) {
+ : BaseLineEdit(parent), m_mouseSelectsAllText(true), m_googleSuggest(new GoogleSuggest(this)) {
setPlaceholderText(tr("Website address goes here"));
}
LocationLineEdit::~LocationLineEdit() {
+
}
void LocationLineEdit::focusOutEvent(QFocusEvent *event) {
diff --git a/src/gui/locationlineedit.h b/src/gui/locationlineedit.h
old mode 100644
new mode 100755
index 9bb8e03aa..57b24c7ac
--- a/src/gui/locationlineedit.h
+++ b/src/gui/locationlineedit.h
@@ -22,6 +22,7 @@
class WebBrowser;
+class GoogleSuggest;
class LocationLineEdit : public BaseLineEdit {
Q_OBJECT
@@ -37,6 +38,7 @@ class LocationLineEdit : public BaseLineEdit {
private:
bool m_mouseSelectsAllText;
+ GoogleSuggest *m_googleSuggest;
};
#endif // LOCATIONLINEEDIT_H
diff --git a/src/network-web/googlesuggest.cpp b/src/network-web/googlesuggest.cpp
new file mode 100755
index 000000000..fc6fb61e5
--- /dev/null
+++ b/src/network-web/googlesuggest.cpp
@@ -0,0 +1,203 @@
+// This file is part of RSS Guard.
+//
+// Copyright (C) 2011-2015 by Martin Rotter
+//
+// RSS Guard 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 3 of the License, or
+// (at your option) any later version.
+//
+// RSS Guard 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 RSS Guard. If not, see .
+
+// You may use this file under the terms of the BSD license as follows:
+//
+// "Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+// of its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+
+#include "network-web/googlesuggest.h"
+
+#include "definitions/definitions.h"
+#include "network-web/webbrowsernetworkaccessmanager.h"
+#include "gui/locationlineedit.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+GoogleSuggest::GoogleSuggest(LocationLineEdit *editor, QObject *parent) : QObject(parent), editor(editor) {
+ popup = new QListWidget();
+ popup->setWindowFlags(Qt::Popup);
+ popup->setFocusPolicy(Qt::NoFocus);
+ popup->setFocusProxy(editor);
+ popup->setMouseTracking(true);
+ popup->setSelectionBehavior(QAbstractItemView::SelectRows);
+ popup->setFrameStyle(QFrame::Box | QFrame::Plain);
+ popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ popup->installEventFilter(this);
+
+ timer = new QTimer(this);
+ timer->setSingleShot(true);
+ timer->setInterval(500);
+
+ connect(popup, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(doneCompletion()));
+ connect(timer, SIGNAL(timeout()), SLOT(autoSuggest()));
+ connect(editor, SIGNAL(textEdited(QString)), timer, SLOT(start()));
+}
+
+GoogleSuggest::~GoogleSuggest() {
+ delete popup;
+}
+
+bool GoogleSuggest::eventFilter(QObject *object, QEvent *event) {
+ if (object != popup) {
+ return false;
+ }
+
+ if (event->type() == QEvent::MouseButtonPress) {
+ popup->hide();
+ editor->setFocus();
+ return true;
+ }
+
+ if (event->type() == QEvent::KeyPress) {
+ bool consumed = false;
+ int key = static_cast(event)->key();
+
+ switch (key) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ doneCompletion();
+ consumed = true;
+
+ case Qt::Key_Escape:
+ editor->setFocus();
+ popup->hide();
+ consumed = true;
+
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ break;
+
+ default:
+ editor->setFocus();
+ editor->event(event);
+ popup->hide();
+ break;
+ }
+
+ return consumed;
+ }
+
+ return false;
+}
+
+void GoogleSuggest::showCompletion(const QStringList &choices) {
+ if (choices.isEmpty()) {
+ return;
+ }
+
+ popup->setUpdatesEnabled(false);
+ popup->clear();
+
+ foreach (const QString &choice, choices) {
+ new QListWidgetItem(choice, popup);
+ }
+
+ popup->setCurrentItem(popup->item(0));
+ popup->adjustSize();
+ popup->setUpdatesEnabled(true);
+ popup->resize(editor->width(), popup->sizeHintForRow(0) * qMin(7, choices.count()) + 3);
+ popup->move(editor->mapToGlobal(QPoint(0, editor->height())));
+ popup->setFocus();
+ popup->show();
+}
+
+void GoogleSuggest::doneCompletion() {
+ timer->stop();
+ popup->hide();
+ editor->setFocus();
+
+ QListWidgetItem *item = popup->currentItem();
+
+ if (item != NULL) {
+ editor->submit(QString(GOOGLE_SEARCH_URL).arg(item->text()));
+ }
+}
+
+void GoogleSuggest::preventSuggest() {
+ timer->stop();
+}
+
+void GoogleSuggest::autoSuggest() {
+ QString str = QUrl::toPercentEncoding(editor->text());
+ QString url = QString(GOOGLE_SUGGEST_URL).arg(str);
+
+ connect(WebBrowserNetworkAccessManager::instance()->get(QNetworkRequest(QString(url))), SIGNAL(finished()),
+ this, SLOT(handleNetworkData()));
+}
+
+void GoogleSuggest::handleNetworkData() {
+ QNetworkReply *reply = static_cast(sender());
+
+ if (!reply->error()) {
+ QStringList choices;
+ QDomDocument xml;
+ QByteArray response = reply->readAll();
+
+ QTextCodec *c = QTextCodec::codecForUtfText(response);
+ xml.setContent(c->toUnicode(response));
+
+ QDomNodeList suggestions = xml.elementsByTagName("suggestion");
+
+ for (int i = 0; i < suggestions.size(); i++) {
+ QDomElement element = suggestions.at(i).toElement();
+
+ if (element.attributes().contains("data")) {
+ choices.append(element.attribute("data"));
+ }
+ }
+
+ showCompletion(choices);
+ }
+
+ reply->deleteLater();
+}
diff --git a/src/network-web/googlesuggest.h b/src/network-web/googlesuggest.h
new file mode 100755
index 000000000..cd63de156
--- /dev/null
+++ b/src/network-web/googlesuggest.h
@@ -0,0 +1,81 @@
+// This file is part of RSS Guard.
+//
+// Copyright (C) 2011-2015 by Martin Rotter
+//
+// RSS Guard 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 3 of the License, or
+// (at your option) any later version.
+//
+// RSS Guard 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 RSS Guard. If not, see .
+
+// You may use this file under the terms of the BSD license as follows:
+//
+// "Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+// of its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+
+#ifndef GOOGLESUGGEST_H
+#define GOOGLESUGGEST_H
+
+#include
+
+
+class LocationLineEdit;
+class QNetworkReply;
+class QTimer;
+class QListWidget;
+class QNetworkAccessManager;
+
+class GoogleSuggest : public QObject {
+ Q_OBJECT
+
+ public:
+ // Constructors.
+ explicit GoogleSuggest(LocationLineEdit *editor, QObject *parent = 0);
+ virtual ~GoogleSuggest();
+
+ bool eventFilter(QObject *object, QEvent *event);
+ void showCompletion(const QStringList &choices);
+
+ public slots:
+ void doneCompletion();
+ void preventSuggest();
+ void autoSuggest();
+ void handleNetworkData();
+
+ private:
+ LocationLineEdit *editor;
+ QListWidget *popup;
+ QTimer *timer;
+};
+
+#endif // GOOGLESUGGEST_H