3 This file is part of Minitube.
4 Copyright 2013, Flavio Tordini <flavio.tordini@gmail.com>
6 Minitube is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 Minitube is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Minitube. If not, see <http://www.gnu.org/licenses/>.
20 #include "autocomplete.h"
21 #include "suggester.h"
23 #include "searchlineedit_mac.h"
25 #include "searchlineedit.h"
28 AutoComplete::AutoComplete(SearchLineEdit *buddy, QLineEdit *lineEdit):
29 QObject(buddy), buddy(buddy), lineEdit(lineEdit), suggester(0) {
33 popup = new QListWidget();
34 popup->setMouseTracking(true);
35 popup->setWindowFlags(Qt::Popup);
36 popup->setAttribute(Qt::WA_ShowWithoutActivating);
37 popup->setFocusPolicy(Qt::NoFocus);
38 popup->setFocusProxy(buddy);
39 popup->installEventFilter(this);
41 popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
42 popup->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
43 popup->setWindowOpacity(.9);
44 popup->setProperty("suggest", true);
45 popup->setFrameShape(QFrame::NoFrame);
46 popup->setAttribute(Qt::WA_TranslucentBackground);
47 popup->viewport()->setStyleSheet("border:0; border-radius:5px; background:palette(base)");
49 connect(popup, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(acceptSuggestion()));
50 connect(popup, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
51 SLOT(currentItemChanged(QListWidgetItem*)));
52 connect(popup, SIGNAL(itemEntered(QListWidgetItem*)), SLOT(itemEntered(QListWidgetItem *)));
54 timer = new QTimer(this);
55 timer->setSingleShot(true);
56 timer->setInterval(500);
57 connect(timer, SIGNAL(timeout()), SLOT(suggest()));
58 connect(buddy, SIGNAL(textEdited(QString)), timer, SLOT(start()));
61 AutoComplete::~AutoComplete() {
65 bool AutoComplete::eventFilter(QObject *obj, QEvent *ev) {
66 if (obj != popup) return false;
68 if (ev->type() == QEvent::Leave) {
69 popup->setCurrentItem(0);
70 popup->clearSelection();
71 if (!originalText.isEmpty()) buddy->setText(originalText);
75 if (ev->type() == QEvent::FocusOut) {
77 buddy->setText(originalText);
82 if (ev->type() == QEvent::KeyPress) {
83 bool consumed = false;
84 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(ev);
85 // qWarning() << keyEvent->text();
86 switch (keyEvent->key()) {
89 if (popup->currentItem()) {
102 buddy->setText(originalText);
108 if (popup->currentRow() == 0) {
109 popup->setCurrentItem(0);
110 popup->clearSelection();
111 buddy->setText(originalText);
121 case Qt::Key_PageDown:
126 // qDebug() << keyEvent->text();
138 void AutoComplete::showCompletion(const QList<Suggestion *> &suggestions) {
139 if (suggestions.isEmpty()) {
144 popup->setUpdatesEnabled(false);
146 for (int i = 0; i < suggestions.count(); ++i) {
147 QListWidgetItem * item;
148 item = new QListWidgetItem(popup);
149 Suggestion *s = suggestions[i];
150 item->setText(s->value);
151 if (!s->type.isEmpty())
152 item->setIcon(QIcon(":/images/" + s->type + ".png"));
154 popup->setCurrentItem(0);
156 for (int i = 0; i < suggestions.count(); ++i)
157 h += popup->sizeHintForRow(i);
158 popup->resize(buddy->width(), h);
159 popup->move(buddy->mapToGlobal(QPoint(0, buddy->height())));
162 if (popup->isHidden()) popup->show();
163 popup->setUpdatesEnabled(true);
166 void AutoComplete::acceptSuggestion() {
168 originalText.clear();
171 int index = popup->currentIndex().row();
172 if (index >= 0 && index < suggestions.size()) {
173 Suggestion* suggestion = suggestions.at(index);
174 buddy->setText(suggestion->value);
175 emit suggestionAccepted(suggestion);
176 emit suggestionAccepted(suggestion->value);
178 } else qWarning() << "No suggestion for index" << index;
181 void AutoComplete::preventSuggest() {
185 popup->setFrameShape(QFrame::NoFrame);
188 void AutoComplete::enableSuggest() {
192 void AutoComplete::setSuggester(Suggester* suggester) {
193 if (this->suggester) this->suggester->disconnect();
194 this->suggester = suggester;
195 connect(suggester, SIGNAL(ready(QList<Suggestion*>)), SLOT(suggestionsReady(QList<Suggestion*>)));
198 void AutoComplete::suggest() {
199 if (!enabled) return;
200 if (!buddy->hasFocus()) return;
202 popup->setCurrentItem(0);
203 popup->clearSelection();
205 originalText = buddy->text();
206 if (originalText.isEmpty()) {
212 if (suggester) suggester->suggest(originalText);
215 void AutoComplete::suggestionsReady(const QList<Suggestion *> &suggestions) {
216 qDeleteAll(this->suggestions);
217 this->suggestions = suggestions;
218 if (!enabled) return;
219 if (!buddy->hasFocus()) return;
220 showCompletion(suggestions);
223 void AutoComplete::itemEntered(QListWidgetItem *item) {
225 item->setSelected(true);
226 popup->setCurrentItem(item);
229 void AutoComplete::currentItemChanged(QListWidgetItem *item) {
231 buddy->setText(item->text());
232 // lineEdit->setSelection(originalText.length(), editor->text().length());