]> git.sur5r.net Git - minitube/blob - src/googlesuggest.cpp
Suggestions from YouTube data, not Google search
[minitube] / src / googlesuggest.cpp
1 #include "googlesuggest.h"
2 #include "networkaccess.h"
3
4 #define GSUGGEST_URL "http://suggestqueries.google.com/complete/search?ds=yt&output=toolbar&hl=%1&q=%2"
5
6 namespace The {
7     NetworkAccess* http();
8 }
9
10 GSuggestCompletion::GSuggestCompletion(QLineEdit *parent): QObject(parent), editor(parent) {
11
12     popup = new QListWidget;
13     popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
14
15     popup->installEventFilter(this);
16     popup->setMouseTracking(true);
17
18     connect(popup, SIGNAL(itemClicked(QListWidgetItem*)),
19             SLOT(doneCompletion()));
20
21     connect(popup, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
22             SLOT(currentItemChanged(QListWidgetItem *)));
23
24     connect(popup, SIGNAL(itemEntered(QListWidgetItem*)),
25             SLOT(currentItemChanged(QListWidgetItem *)));
26
27     popup->setWindowFlags(Qt::Popup);
28     popup->setFocusPolicy(Qt::NoFocus);
29     popup->setFocusProxy(parent);
30
31     timer = new QTimer(this);
32     timer->setSingleShot(true);
33     timer->setInterval(250);
34     connect(timer, SIGNAL(timeout()), SLOT(autoSuggest()));
35     connect(editor, SIGNAL(textEdited(QString)), timer, SLOT(start()));
36
37 }
38
39 GSuggestCompletion::~GSuggestCompletion() {
40     delete popup;
41 }
42
43 bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev) {
44     if (obj != popup)
45         return false;
46
47     if (ev->type() == QEvent::MouseButtonPress) {
48         popup->hide();
49         editor->setFocus();
50         editor->setText(originalText);
51         return true;
52     }
53
54     if (ev->type() == QEvent::KeyPress) {
55
56         bool consumed = false;
57         int key = static_cast<QKeyEvent*>(ev)->key();
58         switch (key) {
59         case Qt::Key_Enter:
60         case Qt::Key_Return:
61             if (popup->currentItem()) {
62                 doneCompletion();
63                 consumed = true;
64             } else {
65                 editor->setFocus();
66                 editor->event(ev);
67                 popup->hide();
68             }
69             break;
70
71         case Qt::Key_Escape:
72             editor->setFocus();
73             editor->setText(originalText);
74             popup->hide();
75             consumed = true;
76             break;
77
78         case Qt::Key_Up:
79         case Qt::Key_Down:
80         case Qt::Key_Home:
81         case Qt::Key_End:
82         case Qt::Key_PageUp:
83         case Qt::Key_PageDown:
84             break;
85
86         default:
87             editor->setFocus();
88             editor->event(ev);
89             popup->hide();
90             break;
91         }
92
93         return consumed;
94     }
95
96     return false;
97 }
98
99 void GSuggestCompletion::showCompletion(const QStringList &choices) {
100
101     if (choices.isEmpty())
102         return;
103
104     popup->setUpdatesEnabled(false);
105     popup->clear();
106     for (int i = 0; i < choices.count(); ++i) {
107         QListWidgetItem * item;
108         item = new QListWidgetItem(popup);
109         item->setText(choices[i]);
110     }
111     popup->setCurrentItem(0);
112     popup->adjustSize();
113     popup->setUpdatesEnabled(true);
114
115     popup->move(editor->mapToGlobal(QPoint(0, editor->height())));
116     popup->setFocus();
117     popup->show();
118 }
119
120 void GSuggestCompletion::doneCompletion() {
121     timer->stop();
122     popup->hide();
123     editor->setFocus();
124     QListWidgetItem *item = popup->currentItem();
125     if (item) {
126         editor->setText(item->text());
127         QKeyEvent *e;
128         e = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
129         QApplication::postEvent(editor, e);
130         e = new QKeyEvent(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier);
131         QApplication::postEvent(editor, e);
132     }
133 }
134
135 void GSuggestCompletion::preventSuggest() {
136     timer->stop();
137 }
138
139 void GSuggestCompletion::autoSuggest() {
140     QString str = editor->text();
141     originalText = str;
142     qDebug() << "originalText" << originalText;
143     if (str.isEmpty()) return;
144
145     QString url = QString(GSUGGEST_URL).arg(QLocale::system().name().replace("_", "-"), str);
146
147     QObject *reply = The::http()->get(url);
148     connect(reply, SIGNAL(data(QByteArray)), SLOT(handleNetworkData(QByteArray)));
149 }
150
151 void GSuggestCompletion::handleNetworkData(QByteArray response) {
152
153     QStringList choices;
154
155     QXmlStreamReader xml(response);
156     while (!xml.atEnd()) {
157         xml.readNext();
158         if (xml.tokenType() == QXmlStreamReader::StartElement)
159             if (xml.name() == "suggestion") {
160             QStringRef str = xml.attributes().value("data");
161             choices << str.toString();
162         }
163     }
164
165     showCompletion(choices);
166
167 }
168
169 void GSuggestCompletion::currentItemChanged(QListWidgetItem *current) {
170     if (current) {
171         qDebug() << "current" << current->text();
172         current->setSelected(true);
173         editor->setText(current->text());
174         editor->setSelection(originalText.length(), editor->text().length());
175     } else {
176         popup->clearSelection();
177     }
178 }