aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/guiSQLiteStudio/completer
diff options
context:
space:
mode:
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/completer')
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp133
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.h31
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completermodel.cpp170
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completermodel.h50
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completerview.cpp70
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completerview.h30
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp229
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.h64
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.ui47
9 files changed, 824 insertions, 0 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp b/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp
new file mode 100644
index 0000000..bda3040
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp
@@ -0,0 +1,133 @@
+#include "completeritemdelegate.h"
+#include "completermodel.h"
+#include <QPainter>
+#include <QIcon>
+#include <QApplication>
+#include <QVariant>
+#include <QDebug>
+
+/*
+ * Some of the code in this file comes from Qt5.1, from qcommonstyle.cpp.
+ * It uses similar (but different) routines as Qt does for drawing CE_ItemViewItem.
+ */
+
+CompleterItemDelegate::CompleterItemDelegate(QObject *parent) :
+ QStyledItemDelegate(parent)
+{
+}
+
+void CompleterItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
+{
+ QStyleOptionViewItem opt = option;
+ initStyleOption(&opt, index);
+
+ QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
+
+ paintIcon(painter, opt, index);
+ paintText(painter, opt, index);
+}
+
+QSize CompleterItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
+{
+ QSize size = QStyledItemDelegate::sizeHint(option, index);
+ if (size.height() < 18)
+ size.setHeight(18); // at least 1 pixel larger than icons
+
+ return size;
+}
+
+void CompleterItemDelegate::paintIcon(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
+{
+ QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
+ QSize iconSize = icon.availableSizes()[0];
+
+ QIcon::Mode mode = QIcon::Normal;
+ if (!(option.state & QStyle::State_Enabled))
+ mode = QIcon::Disabled;
+ else if (option.state & QStyle::State_Selected)
+ mode = QIcon::Selected;
+
+ QRect iconRect = option.rect;
+ iconRect.setSize(iconSize + QSize(spacer*2, spacer*2));
+ iconRect.setTopLeft(iconRect.topLeft() + QPoint(spacer, spacer));
+
+ QIcon::State state = option.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
+ icon.paint(painter, iconRect, option.decorationAlignment, mode, state);
+}
+
+void CompleterItemDelegate::paintText(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
+{
+ painter->save();
+
+ // Colors
+ QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+
+ QColor prefixColor = option.palette.color(cg, QPalette::Dark);
+ QColor valueColor = option.palette.color(cg, QPalette::Text);
+ QColor labelColor = option.palette.color(cg, QPalette::Link);
+ if (option.state & QStyle::State_Selected)
+ {
+#ifdef Q_OS_WIN32
+ prefixColor = option.palette.color(cg, QPalette::Text);
+ valueColor = option.palette.color(cg, QPalette::Text);
+ labelColor = option.palette.color(cg, QPalette::Text);
+#else
+ prefixColor = option.palette.color(cg, QPalette::HighlightedText);
+ valueColor = option.palette.color(cg, QPalette::HighlightedText);
+ labelColor = option.palette.color(cg, QPalette::HighlightedText);
+#endif
+ }
+
+ // Using ascent() to measure usual height of the font, excluding anything below baseline.
+ int x = option.rect.x() + 20;
+ int y = option.rect.y() + option.rect.height() / 2 + option.fontMetrics.ascent() / 2 - spacer;
+
+ painter->setFont(option.font);
+
+ // Getting all data to be painted
+ QString prefixValue = index.data(CompleterModel::PREFIX).toString();
+ QString value = index.data(CompleterModel::VALUE).toString();
+ QString label = index.data(CompleterModel::LABEL).toString();
+
+ // Drawing prefix, value and label
+ painter->setPen(prefixColor);
+ paintPrefix(painter, option.fontMetrics, x, y, prefixValue);
+
+ painter->setPen(valueColor);
+ paintValue(painter, option.fontMetrics, x, y, value);
+
+ painter->setPen(labelColor);
+ paintLabel(painter, x, y, label, value.isEmpty());
+
+ painter->restore();
+}
+
+void CompleterItemDelegate::paintPrefix(QPainter* painter, const QFontMetrics& metrics, int& x, int y, const QString& text) const
+{
+ if (text.isNull())
+ return;
+
+ QString value = text + ".";
+ painter->drawText(QPoint(x, y), value);
+ x += metrics.width(value);
+}
+
+void CompleterItemDelegate::paintValue(QPainter* painter, const QFontMetrics& metrics, int& x, int y, const QString& text) const
+{
+ painter->drawText(QPoint(x, y), text);
+ x += metrics.width(text);
+}
+
+void CompleterItemDelegate::paintLabel(QPainter* painter, int& x, int y, const QString& text, bool emptyValue) const
+{
+ if (text.isNull())
+ return;
+
+ if (!emptyValue) //if the value was empty, there's no reason to move te label right
+ x += 10;
+
+ QString label = "(" + text + ")";
+ painter->drawText(QPoint(x, y), label);
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.h b/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.h
new file mode 100644
index 0000000..5f7aa7c
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.h
@@ -0,0 +1,31 @@
+#ifndef COMPLETERITEMDELEGATE_H
+#define COMPLETERITEMDELEGATE_H
+
+#include "guiSQLiteStudio_global.h"
+#include "expectedtoken.h"
+#include <QStyledItemDelegate>
+
+class QIcon;
+
+class GUI_API_EXPORT CompleterItemDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+ public:
+ explicit CompleterItemDelegate(QObject *parent = 0);
+
+ void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
+ QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
+
+ private:
+ QIcon* getIcon(ExpectedToken::Type type) const;
+ void paintBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
+ void paintIcon(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
+ void paintText(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
+ void paintPrefix(QPainter* painter, const QFontMetrics& metrics, int& x, int y, const QString& text) const;
+ void paintValue(QPainter* painter, const QFontMetrics& metrics, int& x, int y, const QString& text) const;
+ void paintLabel(QPainter* painter, int& x, int y, const QString& text, bool emptyValue) const;
+
+ const static int spacer = 1;
+};
+
+#endif // COMPLETERITEMDELEGATE_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completermodel.cpp b/SQLiteStudio3/guiSQLiteStudio/completer/completermodel.cpp
new file mode 100644
index 0000000..aeb481e
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completermodel.cpp
@@ -0,0 +1,170 @@
+#include "completermodel.h"
+#include "iconmanager.h"
+#include "common/unused.h"
+#include "completerview.h"
+#include <QIcon>
+#include <QVariant>
+
+CompleterModel::CompleterModel(QObject *parent) :
+ QAbstractItemModel(parent)
+{
+}
+
+
+QModelIndex CompleterModel::index(int row, int column, const QModelIndex& parent) const
+{
+ if (parent.isValid())
+ return QModelIndex(); // no childrens
+
+ return createIndex(row, column);
+}
+
+QModelIndex CompleterModel::parent(const QModelIndex& child) const
+{
+ UNUSED(child);
+ return QModelIndex();
+}
+
+int CompleterModel::rowCount(const QModelIndex& parent) const
+{
+ UNUSED(parent);
+ return tokens.size();
+}
+
+int CompleterModel::columnCount(const QModelIndex& parent) const
+{
+ UNUSED(parent);
+ return 1;
+}
+
+QVariant CompleterModel::data(const QModelIndex& index, int role) const
+{
+ int row = index.row();
+ if (row < 0 || row >= tokens.size())
+ return QVariant();
+
+ ExpectedTokenPtr token = tokens[row];
+ switch (role)
+ {
+ case Qt::DisplayRole:
+ case VALUE:
+ return token->value;
+ case CONTEXT:
+ return token->contextInfo;
+ case LABEL:
+ return token->label;
+ case PREFIX:
+ return token->prefix;
+ case TYPE:
+ return (int)token->type;
+ case Qt::DecorationRole:
+ return getIcon(token->type);
+ }
+
+ return QVariant();
+}
+
+void CompleterModel::setCompleterView(CompleterView* view)
+{
+ completerView = view;
+}
+
+void CompleterModel::setData(const QList<ExpectedTokenPtr>& data)
+{
+ clear();
+ beginInsertRows(QModelIndex(), 0, data.size()-1);
+ tokens = data;
+ endInsertRows();
+}
+
+void CompleterModel::setFilter(const QString& filter)
+{
+ this->filter = filter;
+ applyFilter();
+}
+
+QString CompleterModel::getFilter() const
+{
+ return filter;
+}
+
+void CompleterModel::applyFilter()
+{
+ bool empty = filter.isEmpty();
+ QModelIndex idx;
+ QString value;
+ QString prefix;
+ bool matched = empty;
+ for (int i = 0; i < rowCount(QModelIndex()); i++)
+ {
+ if (!empty)
+ {
+ idx = index(i, 0, QModelIndex());
+ value = idx.data(VALUE).toString();
+ prefix = idx.data(PREFIX).toString();
+ if (!prefix.isEmpty())
+ value.prepend(prefix+".");
+
+ matched = value.startsWith(filter, Qt::CaseInsensitive);
+ }
+
+ completerView->setRowHidden(i, !matched);
+ }
+}
+
+
+void CompleterModel::clear()
+{
+ beginResetModel();
+ tokens.clear();
+ endResetModel();
+}
+
+ExpectedTokenPtr CompleterModel::getToken(int index) const
+{
+ if (index < 0 || index >= tokens.size())
+ return ExpectedTokenPtr();
+
+ return tokens[index];
+}
+
+QIcon CompleterModel::getIcon(ExpectedToken::Type type) const
+{
+ switch (type)
+ {
+ case ExpectedToken::COLUMN:
+ return ICONS.COLUMN;
+ case ExpectedToken::TABLE:
+ return ICONS.TABLE;
+ case ExpectedToken::INDEX:
+ return ICONS.INDEX;
+ case ExpectedToken::TRIGGER:
+ return ICONS.TRIGGER;
+ case ExpectedToken::VIEW:
+ return ICONS.VIEW;
+ case ExpectedToken::DATABASE:
+ return ICONS.DATABASE;
+ case ExpectedToken::OTHER:
+ return ICONS.COMPLETER_OTHER;
+ case ExpectedToken::KEYWORD:
+ return ICONS.KEYWORD;
+ case ExpectedToken::FUNCTION:
+ return ICONS.FUNCTION;
+ case ExpectedToken::OPERATOR:
+ return ICONS.COMPLETER_OPERATOR;
+ case ExpectedToken::STRING:
+ return ICONS.COMPLETER_STRING;
+ case ExpectedToken::NUMBER:
+ return ICONS.COMPLETER_NUMBER;
+ case ExpectedToken::BLOB:
+ return ICONS.COMPLETER_BLOB;
+ case ExpectedToken::COLLATION:
+ return ICONS.CONSTRAINT_COLLATION;
+ case ExpectedToken::PRAGMA:
+ return ICONS.COMPLETER_PRAGMA;
+ case ExpectedToken::NO_VALUE:
+ return ICONS.COMPLETER_NO_VALUE;
+ }
+
+ return ICONS.COMPLETER_NO_VALUE;
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completermodel.h b/SQLiteStudio3/guiSQLiteStudio/completer/completermodel.h
new file mode 100644
index 0000000..5edd46f
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completermodel.h
@@ -0,0 +1,50 @@
+#ifndef COMPLETERMODEL_H
+#define COMPLETERMODEL_H
+
+#include "guiSQLiteStudio_global.h"
+#include "expectedtoken.h"
+#include <QAbstractItemModel>
+#include <QModelIndex>
+
+class CompleterView;
+class Icon;
+
+class GUI_API_EXPORT CompleterModel : public QAbstractItemModel
+{
+ public:
+ using QAbstractItemModel::setData;
+
+ enum UserRole
+ {
+ VALUE = 1000,
+ CONTEXT = 1001,
+ PREFIX = 1002,
+ LABEL = 1003,
+ TYPE = 1004
+ };
+
+ explicit CompleterModel(QObject *parent = 0);
+
+ QModelIndex index(int row, int column, const QModelIndex& parent) const;
+ QModelIndex parent(const QModelIndex& child) const;
+ int rowCount(const QModelIndex& parent) const;
+ int columnCount(const QModelIndex& parent) const;
+ QVariant data(const QModelIndex& index, int role) const;
+
+ void setCompleterView(CompleterView* view);
+ void setData(const QList<ExpectedTokenPtr>& data);
+ void setFilter(const QString& filter);
+ QString getFilter() const;
+ void clear();
+ ExpectedTokenPtr getToken(int index) const;
+
+ private:
+ QIcon getIcon(ExpectedToken::Type type) const;
+ void applyFilter();
+
+ QList<ExpectedTokenPtr> tokens;
+ QString filter;
+ CompleterView* completerView = nullptr;
+};
+
+#endif // COMPLETERMODEL_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completerview.cpp b/SQLiteStudio3/guiSQLiteStudio/completer/completerview.cpp
new file mode 100644
index 0000000..c154b14
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completerview.cpp
@@ -0,0 +1,70 @@
+#include "completerview.h"
+#include "completeritemdelegate.h"
+#include <QMouseEvent>
+
+CompleterView::CompleterView(QWidget *parent) :
+ QListView(parent)
+{
+ setItemDelegate(new CompleterItemDelegate(this));
+}
+
+void CompleterView::selectFirstVisible()
+{
+ QModelIndex idx;
+ for (int i = 0; i < model()->rowCount(); i++)
+ {
+ if (isRowHidden(i))
+ continue;
+
+ idx = model()->index(i, 0, QModelIndex());
+ selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
+ break;
+ }
+}
+
+bool CompleterView::hasVisibleItem() const
+{
+ return countVisibleItem() > 0;
+}
+
+int CompleterView::countVisibleItem() const
+{
+ int cnt = 0;
+ for (int i = 0; i < model()->rowCount(); i++)
+ {
+ if (!isRowHidden(i))
+ cnt++;
+ }
+ return cnt;
+}
+
+void CompleterView::focusOutEvent(QFocusEvent* e)
+{
+ emit focusOut();
+ QListView::focusOutEvent(e);
+}
+
+void CompleterView::keyPressEvent(QKeyEvent* e)
+{
+ QString txt = e->text();
+ if (!txt.isEmpty() && txt[0].isPrint())
+ {
+ emit textTyped(txt);
+ return;
+ }
+
+ switch (e->key())
+ {
+ case Qt::Key_Backspace:
+ emit backspace();
+ return;
+ case Qt::Key_Left:
+ emit left();
+ return;
+ case Qt::Key_Right:
+ emit right();
+ return;
+ }
+
+ QListView::keyPressEvent(e);
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completerview.h b/SQLiteStudio3/guiSQLiteStudio/completer/completerview.h
new file mode 100644
index 0000000..ef654af
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completerview.h
@@ -0,0 +1,30 @@
+#ifndef COMPLETERLIST_H
+#define COMPLETERLIST_H
+
+#include "guiSQLiteStudio_global.h"
+#include <QListWidget>
+
+class CompleterView : public QListView
+{
+ Q_OBJECT
+
+ public:
+ explicit CompleterView(QWidget *parent = 0);
+
+ void selectFirstVisible();
+ bool hasVisibleItem() const;
+ int countVisibleItem() const;
+
+ protected:
+ void focusOutEvent(QFocusEvent* e);
+ void keyPressEvent(QKeyEvent* e);
+
+ signals:
+ void focusOut();
+ void textTyped(const QString& text);
+ void backspace();
+ void left();
+ void right();
+};
+
+#endif // COMPLETERLIST_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp
new file mode 100644
index 0000000..34ae30b
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp
@@ -0,0 +1,229 @@
+#include "completerwindow.h"
+#include "ui_completerwindow.h"
+#include "completermodel.h"
+#include "common/unused.h"
+#include "sqleditor.h"
+#include "common/utils_sql.h"
+#include <QKeyEvent>
+#include <QListView>
+#include <QDebug>
+
+CompleterWindow::CompleterWindow(SqlEditor *parent) :
+ QDialog(parent, Qt::FramelessWindowHint),
+ ui(new Ui::CompleterWindow),
+ sqlEditor(parent)
+{
+ ui->setupUi(this);
+ init();
+}
+
+CompleterWindow::~CompleterWindow()
+{
+ delete ui;
+}
+
+void CompleterWindow::init()
+{
+ model = new CompleterModel(this);
+ ui->list->setModel(model);
+ model->setCompleterView(ui->list);
+
+ setFocusProxy(ui->list);
+ connect(ui->list, SIGNAL(focusOut()), this, SLOT(focusOut()));
+ connect(ui->list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(doubleClicked(QModelIndex)));
+ connect(ui->list->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(currentRowChanged(QModelIndex,QModelIndex)));
+ connect(ui->list, SIGNAL(textTyped(QString)), this, SIGNAL(textTyped(QString)));
+ connect(ui->list, SIGNAL(backspace()), this, SIGNAL(backspacePressed()));
+ connect(ui->list, SIGNAL(left()), this, SIGNAL(leftPressed()));
+ connect(ui->list, SIGNAL(right()), this, SIGNAL(rightPressed()));
+ reset();
+}
+
+void CompleterWindow::reset()
+{
+ model->clear();
+ ui->status->showMessage(QString::null);
+}
+
+void CompleterWindow::setData(const CompletionHelper::Results& completionResults)
+{
+ ui->status->showMessage(QString::null);
+ model->setData(completionResults.expectedTokens);
+ filter = completionResults.partialToken;
+ wrappedFilter = completionResults.wrappedToken;
+ updateFilter();
+}
+
+void CompleterWindow::setDb(Db* db)
+{
+ this->db = db;
+}
+
+void CompleterWindow::updateFilter()
+{
+ model->setFilter(filter);
+ ui->list->selectFirstVisible();
+
+ if (!ui->list->hasVisibleItem())
+ reject();
+}
+
+void CompleterWindow::shringFilterBy(int chars)
+{
+ if (filter.size() < chars)
+ {
+ if (wrappedFilter && chars == 1)
+ {
+ wrappedFilter = false;
+ updateFilter();
+ return;
+ }
+
+ reject();
+ return;
+ }
+
+ filter.truncate(filter.length() - chars);
+ updateFilter();
+}
+
+void CompleterWindow::extendFilterBy(const QString& text)
+{
+ if (filter.isEmpty() && text.size() == 1 && isWrapperChar(text[0], db->getDialect()))
+ {
+ wrappedFilter = true;
+ updateFilter();
+ return;
+ }
+
+ filter.append(text);
+ updateFilter();
+}
+
+bool CompleterWindow::immediateResolution()
+{
+ if (ui->list->countVisibleItem() == 1)
+ {
+ accept();
+ return true;
+ }
+ return false;
+}
+
+ExpectedTokenPtr CompleterWindow::getSelected()
+{
+ QModelIndex current = ui->list->currentIndex();
+ if (!current.isValid())
+ return ExpectedTokenPtr();
+
+ return model->getToken(current.row());
+}
+
+int CompleterWindow::getNumberOfCharsToRemove()
+{
+ return filter.size() + (wrappedFilter ? 1 : 0);
+}
+
+void CompleterWindow::changeEvent(QEvent *e)
+{
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void CompleterWindow::keyPressEvent(QKeyEvent* e)
+{
+ if (e->key() == Qt::Key_Return)
+ {
+ accept();
+ return;
+ }
+
+ QDialog::keyPressEvent(e);
+}
+
+QString CompleterWindow::getStatusMsg(const QModelIndex& index)
+{
+ ExpectedToken::Type type = (ExpectedToken::Type)index.data(CompleterModel::TYPE).toInt();
+ QString value = index.data(CompleterModel::VALUE).toString();
+ QString label = index.data(CompleterModel::LABEL).toString();
+
+ switch (type)
+ {
+ case ExpectedToken::COLUMN:
+ return tr("Column: %1", "completer statusbar").arg(value);
+ case ExpectedToken::TABLE:
+ return tr("Table: %1", "completer statusbar").arg(value);
+ case ExpectedToken::INDEX:
+ return tr("Index: %1", "completer statusbar").arg(value);
+ case ExpectedToken::TRIGGER:
+ return tr("Trigger: %1", "completer statusbar").arg(value);
+ case ExpectedToken::VIEW:
+ return tr("View: %1", "completer statusbar").arg(value);
+ case ExpectedToken::DATABASE:
+ return tr("Database: %1", "completer statusbar").arg(value);
+ case ExpectedToken::OTHER:
+ {
+ if (!label.isEmpty())
+ return label;
+
+ if (!value.isEmpty())
+ return value;
+
+ return "";
+ }
+ case ExpectedToken::KEYWORD:
+ return tr("Keyword: %1", "completer statusbar").arg(value);
+ case ExpectedToken::FUNCTION:
+ return tr("Function: %1", "completer statusbar").arg(value);
+ case ExpectedToken::OPERATOR:
+ return tr("Operator: %1", "completer statusbar").arg(value);
+ case ExpectedToken::STRING:
+ return tr("String", "completer statusbar");
+ case ExpectedToken::NUMBER:
+ return tr("Number", "completer statusbar").arg(value);
+ case ExpectedToken::BLOB:
+ return tr("Binary data", "completer statusbar").arg(value);
+ case ExpectedToken::COLLATION:
+ return tr("Collation: %1", "completer statusbar").arg(value);
+ case ExpectedToken::PRAGMA:
+ return tr("Pragma function: %1", "completer statusbar").arg(value);
+ case ExpectedToken::NO_VALUE:
+ {
+ if (!label.isEmpty())
+ return label;
+
+ if (!value.isEmpty())
+ return value;
+
+ return "";
+ }
+ }
+ return "";
+}
+
+void CompleterWindow::focusOut()
+{
+ QWidget* focused = QApplication::focusWidget();
+ if (!focused || focused == this || isAncestorOf(focused))
+ return;
+
+ reject();
+}
+
+void CompleterWindow::doubleClicked(const QModelIndex& index)
+{
+ UNUSED(index);
+ accept();
+}
+
+void CompleterWindow::currentRowChanged(const QModelIndex& current, const QModelIndex& previous)
+{
+ UNUSED(previous);
+ ui->status->showMessage(getStatusMsg(current));
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.h b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.h
new file mode 100644
index 0000000..7c933c8
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.h
@@ -0,0 +1,64 @@
+#ifndef COMPLETERWINDOW_H
+#define COMPLETERWINDOW_H
+
+#include "expectedtoken.h"
+#include "completionhelper.h"
+#include "guiSQLiteStudio_global.h"
+#include <QDialog>
+#include <QModelIndex>
+
+namespace Ui {
+ class CompleterWindow;
+}
+
+class CompleterModel;
+class QSizeGrip;
+class SqlEditor;
+
+class GUI_API_EXPORT CompleterWindow : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ explicit CompleterWindow(SqlEditor* parent = 0);
+ ~CompleterWindow();
+
+ void reset();
+ void setData(const CompletionHelper::Results& completionResults);
+ void setDb(Db* db);
+ ExpectedTokenPtr getSelected();
+ int getNumberOfCharsToRemove();
+ void shringFilterBy(int chars);
+ void extendFilterBy(const QString& text);
+ bool immediateResolution();
+
+ protected:
+ void changeEvent(QEvent *e);
+ void keyPressEvent(QKeyEvent* e);
+
+ private:
+ void updateCurrent();
+ QString getStatusMsg(const QModelIndex& index);
+ void updateFilter();
+ void init();
+
+ Ui::CompleterWindow *ui = nullptr;
+ CompleterModel* model = nullptr;
+ SqlEditor* sqlEditor = nullptr;
+ QString filter;
+ Db* db = nullptr;
+ bool wrappedFilter = false;
+
+ private slots:
+ void focusOut();
+ void doubleClicked(const QModelIndex& index);
+ void currentRowChanged(const QModelIndex& current, const QModelIndex& previous);
+
+ signals:
+ void textTyped(const QString& text);
+ void backspacePressed();
+ void leftPressed();
+ void rightPressed();
+};
+
+#endif // COMPLETERWINDOW_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.ui b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.ui
new file mode 100644
index 0000000..d5ce987
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.ui
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CompleterWindow</class>
+ <widget class="QDialog" name="CompleterWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>309</width>
+ <height>184</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">SQLiteStudio completer</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="CompleterView" name="list">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QStatusBar" name="status"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>CompleterView</class>
+ <extends>QListView</extends>
+ <header>completer/completerview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>