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