1 #include "completerwindow.h"
2 #include "ui_completerwindow.h"
3 #include "completermodel.h"
4 #include "common/unused.h"
5 #include "sqleditor.h"
6 #include "common/utils_sql.h"
7 #include <QKeyEvent>
8 #include <QListView>
9 #include <QDebug>
10 
CompleterWindow(SqlEditor * parent)11 CompleterWindow::CompleterWindow(SqlEditor *parent) :
12     QDialog(parent, Qt::FramelessWindowHint),
13     ui(new Ui::CompleterWindow),
14     sqlEditor(parent)
15 {
16     ui->setupUi(this);
17     init();
18 }
19 
~CompleterWindow()20 CompleterWindow::~CompleterWindow()
21 {
22     delete ui;
23 }
24 
init()25 void CompleterWindow::init()
26 {
27     model = new CompleterModel(this);
28     ui->list->setModel(model);
29     model->setCompleterView(ui->list);
30 
31     setFocusProxy(ui->list);
32     connect(ui->list, SIGNAL(focusOut()), this, SLOT(focusOut()));
33     connect(ui->list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(doubleClicked(QModelIndex)));
34     connect(ui->list->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(currentRowChanged(QModelIndex,QModelIndex)));
35     connect(ui->list, SIGNAL(textTyped(QString)), this, SIGNAL(textTyped(QString)));
36     connect(ui->list, SIGNAL(backspace()), this, SIGNAL(backspacePressed()));
37     connect(ui->list, SIGNAL(left()), this, SIGNAL(leftPressed()));
38     connect(ui->list, SIGNAL(right()), this, SIGNAL(rightPressed()));
39     reset();
40 }
41 
reset()42 void CompleterWindow::reset()
43 {
44     model->clear();
45     ui->status->showMessage(QString());
46 }
47 
setData(const CompletionHelper::Results & completionResults)48 void CompleterWindow::setData(const CompletionHelper::Results& completionResults)
49 {
50     ui->status->showMessage(QString());
51     model->setData(completionResults.expectedTokens);
52     filter = completionResults.partialToken;
53     wrappedFilter = completionResults.wrappedToken;
54     updateFilter();
55 }
56 
setDb(Db * db)57 void CompleterWindow::setDb(Db* db)
58 {
59     this->db = db;
60 }
61 
updateFilter()62 void CompleterWindow::updateFilter()
63 {
64     model->setFilter(filter);
65     ui->list->selectFirstVisible();
66 
67     if (!ui->list->hasVisibleItem())
68         reject();
69 }
70 
shringFilterBy(int chars)71 void CompleterWindow::shringFilterBy(int chars)
72 {
73     if (filter.size() < chars)
74     {
75         if (wrappedFilter && chars == 1)
76         {
77             wrappedFilter = false;
78             updateFilter();
79             return;
80         }
81 
82         reject();
83         return;
84     }
85 
86     filter.truncate(filter.length() - chars);
87     updateFilter();
88 }
89 
extendFilterBy(const QString & text)90 void CompleterWindow::extendFilterBy(const QString& text)
91 {
92     if (filter.isEmpty() && text.size() == 1 && isWrapperChar(text[0]))
93     {
94         wrappedFilter = true;
95         updateFilter();
96         return;
97     }
98 
99     filter.append(text);
100     updateFilter();
101 }
102 
immediateResolution()103 bool CompleterWindow::immediateResolution()
104 {
105     if (ui->list->countVisibleItem() == 1)
106     {
107         accept();
108         return true;
109     }
110     return false;
111 }
112 
getSelected()113 ExpectedTokenPtr CompleterWindow::getSelected()
114 {
115     QModelIndex current = ui->list->currentIndex();
116     if (!current.isValid())
117         return ExpectedTokenPtr();
118 
119     return model->getToken(current.row());
120 }
121 
getNumberOfCharsToRemove()122 int CompleterWindow::getNumberOfCharsToRemove()
123 {
124     return filter.size() + (wrappedFilter ? 1 : 0);
125 }
126 
changeEvent(QEvent * e)127 void CompleterWindow::changeEvent(QEvent *e)
128 {
129     QDialog::changeEvent(e);
130     switch (e->type()) {
131         case QEvent::LanguageChange:
132             ui->retranslateUi(this);
133             break;
134         default:
135             break;
136     }
137 }
138 
keyPressEvent(QKeyEvent * e)139 void CompleterWindow::keyPressEvent(QKeyEvent* e)
140 {
141     if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
142     {
143         accept();
144         return;
145     }
146 
147     QDialog::keyPressEvent(e);
148 }
149 
getStatusMsg(const QModelIndex & index)150 QString CompleterWindow::getStatusMsg(const QModelIndex& index)
151 {
152     ExpectedToken::Type type = (ExpectedToken::Type)index.data(CompleterModel::TYPE).toInt();
153     QString value = index.data(CompleterModel::VALUE).toString();
154     QString label = index.data(CompleterModel::LABEL).toString();
155 
156     switch (type)
157     {
158         case ExpectedToken::COLUMN:
159             return tr("Column: %1", "completer statusbar").arg(value);
160         case ExpectedToken::TABLE:
161             return tr("Table: %1", "completer statusbar").arg(value);
162         case ExpectedToken::INDEX:
163             return tr("Index: %1", "completer statusbar").arg(value);
164         case ExpectedToken::TRIGGER:
165             return tr("Trigger: %1", "completer statusbar").arg(value);
166         case ExpectedToken::VIEW:
167             return tr("View: %1", "completer statusbar").arg(value);
168         case ExpectedToken::DATABASE:
169             return tr("Database: %1", "completer statusbar").arg(value);
170         case ExpectedToken::OTHER:
171         {
172             if (!label.isEmpty())
173                 return label;
174 
175             if (!value.isEmpty())
176                 return value;
177 
178             return "";
179         }
180         case ExpectedToken::KEYWORD:
181             return tr("Keyword: %1", "completer statusbar").arg(value);
182         case ExpectedToken::FUNCTION:
183             return tr("Function: %1", "completer statusbar").arg(value);
184         case ExpectedToken::OPERATOR:
185             return tr("Operator: %1", "completer statusbar").arg(value);
186         case ExpectedToken::STRING:
187             return tr("String", "completer statusbar");
188         case ExpectedToken::NUMBER:
189             return tr("Number", "completer statusbar").arg(value);
190         case ExpectedToken::BLOB:
191             return tr("Binary data", "completer statusbar").arg(value);
192         case ExpectedToken::COLLATION:
193             return tr("Collation: %1", "completer statusbar").arg(value);
194         case ExpectedToken::PRAGMA:
195             return tr("Pragma function: %1", "completer statusbar").arg(value);
196         case ExpectedToken::NO_VALUE:
197         {
198             if (!label.isEmpty())
199                 return label;
200 
201             if (!value.isEmpty())
202                 return value;
203 
204             return "";
205         }
206     }
207     return "";
208 }
209 
focusOut()210 void CompleterWindow::focusOut()
211 {
212     QWidget* focused = QApplication::focusWidget();
213     if (!focused || focused == this || isAncestorOf(focused))
214         return;
215 
216     reject();
217 }
218 
doubleClicked(const QModelIndex & index)219 void CompleterWindow::doubleClicked(const QModelIndex& index)
220 {
221     UNUSED(index);
222     accept();
223 }
224 
currentRowChanged(const QModelIndex & current,const QModelIndex & previous)225 void CompleterWindow::currentRowChanged(const QModelIndex& current, const QModelIndex& previous)
226 {
227     UNUSED(previous);
228     ui->status->showMessage(getStatusMsg(current));
229 }
230 
showEvent(QShowEvent * e)231 void CompleterWindow::showEvent(QShowEvent*e)
232 {
233     QDialog::showEvent(e);
234 
235     // A hack for Gnome3 to give this widget a focus. Harmless for others.
236     ui->list->activateWindow();
237 }
238