From baf4d5b6882803c96fbbdc528f7cb71bd849288d Mon Sep 17 00:00:00 2001 From: Flavio Tordini Date: Tue, 21 Jul 2009 22:14:45 +0200 Subject: [PATCH] Google suggest --- minitube.pro | 8 +- src/googlesuggest.cpp | 178 +++++++++++++++++++++++++++++++++++++++++ src/googlesuggest.h | 30 +++++++ src/searchlineedit.cpp | 14 +++- src/searchlineedit.h | 3 + 5 files changed, 226 insertions(+), 7 deletions(-) create mode 100644 src/googlesuggest.cpp create mode 100644 src/googlesuggest.h diff --git a/minitube.pro b/minitube.pro index eb397e5..1518c59 100755 --- a/minitube.pro +++ b/minitube.pro @@ -1,6 +1,5 @@ # On some distro, Phonon headers cannot be found INCLUDEPATH += /usr/include/phonon - CONFIG += release TEMPLATE = app @@ -41,7 +40,8 @@ HEADERS += src/MainWindow.h \ src/searchparams.h \ src/minisplitter.h \ src/loadingwidget.h \ - src/videoareawidget.h + src/videoareawidget.h \ + src/googlesuggest.h SOURCES += src/main.cpp \ src/MainWindow.cpp \ src/SearchView.cpp \ @@ -65,7 +65,8 @@ SOURCES += src/main.cpp \ src/searchparams.cpp \ src/minisplitter.cpp \ src/loadingwidget.cpp \ - src/videoareawidget.cpp + src/videoareawidget.cpp \ + src/googlesuggest.cpp RESOURCES += resources.qrc DESTDIR = build/target/ OBJECTS_DIR = build/obj/ @@ -105,6 +106,7 @@ unix { translations.files += $$DESTDIR/locale desktop.path = $$DATADIR/applications desktop.files += minitube.desktop + # iconxpm.path = $$DATADIR/pixmaps # iconxpm.files += data/minitube.xpm iconsvg.path = $$DATADIR/icons/hicolor/scalable/apps diff --git a/src/googlesuggest.cpp b/src/googlesuggest.cpp new file mode 100644 index 0000000..0ad1932 --- /dev/null +++ b/src/googlesuggest.cpp @@ -0,0 +1,178 @@ +#include "googlesuggest.h" +#include "networkaccess.h" + +#define GSUGGEST_URL "http://suggestqueries.google.com/complete/search?output=toolbar&hl=%1&q=%2" + +namespace The { + NetworkAccess* http(); +} + +GSuggestCompletion::GSuggestCompletion(QLineEdit *parent): QObject(parent), editor(parent) { + + popup = new QListWidget; + popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + popup->installEventFilter(this); + popup->setMouseTracking(true); + + connect(popup, SIGNAL(itemClicked(QListWidgetItem*)), + SLOT(doneCompletion())); + + connect(popup, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), + SLOT(currentItemChanged(QListWidgetItem *))); + + connect(popup, SIGNAL(itemEntered(QListWidgetItem*)), + SLOT(currentItemChanged(QListWidgetItem *))); + + popup->setWindowFlags(Qt::Popup); + popup->setFocusPolicy(Qt::NoFocus); + popup->setFocusProxy(parent); + + timer = new QTimer(this); + timer->setSingleShot(true); + timer->setInterval(250); + connect(timer, SIGNAL(timeout()), SLOT(autoSuggest())); + connect(editor, SIGNAL(textEdited(QString)), timer, SLOT(start())); + +} + +GSuggestCompletion::~GSuggestCompletion() { + delete popup; +} + +bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev) { + if (obj != popup) + return false; + + if (ev->type() == QEvent::MouseButtonPress) { + popup->hide(); + editor->setFocus(); + editor->setText(originalText); + return true; + } + + if (ev->type() == QEvent::KeyPress) { + + bool consumed = false; + int key = static_cast(ev)->key(); + switch (key) { + case Qt::Key_Enter: + case Qt::Key_Return: + if (popup->currentItem()) { + doneCompletion(); + consumed = true; + } else { + editor->setFocus(); + editor->event(ev); + popup->hide(); + } + break; + + case Qt::Key_Escape: + editor->setFocus(); + editor->setText(originalText); + popup->hide(); + consumed = true; + break; + + 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(ev); + popup->hide(); + break; + } + + return consumed; + } + + return false; +} + +void GSuggestCompletion::showCompletion(const QStringList &choices) { + + if (choices.isEmpty()) + return; + + popup->setUpdatesEnabled(false); + popup->clear(); + for (int i = 0; i < choices.count(); ++i) { + QListWidgetItem * item; + item = new QListWidgetItem(popup); + item->setText(choices[i]); + } + popup->setCurrentItem(0); + popup->adjustSize(); + popup->setUpdatesEnabled(true); + + popup->move(editor->mapToGlobal(QPoint(0, editor->height()))); + popup->setFocus(); + popup->show(); +} + +void GSuggestCompletion::doneCompletion() { + timer->stop(); + popup->hide(); + editor->setFocus(); + QListWidgetItem *item = popup->currentItem(); + if (item) { + editor->setText(item->text()); + QKeyEvent *e; + e = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); + QApplication::postEvent(editor, e); + e = new QKeyEvent(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); + QApplication::postEvent(editor, e); + } +} + +void GSuggestCompletion::preventSuggest() { + timer->stop(); +} + +void GSuggestCompletion::autoSuggest() { + QString str = editor->text(); + originalText = str; + qDebug() << "originalText" << originalText; + if (str.isEmpty()) return; + + QString url = QString(GSUGGEST_URL).arg(QLocale::system().name().replace("_", "-"), str); + + QObject *reply = The::http()->get(url); + connect(reply, SIGNAL(data(QByteArray)), SLOT(handleNetworkData(QByteArray))); +} + +void GSuggestCompletion::handleNetworkData(QByteArray response) { + + QStringList choices; + + QXmlStreamReader xml(response); + while (!xml.atEnd()) { + xml.readNext(); + if (xml.tokenType() == QXmlStreamReader::StartElement) + if (xml.name() == "suggestion") { + QStringRef str = xml.attributes().value("data"); + choices << str.toString(); + } + } + + showCompletion(choices); + +} + +void GSuggestCompletion::currentItemChanged(QListWidgetItem *current) { + if (current) { + qDebug() << "current" << current->text(); + current->setSelected(true); + editor->setText(current->text()); + editor->setSelection(originalText.length(), editor->text().length()); + } else { + popup->clearSelection(); + } +} diff --git a/src/googlesuggest.h b/src/googlesuggest.h new file mode 100644 index 0000000..8ca766b --- /dev/null +++ b/src/googlesuggest.h @@ -0,0 +1,30 @@ +#ifndef GOOGLESUGGEST_H +#define GOOGLESUGGEST_H + +#include + +class GSuggestCompletion : public QObject { + Q_OBJECT + +public: + GSuggestCompletion(QLineEdit *parent); + ~GSuggestCompletion(); + bool eventFilter(QObject *obj, QEvent *ev); + void showCompletion(const QStringList &choices); + +public slots: + void doneCompletion(); + void preventSuggest(); + void autoSuggest(); + void handleNetworkData(QByteArray response); + void currentItemChanged(QListWidgetItem *current); + +private: + QLineEdit *editor; + QString originalText; + QListWidget *popup; + QTimer *timer; + +}; + +#endif // GOOGLESUGGEST_H diff --git a/src/searchlineedit.cpp b/src/searchlineedit.cpp index 8a42d8a..3c4e1fa 100644 --- a/src/searchlineedit.cpp +++ b/src/searchlineedit.cpp @@ -43,8 +43,10 @@ #include #include +#include "googlesuggest.h" + ClearButton::ClearButton(QWidget *parent) - : QAbstractButton(parent) + : QAbstractButton(parent) { setCursor(Qt::ArrowCursor); setToolTip(tr("Clear")); @@ -95,8 +97,8 @@ protected: }; SearchButton::SearchButton(QWidget *parent) - : QAbstractButton(parent), - m_menu(0) + : QAbstractButton(parent), + m_menu(0) { setObjectName(QLatin1String("SearchButton")); setCursor(Qt::ArrowCursor); @@ -159,7 +161,7 @@ void SearchButton::paintEvent(QPaintEvent *event) - When there is text a clear button is displayed on the right hand side */ SearchLineEdit::SearchLineEdit(QWidget *parent) : ExLineEdit(parent), - m_searchButton(new SearchButton(this)) +m_searchButton(new SearchButton(this)) { connect(lineEdit(), SIGNAL(textChanged(const QString &)), this, SIGNAL(textChanged(const QString &))); @@ -172,6 +174,9 @@ SearchLineEdit::SearchLineEdit(QWidget *parent) : ExLineEdit(parent), QSizePolicy policy = sizePolicy(); setSizePolicy(QSizePolicy::Preferred, policy.verticalPolicy()); + + // completion + completion = new GSuggestCompletion(m_lineEdit); } void SearchLineEdit::paintEvent(QPaintEvent *event) @@ -238,5 +243,6 @@ QMenu *SearchLineEdit::menu() const void SearchLineEdit::returnPressed() { + completion->preventSuggest(); emit search(lineEdit()->text()); } diff --git a/src/searchlineedit.h b/src/searchlineedit.h index b7b8005..99ab266 100644 --- a/src/searchlineedit.h +++ b/src/searchlineedit.h @@ -48,6 +48,7 @@ class QMenu; QT_END_NAMESPACE class SearchButton; +class GSuggestCompletion; /* Clear button on the right hand side of the search widget. @@ -97,6 +98,8 @@ private: SearchButton *m_searchButton; QString m_inactiveText; + + GSuggestCompletion *completion; }; #endif // SEARCHLINEEDIT_H -- 2.39.5