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