summaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/guiSQLiteStudio
diff options
context:
space:
mode:
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio')
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/dialogsizehandler.cpp59
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/dialogsizehandler.h34
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/widgetcover.cpp11
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/widgetcover.h1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp5
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/configmapper.cpp1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.h4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp32
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.h3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.cpp33
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.h1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqldatasourcequerymodel.cpp8
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp33
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h9
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp112
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemlineedit.cpp14
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemlineedit.h20
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp57
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h18
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlviewmodel.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dataview.cpp16
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dataview.h3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp15
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.h6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp224
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h15
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp43
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp28
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.ui37
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/searchtextdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp5
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/extendedpalette.h3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp41
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/sqleditor.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/taskbar.cpp12
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de_DE.ts4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/uiutils.cpp16
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/uiutils.h3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp62
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui27
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp27
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp11
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp46
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp55
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.h18
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp31
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp6
77 files changed, 1018 insertions, 289 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/dialogsizehandler.cpp b/SQLiteStudio3/guiSQLiteStudio/common/dialogsizehandler.cpp
new file mode 100644
index 0000000..ad283ca
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/common/dialogsizehandler.cpp
@@ -0,0 +1,59 @@
+#include "dialogsizehandler.h"
+#include "services/config.h"
+#include <QEvent>
+#include <QTimer>
+#include <QWidget>
+#include <QScreen>
+#include <QGuiApplication>
+
+DialogSizeHandler::DialogSizeHandler(QObject *parent) :
+ DialogSizeHandler(parent->objectName(), parent)
+{
+}
+
+DialogSizeHandler::DialogSizeHandler(const QString &key, QObject *parent) :
+ QObject(parent), configKey(key)
+{
+ saveTimer = new QTimer(this);
+ saveTimer->setInterval(500);
+ saveTimer->setSingleShot(true);
+ connect(saveTimer, SIGNAL(timeout()), this, SLOT(doSave()));
+
+ QRect geom = CFG->get(CONFIG_GROUP, configKey).toRect();
+ if (geom.isValid() && qApp->primaryScreen()->geometry().contains(geom))
+ {
+ QWidget* w = qobject_cast<QWidget*>(parent);
+ w->setGeometry(geom);
+ }
+}
+
+DialogSizeHandler::~DialogSizeHandler()
+{
+}
+
+void DialogSizeHandler::applyFor(QObject *parent)
+{
+ applyFor(parent->objectName(), parent);
+}
+
+void DialogSizeHandler::applyFor(const QString &key, QObject *parent)
+{
+ DialogSizeHandler* handler = new DialogSizeHandler(key, parent);
+ parent->installEventFilter(handler);
+}
+
+bool DialogSizeHandler::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::Resize || event->type() == QEvent::Move)
+ {
+ QWidget* w = qobject_cast<QWidget*>(obj);
+ recentGeometry = w->geometry();
+ saveTimer->start();
+ }
+ return false;
+}
+
+void DialogSizeHandler::doSave()
+{
+ CFG->set(CONFIG_GROUP, configKey, recentGeometry);
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/dialogsizehandler.h b/SQLiteStudio3/guiSQLiteStudio/common/dialogsizehandler.h
new file mode 100644
index 0000000..916f65d
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/common/dialogsizehandler.h
@@ -0,0 +1,34 @@
+#ifndef DIALOGSIZEHANDLER_H
+#define DIALOGSIZEHANDLER_H
+
+#include <QObject>
+#include <QRect>
+
+class QTimer;
+
+class DialogSizeHandler : public QObject
+{
+ Q_OBJECT
+public:
+ explicit DialogSizeHandler(QObject *parent);
+ DialogSizeHandler(const QString& key, QObject *parent);
+ virtual ~DialogSizeHandler();
+
+ static void applyFor(QObject *parent);
+ static void applyFor(const QString& key, QObject *parent);
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
+
+private:
+ static const constexpr char* CONFIG_GROUP = "DialogDimensions";
+
+ QString configKey;
+ QTimer* saveTimer = nullptr;
+ QRect recentGeometry;
+
+public slots:
+ void doSave();
+};
+
+#endif // DIALOGSIZEHANDLER_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/widgetcover.cpp b/SQLiteStudio3/guiSQLiteStudio/common/widgetcover.cpp
index 168c7f9..7866888 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/widgetcover.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/common/widgetcover.cpp
@@ -142,7 +142,13 @@ void WidgetCover::hide()
void WidgetCover::setProgress(int value)
{
- busyBar->setValue(value);
+ if (undetermined)
+ {
+ busyBar->setRange(0, value);
+ busyBar->setValue(value);
+ }
+ else
+ busyBar->setValue(value);
}
QEasingCurve WidgetCover::getEasingCurve() const
@@ -203,6 +209,7 @@ void WidgetCover::displayProgress(int maxValue, const QString& format)
return;
busyBar->setRange(0, maxValue);
+ undetermined = maxValue == 0;
if (!format.isNull())
busyBar->setFormat(format);
@@ -224,6 +231,7 @@ void WidgetCover::initWithProgressBarOnly(const QString& format)
busyBar->setRange(0, 100);
busyBar->setFormat(format);
busyBar->setTextVisible(true);
+ undetermined = false;
containerLayout->addWidget(busyBar, 0, 0);
}
@@ -236,6 +244,7 @@ void WidgetCover::initWithInterruptContainer(const QString& interruptButtonText)
busyBar = new QProgressBar();
busyBar->setRange(0, 0);
busyBar->setTextVisible(false);
+ undetermined = true;
containerLayout->addWidget(busyBar, 0, 0);
containerLayout->addWidget(cancelButton, 1, 0);
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/widgetcover.h b/SQLiteStudio3/guiSQLiteStudio/common/widgetcover.h
index 0b7a2f5..3d64ef5 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/widgetcover.h
+++ b/SQLiteStudio3/guiSQLiteStudio/common/widgetcover.h
@@ -55,6 +55,7 @@ class GUI_API_EXPORT WidgetCover : public QWidget
QGridLayout* containerLayout = nullptr;
QPushButton* cancelButton = nullptr;
QProgressBar* busyBar = nullptr;
+ bool undetermined = false;
signals:
void cancelClicked();
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp
index b5b0264..a81508d 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp
@@ -157,6 +157,11 @@ void WidgetStateIndicator::setVisible(bool visible, const QString& msg)
hide();
}
+bool WidgetStateIndicator::isVisible() const
+{
+ return labelParent->isVisible();
+}
+
void WidgetStateIndicator::release()
{
setVisible(false);
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h
index 28c6e0b..065c87a 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h
+++ b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h
@@ -34,6 +34,7 @@ class GUI_API_EXPORT WidgetStateIndicator : public QObject
void show(const QString& msg = QString());
void hide();
void setVisible(bool visible, const QString& msg = QString());
+ bool isVisible() const;
void release();
void info(const QString& msg);
void warn(const QString& msg);
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp
index 68ca58d..fb5dac9 100644
--- a/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp
@@ -236,9 +236,9 @@ QString CompleterWindow::getStatusMsg(const QModelIndex& index)
case ExpectedToken::OPERATOR:
return tr("Operator: %1", "completer statusbar").arg(value);
case ExpectedToken::STRING:
- return tr("String", "completer statusbar");
+ return tr("String", "completer statusbar").arg(value);
case ExpectedToken::NUMBER:
- return tr("Number", "completer statusbar").arg(value);
+ return tr("Number", "completer statusbar");
case ExpectedToken::BLOB:
return tr("Binary data", "completer statusbar").arg(value);
case ExpectedToken::COLLATION:
diff --git a/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp b/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp
index 704104b..ea176ad 100644
--- a/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp
@@ -441,7 +441,6 @@ void ConfigMapper::saveFromWidget(QWidget* widget, CfgEntry* cfgEntry)
saveCommonConfigFromWidget(widget, cfgEntry);
}
-
bool ConfigMapper::saveCustomConfigFromWidget(QWidget* widget, CfgEntry* key)
{
QList<CustomConfigWidgetPlugin*> handlers;
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.cpp
index de78b2b..d10dc5a 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columncollatepanel.cpp
@@ -102,6 +102,8 @@ void ColumnCollatePanel::storeConfiguration()
if (ui->namedCheck->isChecked())
constr->name = ui->namedEdit->text();
+ else
+ constr->name.clear();
constr->collationName = ui->collationCombo->currentText();
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
index bb70c81..79b6b6a 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
@@ -139,6 +139,8 @@ void ColumnDefaultPanel::storeConfiguration()
if (ui->namedCheck->isChecked())
constr->name = ui->namedEdit->text();
+ else
+ constr->name.clear();
}
void ColumnDefaultPanel::storeExpr(SqliteCreateTable::Column::Constraint* constr)
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp
index 308b868..8e49c93 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp
@@ -133,6 +133,8 @@ void ColumnGeneratedPanel::storeConfiguration()
if (ui->namedCheck->isChecked())
constr->name = ui->namedEdit->text();
+ else
+ constr->name.clear();
}
void ColumnGeneratedPanel::storeExpr(SqliteCreateTable::Column::Constraint* constr)
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp
index fa7b7c3..2c70eb9 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp
@@ -61,7 +61,7 @@ void ColumnPrimaryKeyPanel::readConstraint()
if (!constr->name.isNull())
{
- ui->namedCheck->setEnabled(true);
+ ui->namedCheck->setChecked(true);
ui->namedEdit->setText(constr->name);
}
@@ -122,6 +122,8 @@ void ColumnPrimaryKeyPanel::storeConfiguration()
if (ui->namedCheck->isChecked())
constr->name = ui->namedEdit->text();
+ else
+ constr->name.clear();
if (ui->conflictCheck->isChecked() && ui->conflictCombo->currentIndex() > -1)
constr->onConflict = sqliteConflictAlgo(ui->conflictCombo->currentText());
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.cpp
index 7c0f5a8..3b455e9 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnuniqueandnotnullpanel.cpp
@@ -93,6 +93,8 @@ void ColumnUniqueAndNotNullPanel::storeConfiguration()
SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data());
if (ui->namedCheck->isChecked())
constr->name = ui->namedEdit->text();
+ else
+ constr->name.clear();
if (ui->conflictCheck->isChecked() && ui->conflictCombo->currentIndex() > -1)
constr->onConflict = sqliteConflictAlgo(ui->conflictCombo->currentText());
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp
index 4f3e350..3296532 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp
@@ -29,6 +29,16 @@ void ConstraintPanel::setConstraint(SqliteStatement* stmt)
constraintAvailable();
}
+void ConstraintPanel::setCreateTableStmt(SqliteCreateTable *stmt)
+{
+ createTableStmt = stmt;
+}
+
+void ConstraintPanel::setColumnStmt(SqliteCreateTable::Column *stmt)
+{
+ columnStmt = stmt;
+}
+
void ConstraintPanel::storeDefinition()
{
storeConfiguration();
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.h
index 9f875a9..f7ed9d5 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.h
@@ -16,6 +16,8 @@ class GUI_API_EXPORT ConstraintPanel : public QWidget
virtual ~ConstraintPanel();
void setConstraint(SqliteStatement* stmt);
+ void setCreateTableStmt(SqliteCreateTable* stmt);
+ void setColumnStmt(SqliteCreateTable::Column* stmt);
void storeDefinition();
virtual void setDb(Db* value);
@@ -68,6 +70,8 @@ class GUI_API_EXPORT ConstraintPanel : public QWidget
Db* db = nullptr;
QPointer<SqliteStatement> constraint;
+ QPointer<SqliteCreateTable> createTableStmt;
+ QPointer<SqliteCreateTable::Column> columnStmt;
public slots:
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp
index cecf5f4..5e85915 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp
@@ -53,6 +53,8 @@ bool TableForeignKeyPanel::validate()
setValidState(combo, idxOk, tr("Pick the foreign column."));
if (!idxOk)
columnsSelected = false;
+ else
+ handleFkTypeMatched(combo, check->property(UI_PROP_COLUMN).toString(), combo->currentText());
break;
}
@@ -386,6 +388,36 @@ void TableForeignKeyPanel::storeMatchCondition(const QString& reaction)
constr->foreignKey->conditions << condition;
}
+void TableForeignKeyPanel::handleFkTypeMatched(QWidget* indicatorParent, const QString &localColumn, const QString fkColumn)
+{
+ SqliteCreateTable::Column* column = createTableStmt->getColumn(localColumn);
+ if (!column || !column->type)
+ return;
+
+ QString localType = column->type->toDataType().toString();
+
+ // FK column type
+ QString fkTable = ui->fkTableCombo->currentText();
+ if (!fkTableTypesCache.contains(fkTable, Qt::CaseInsensitive))
+ {
+ SchemaResolver resolver(db);
+ fkTableTypesCache[fkTable] = resolver.getTableColumnDataTypesByName(fkTable);
+ }
+
+ StrHash<DataType> fkTypes = fkTableTypesCache.value(fkTable, Qt::CaseInsensitive);
+ if (!fkTypes.contains(fkColumn, Qt::CaseInsensitive))
+ return;
+
+ QString fkType = fkTypes.value(fkColumn, Qt::CaseInsensitive).toString();
+
+ if (localType.toLower().trimmed() != fkType.toLower().trimmed())
+ {
+ setValidStateWarning(indicatorParent,
+ tr("Referenced column type (%1) is different than type declared for local column (%2). It may cause issues while inserting or updating data.")
+ .arg(fkType, localType));
+ }
+}
+
void TableForeignKeyPanel::readTables()
{
SchemaResolver resolver(db);
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.h
index cecc04a..a6d48e6 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.h
@@ -4,6 +4,7 @@
#include "constraintpanel.h"
#include "parser/ast/sqlitecreatetable.h"
#include "guiSQLiteStudio_global.h"
+#include "common/strhash.h"
#include <QStringListModel>
#include <QWidget>
@@ -40,12 +41,14 @@ class GUI_API_EXPORT TableForeignKeyPanel : public ConstraintPanel
int getColumnIndex(const QString& colName);
void storeCondition(SqliteForeignKey::Condition::Action action, const QString& reaction);
void storeMatchCondition(const QString& reaction);
+ void handleFkTypeMatched(QWidget* indicatorParent, const QString& localColumn, const QString fkColumn);
Ui::TableForeignKeyPanel *ui = nullptr;
QGridLayout* columnsLayout = nullptr;
int totalColumns = 0;
QStringListModel fkColumnsModel;
QSignalMapper* columnSignalMapping = nullptr;
+ StrHash<StrHash<DataType>> fkTableTypesCache;
private slots:
void updateState();
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.cpp
index b9ca7b7..a3ba2ab 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.cpp
@@ -10,6 +10,7 @@
#include <QScreen>
#include <QLineEdit>
#include <QScrollBar>
+#include <QCompleter>
FkComboBox::FkComboBox(QWidget* parent, int dropDownViewMinWidth)
: QComboBox(parent), dropDownViewMinWidth(dropDownViewMinWidth)
@@ -45,8 +46,8 @@ QString FkComboBox::getSqlForFkEditor(Db* db, SqlQueryModelColumn* columnModel,
src = wrapObjIfNeeded(fk->foreignTable);
if (i == 0)
{
- firstSrcCol = col;
fullSrcCol = src + "." + col;
+ firstSrcCol = fullSrcCol;
selectedCols << dbColTpl.arg(fullSrcCol, wrapObjIfNeeded(columnModel->column));
}
@@ -89,7 +90,7 @@ QString FkComboBox::getSqlForFkEditor(Db* db, SqlQueryModelColumn* columnModel,
QString currValueColName = generateUniqueName("curr", usedNames);
QString currValueExpr = currentValue.isNull() ?
currNullValueTpl.arg(firstSrcCol, currValueColName) :
- currValueTpl.arg(firstSrcCol, wrapValueIfNeeded(currentValue), currValueColName);
+ currValueTpl.arg(firstSrcCol, valueToSqlLiteral(currentValue), currValueColName);
return sql.arg(
selectedCols.join(", "),
@@ -110,8 +111,6 @@ void FkComboBox::setValue(const QVariant& value)
bool doExecQuery = (sourceValue != value || comboModel->getQuery().isNull());
sourceValue = value;
setCurrentText(value.toString());
- if (!value.isNull() && isEditable())
- lineEdit()->selectAll();
if (doExecQuery)
{
@@ -221,6 +220,13 @@ void FkComboBox::init()
comboView->horizontalHeader()->setVisible(true);
comboView->setSelectionMode(QAbstractItemView::SingleSelection);
comboView->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ connect(completer(), QOverload<const QString &>::of(&QCompleter::highlighted),
+ [=](const QString &value)
+ {
+ // #5083 In case of case-sensitive mismatch, we need to sync case, so that next/prev navigation with keybord works correctly.
+ setCurrentText(value.left(currentText().length()));
+ });
}
void FkComboBox::updateComboViewGeometry(bool initial) const
@@ -244,6 +250,19 @@ void FkComboBox::updateComboViewGeometry(bool initial) const
}
}
+void FkComboBox::updateCurrentItemIndex(const QString& value)
+{
+ QModelIndex startIdx = comboModel->index(0, modelColumn());
+ QModelIndex endIdx = comboModel->index(comboModel->rowCount() - 1, modelColumn());
+ QModelIndexList idxList = comboModel->findIndexes(startIdx, endIdx, SqlQueryItem::DataRole::VALUE, value.isNull() ? currentText() : value, 1, true);
+
+ if (idxList.size() > 0)
+ {
+ setCurrentIndex(idxList.first().row());
+ view()->selectionModel()->setCurrentIndex(idxList.first(), QItemSelectionModel::SelectCurrent);
+ }
+}
+
int FkComboBox::getFkViewHeaderWidth(bool includeScrollBar) const
{
int wd = comboView->horizontalHeader()->length();
@@ -289,7 +308,9 @@ void FkComboBox::fkDataReady()
}
}
else
+ {
setEditText(beforeLoadValue);
+ }
disableValueChangeNotifications = false;
}
@@ -305,6 +326,10 @@ void FkComboBox::notifyValueModified()
return;
oldValue = currentText();
+ disableValueChangeNotifications = true;
+ updateCurrentItemIndex();
+ disableValueChangeNotifications = false;
+
emit valueModified();
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.h
index 8cb22a5..647bbb6 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/fkcombobox.h
@@ -35,6 +35,7 @@ class FkComboBox : public QComboBox
void init();
void updateComboViewGeometry(bool initial) const;
+ void updateCurrentItemIndex(const QString& value = QString());
int getFkViewHeaderWidth(bool includeScrollBar) const;
QString getSql() const;
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqldatasourcequerymodel.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqldatasourcequerymodel.cpp
index a1a6cee..e02e77a 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqldatasourcequerymodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqldatasourcequerymodel.cpp
@@ -28,7 +28,6 @@ void SqlDataSourceQueryModel::updateTablesInUse(const QString& inUse)
void SqlDataSourceQueryModel::applyFilter(const QString& value, FilterValueProcessor valueProc)
{
-// static_qstring(sql, "SELECT * FROM %1 WHERE %2");
if (value.isEmpty())
{
resetFilter();
@@ -39,14 +38,12 @@ void SqlDataSourceQueryModel::applyFilter(const QString& value, FilterValueProce
for (SqlQueryModelColumnPtr& column : columns)
conditions << wrapObjIfNeeded(column->getAliasedName())+" "+valueProc(value);
-// setQuery(sql.arg(getDataSource(), conditions.join(" OR ")));
queryExecutor->setFilters(conditions.join(" OR "));
- executeQuery();
+ executeQuery(true);
}
void SqlDataSourceQueryModel::applyFilter(const QStringList& values, FilterValueProcessor valueProc)
{
-// static_qstring(sql, "SELECT * FROM %1 WHERE %2");
if (values.isEmpty())
{
resetFilter();
@@ -69,7 +66,6 @@ void SqlDataSourceQueryModel::applyFilter(const QStringList& values, FilterValue
conditions << wrapObjIfNeeded(columns[i]->getAliasedName())+" "+valueProc(values[i]);
}
-// setQuery(sql.arg(getDataSource(), conditions.join(" AND ")));
queryExecutor->setFilters(conditions.join(" AND "));
executeQuery();
}
@@ -139,7 +135,7 @@ void SqlDataSourceQueryModel::resetFilter()
{
// setQuery("SELECT * FROM "+getDataSource());
queryExecutor->setFilters(QString());
- executeQuery();
+ executeQuery(true);
}
QString SqlDataSourceQueryModel::getDatabasePrefix()
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp
index 771e890..81fda44 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp
@@ -143,8 +143,9 @@ void SqlQueryItem::setValue(const QVariant &value, bool loadedFromDb)
// - this item was already marked as uncommitted
bool modified = (
(
- newValue != origValue ||
- origValue.isNull() != newValue.isNull()
+ newValue != origValue ||
+ origValue.isNull() != newValue.isNull() ||
+ newValue.type() != origValue.type()
) &&
!loadedFromDb
) ||
@@ -331,6 +332,18 @@ QVariant SqlQueryItem::data(int role) const
if (value.isNull())
return "NULL";
+ if (value.type() == QVariant::String)
+ {
+ QString str = value.toString();
+ return str.length() > DISPLAY_LEN_LIMIT ? QVariant(str.left(DISPLAY_LEN_LIMIT) + "...") : value;
+ }
+
+ if (value.type() == QVariant::ByteArray)
+ {
+ QByteArray bytes = value.toByteArray();
+ return bytes.size() > DISPLAY_LEN_LIMIT ? QVariant(bytes.left(DISPLAY_LEN_LIMIT) + "...") : value;
+ }
+
return value;
}
case Qt::ForegroundRole:
@@ -377,3 +390,19 @@ QVariant SqlQueryItem::data(int role) const
return QStandardItem::data(role);
}
+
+void SqlQueryItem::resetInitialFocusSelection()
+{
+ QStandardItem::setData(QVariant(), DataRole::EDIT_SKIP_INITIAL_SELECT);
+
+}
+
+void SqlQueryItem::skipInitialFocusSelection()
+{
+ QStandardItem::setData(true, DataRole::EDIT_SKIP_INITIAL_SELECT);
+}
+
+bool SqlQueryItem::shoulSkipInitialFocusSelection() const
+{
+ return QStandardItem::data(DataRole::EDIT_SKIP_INITIAL_SELECT).toBool();
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h
index 0de01c1..85dcda9 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h
@@ -26,7 +26,8 @@ class GUI_API_EXPORT SqlQueryItem : public QObject, public QStandardItem
DELETED = 1007,
OLD_VALUE = 1008,
JUST_INSERTED_WITHOUT_ROWID = 1009,
- COMMITTING_ERROR_MESSAGE = 1010
+ COMMITTING_ERROR_MESSAGE = 1010,
+ EDIT_SKIP_INITIAL_SELECT = 1011 // to prevent content selection initially when editing with double-click
};
};
@@ -72,12 +73,18 @@ class GUI_API_EXPORT SqlQueryItem : public QObject, public QStandardItem
void setData(const QVariant& value, int role = Qt::UserRole + 1);
QVariant data(int role = Qt::UserRole + 1) const;
+ void resetInitialFocusSelection();
+ void skipInitialFocusSelection();
+ bool shoulSkipInitialFocusSelection() const;
+
private:
QVariant adjustVariantType(const QVariant& value);
QString getToolTip() const;
void rememberOldValue();
void clearOldValue();
+ static constexpr int DISPLAY_LEN_LIMIT = 1000;
+
QMutex valueSettingLock;
};
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp
index 7b01084..55f2161 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp
@@ -8,6 +8,7 @@
#include "common/utils_sql.h"
#include "fkcombobox.h"
#include "schemaresolver.h"
+#include "sqlqueryitemlineedit.h"
#include <QHeaderView>
#include <QPainter>
#include <QEvent>
@@ -71,10 +72,22 @@ QWidget* SqlQueryItemDelegate::createEditor(QWidget* parent, const QStyleOptionV
return nullptr;
}
+ bool skipInitSelection = item->shoulSkipInitialFocusSelection();
if (!item->getColumn()->getFkConstraints().isEmpty())
- return getFkEditor(item, parent, model);
+ return getFkEditor(item, skipInitSelection, parent, model);
- return getEditor(item->getValue().userType(), parent);
+ return getEditor(item->getValue().userType(), skipInitSelection, parent);
+}
+
+void SqlQueryItemDelegate::destroyEditor(QWidget* editor, const QModelIndex& index) const
+{
+ QStyledItemDelegate::destroyEditor(editor, index);
+ if (!index.isValid())
+ return;
+
+ const SqlQueryModel* model = dynamic_cast<const SqlQueryModel*>(index.model());
+ SqlQueryItem* item = model->itemFromIndex(index);
+ item->resetInitialFocusSelection();
}
QString SqlQueryItemDelegate::displayText(const QVariant& value, const QLocale& locale) const
@@ -216,100 +229,16 @@ SqlQueryItem* SqlQueryItemDelegate::getItem(const QModelIndex &index) const
return queryModel->itemFromIndex(index);
}
-QWidget* SqlQueryItemDelegate::getEditor(int type, QWidget* parent) const
+QWidget* SqlQueryItemDelegate::getEditor(int type, bool shouldSkipInitialSelection, QWidget* parent) const
{
UNUSED(type);
- QLineEdit *editor = new QLineEdit(parent);
+ SqlQueryItemLineEdit *editor = new SqlQueryItemLineEdit(shouldSkipInitialSelection, parent);
editor->setMaxLength(std::numeric_limits<int>::max());
editor->setFrame(editor->style()->styleHint(QStyle::SH_ItemView_DrawDelegateFrame, 0, editor));
return editor;
}
-QString SqlQueryItemDelegate::getSqlForFkEditor(SqlQueryItem* item) const
-{
- static_qstring(sql, "SELECT %4, %1 FROM %2%3");
- static_qstring(currValueTpl, "(%1 == %2) AS %3");
- static_qstring(currNullValueTpl, "(%1 IS NULL) AS %2");
- static_qstring(dbColTpl, "%1 AS %2");
- static_qstring(conditionTpl, "%1.%2 = %3.%4");
- static_qstring(conditionPrefixTpl, " WHERE %1");
-
- QStringList selectedCols;
- QStringList fkConditionTables;
- QStringList fkConditionCols;
- QStringList srcCols;
- Db* db = item->getModel()->getDb();
- SchemaResolver resolver(db);
-
- QList<SqlQueryModelColumn::ConstraintFk*> fkList = item->getColumn()->getFkConstraints();
- int i = 0;
- QString src;
- QString fullSrcCol;
- QString col;
- QString firstSrcCol;
- QStringList usedNames;
- for (SqlQueryModelColumn::ConstraintFk*& fk : fkList)
- {
- col = wrapObjIfNeeded(fk->foreignColumn);
- src = wrapObjIfNeeded(fk->foreignTable);
- if (i == 0)
- {
- firstSrcCol = col;
- fullSrcCol = src + "." + col;
- selectedCols << dbColTpl.arg(fullSrcCol, wrapObjIfNeeded(item->getColumn()->column));
- }
-
- if (fkConditionTables.contains(src, Qt::CaseInsensitive))
- continue;
-
- srcCols = resolver.getTableColumns(src);
- for (QString& srcCol : srcCols)
- {
- if (fk->foreignColumn.compare(srcCol, Qt::CaseInsensitive) == 0)
- continue; // Exclude matching column. We don't want the same column several times.
-
- fullSrcCol = src + "." + wrapObjIfNeeded(srcCol);
- selectedCols << fullSrcCol;
- usedNames << srcCol;
- }
-
- fkConditionCols << col;
- fkConditionTables << src;
-
- i++;
- }
-
- QStringList conditions;
- QString firstSrc = fkConditionTables.first();
- QString firstCol = fkConditionCols.first();
- for (i = 1; i < fkConditionTables.size(); i++)
- {
- src = fkConditionTables[i];
- col = fkConditionCols[i];
- conditions << conditionTpl.arg(firstSrc, firstCol, src, col);
- }
-
- QString conditionsStr;
- if (!conditions.isEmpty()) {
- conditionsStr = conditionPrefixTpl.arg(conditions.join(", "));
- }
-
- // Current value column (will be 1 for row which matches current cell value)
- QVariant value = item->getValue();
- QString currValueColName = generateUniqueName("curr", usedNames);
- QString currValueExpr = value.isNull() ?
- currNullValueTpl.arg(firstSrcCol, currValueColName) :
- currValueTpl.arg(firstSrcCol, wrapValueIfNeeded(value), currValueColName);
-
- return sql.arg(
- selectedCols.join(", "),
- fkConditionTables.join(", "),
- conditionsStr,
- currValueExpr
- );
-}
-
-QWidget* SqlQueryItemDelegate::getFkEditor(SqlQueryItem* item, QWidget* parent, const SqlQueryModel* model) const
+QWidget* SqlQueryItemDelegate::getFkEditor(SqlQueryItem* item, bool shouldSkipInitialSelection, QWidget* parent, const SqlQueryModel* model) const
{
Db* db = model->getDb();
bool countingError = false;
@@ -320,7 +249,7 @@ QWidget* SqlQueryItemDelegate::getFkEditor(SqlQueryItem* item, QWidget* parent,
notifyWarn(tr("Foreign key for column %2 has more than %1 possible values. It's too much to display in drop down list. You need to edit value manually.")
.arg(FkComboBox::MAX_ROWS_FOR_FK).arg(item->getColumn()->column));
- return getEditor(item->getValue().userType(), parent);
+ return getEditor(item->getValue().userType(), item->shoulSkipInitialFocusSelection(), parent);
}
if (rowCount == 0 && countingError && model->isStructureOutOfDate())
@@ -333,5 +262,8 @@ QWidget* SqlQueryItemDelegate::getFkEditor(SqlQueryItem* item, QWidget* parent,
FkComboBox* cb = new FkComboBox(parent, dropDownViewMinWidth);
cb->init(db, item->getColumn());
cb->setValue(item->getValue());
+ if (!shouldSkipInitialSelection)
+ cb->lineEdit()->selectAll();
+
return cb;
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h
index 655eae2..b703a18 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h
@@ -21,6 +21,7 @@ class GUI_API_EXPORT SqlQueryItemDelegate : public QStyledItemDelegate
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
+ void destroyEditor(QWidget *editor, const QModelIndex &index) const;
QString displayText(const QVariant & value, const QLocale & locale) const;
void setEditorData(QWidget * editor, const QModelIndex & index) const;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
@@ -39,13 +40,12 @@ class GUI_API_EXPORT SqlQueryItemDelegate : public QStyledItemDelegate
};
SqlQueryItem* getItem(const QModelIndex &index) const;
- QWidget* getEditor(int type, QWidget* parent) const;
- QWidget* getFkEditor(SqlQueryItem* item, QWidget* parent, const SqlQueryModel *model) const;
+ QWidget* getEditor(int type, bool shouldSkipInitialSelection, QWidget* parent) const;
+ QWidget* getFkEditor(SqlQueryItem* item, bool shouldSkipInitialSelection, QWidget* parent, const SqlQueryModel *model) const;
void setEditorDataForLineEdit(QLineEdit* le, const QModelIndex& index) const;
void setEditorDataForFk(QComboBox* cb, const QModelIndex& index) const;
void setModelDataForFk(FkComboBox* editor, QAbstractItemModel* model, const QModelIndex& index) const;
void setModelDataForLineEdit(QLineEdit* editor, QAbstractItemModel* model, const QModelIndex& index) const;
- QString getSqlForFkEditor(SqlQueryItem* item) const;
qlonglong getRowCountForFkEditor(Db* db, const QString& query, bool *isError) const;
int getFkViewHeaderWidth(SqlQueryView* fkView, bool includeScrollBar) const;
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemlineedit.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemlineedit.cpp
new file mode 100644
index 0000000..8f981bc
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemlineedit.cpp
@@ -0,0 +1,14 @@
+#include "sqlqueryitemlineedit.h"
+
+SqlQueryItemLineEdit::SqlQueryItemLineEdit(bool shouldSkipInitialSelection, QWidget *parent)
+ : QLineEdit{parent}, shouldSkipInitialSelection(shouldSkipInitialSelection)
+{
+
+}
+
+void SqlQueryItemLineEdit::focusInEvent(QFocusEvent* e)
+{
+ QLineEdit::focusInEvent(e);
+ if (shouldSkipInitialSelection)
+ deselect();
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemlineedit.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemlineedit.h
new file mode 100644
index 0000000..76a79af
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemlineedit.h
@@ -0,0 +1,20 @@
+#ifndef SQLQUERYITEMLINEEDIT_H
+#define SQLQUERYITEMLINEEDIT_H
+
+#include <QLineEdit>
+
+class SqlQueryItemLineEdit : public QLineEdit
+{
+ Q_OBJECT
+
+ public:
+ explicit SqlQueryItemLineEdit(bool shouldSkipInitialSelection, QWidget *parent = nullptr);
+
+ protected:
+ void focusInEvent(QFocusEvent *e);
+
+ private:
+ bool shouldSkipInitialSelection;
+};
+
+#endif // SQLQUERYITEMLINEEDIT_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp
index 2982415..3c44603 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp
@@ -81,7 +81,7 @@ void SqlQueryModel::setAsyncMode(bool enabled)
queryExecutor->setAsyncMode(enabled);
}
-void SqlQueryModel::executeQuery()
+void SqlQueryModel::executeQuery(bool enforcePage0)
{
if (queryExecutor->isExecutionInProgress())
{
@@ -91,7 +91,7 @@ void SqlQueryModel::executeQuery()
queryExecutor->setSkipRowCounting(false);
queryExecutor->setSortOrder(sortOrder);
- queryExecutor->setPage(0);
+ queryExecutor->setPage(page > -1 && !enforcePage0 ? page : 0);
queryExecutor->setForceSimpleMode(simpleExecutionMode);
reloading = false;
@@ -157,6 +157,23 @@ bool SqlQueryModel::isEmptyQuery() const
return true;
}
+void SqlQueryModel::restoreFocusedCell()
+{
+ if (!storedFocus.isValid() || getCurrentPage() != storedFocus.forPage || getRowsPerPage() != storedFocus.forRowsPerPage ||
+ queryExecutor->getFilters() != storedFocus.forFilter)
+ {
+ forgetFocusedCell();
+ return;
+ }
+
+ QModelIndex idx = index(storedFocus.row, storedFocus.column);
+ if (idx.isValid())
+ {
+ view->setCurrentIndex(idx);
+ view->scrollTo(idx, QAbstractItemView::EnsureVisible);
+ }
+}
+
void SqlQueryModel::internalExecutionStopped()
{
reloading = false;
@@ -712,6 +729,21 @@ void SqlQueryModel::detachDependencyTables()
dbListToDetach.clear();
}
+void SqlQueryModel::rememberFocusedCell()
+{
+ QModelIndex idx = getView()->currentIndex();
+ storedFocus.row = idx.row();
+ storedFocus.column = idx.column();
+ storedFocus.forPage = getCurrentPage();
+ storedFocus.forRowsPerPage = getRowsPerPage();
+ storedFocus.forFilter = queryExecutor->getFilters();
+}
+
+void SqlQueryModel::forgetFocusedCell()
+{
+ storedFocus.reset();
+}
+
QString SqlQueryModel::generateSelectQueryForItems(const QList<SqlQueryItem*>& items)
{
QHash<QString, QVariantList> values = toValuesGroupedByColumns(items);
@@ -1439,6 +1471,7 @@ void SqlQueryModel::handleExecFinished(SqlQueryPtr results)
results.clear();
detachDatabases();
}
+ restoreFocusedCell();
}
void SqlQueryModel::handleExecFailed(int code, QString errorMessage)
@@ -1622,7 +1655,11 @@ void SqlQueryModel::storeStep1NumbersFromExecution()
{
lastExecutionTime = queryExecutor->getLastExecutionTime();
page = queryExecutor->getPage();
- sortOrder = queryExecutor->getSortOrder();
+
+ QueryExecutor::SortList newSortOrder = queryExecutor->getSortOrder();
+ if (!sortOrder.isEmpty() && newSortOrder.isEmpty())
+ notifyWarn(tr("There are less columns in the new query, sort order has been reset."));
+ sortOrder = newSortOrder;
rowsAffected = queryExecutor->getRowsAffected();
if (!queryExecutor->getSkipRowCounting())
@@ -2294,3 +2331,17 @@ QString SqlQueryModel::SelectCellsQueryBuilder::getDatabase() const
{
return database;
}
+
+bool SqlQueryModel::StoredFocus::isValid()
+{
+ return row > -1 && column > -1;
+}
+
+void SqlQueryModel::StoredFocus::reset()
+{
+ row = -1;
+ column = -1;
+ forFilter.clear();
+ forRowsPerPage = -1;
+ forPage = -1;
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h
index 43222f1..7fb6938 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h
@@ -65,6 +65,8 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
bool isExecutionInProgress() const;
StrHash<QString> attachDependencyTables();
void detachDependencyTables();
+ void rememberFocusedCell();
+ void forgetFocusedCell();
/**
* @brief Disables or re-enables async query execution
@@ -244,6 +246,18 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
int argSquence = 0;
};
+ struct StoredFocus
+ {
+ int row = -1;
+ int column = -1;
+ int forPage = -1;
+ int forRowsPerPage = -1;
+ QString forFilter;
+
+ bool isValid();
+ void reset();
+ };
+
/**
* @brief commitAddedRow Inserts new row to a table.
* @param itemsInRow All cells for the new row.
@@ -316,6 +330,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
QueryExecutor* queryExecutor = nullptr;
Db* db = nullptr;
QList<SqlQueryModelColumnPtr> columns;
+ StoredFocus storedFocus;
/**
* @brief tablesInUse
@@ -385,6 +400,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
void notifyItemEditionEnded(const QModelIndex& idx);
int getRowsPerPage() const;
bool isEmptyQuery() const;
+ void restoreFocusedCell();
QString query;
QHash<QString, QVariant> queryParams;
@@ -522,7 +538,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
void prevPage();
void nextPage();
void lastPage();
- void executeQuery();
+ void executeQuery(bool enforcePage0 = false);
void interrupt();
void commit();
void rollback();
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp
index 68287bd..cd53773 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp
@@ -58,6 +58,8 @@ SqlQueryModelColumn::EditionForbiddenReason SqlQueryModelColumn::convert(QueryEx
return EditionForbiddenReason::COMMON_TABLE_EXPRESSION;
case QueryExecutor::ColumnEditionForbiddenReason::VIEW_NOT_EXPANDED:
return EditionForbiddenReason::VIEW_NOT_EXPANDED;
+ case QueryExecutor::ColumnEditionForbiddenReason::RES_INLINE_SUBSEL:
+ return EditionForbiddenReason::RESULT_INLINE_SUBSELECT;
}
return static_cast<EditionForbiddenReason>(-1);
}
@@ -66,6 +68,8 @@ QString SqlQueryModelColumn::resolveMessage(SqlQueryModelColumn::EditionForbidde
{
switch (reason)
{
+ case SqlQueryModelColumn::EditionForbiddenReason::RESULT_INLINE_SUBSELECT:
+ return QObject::tr("Cannot edit columns that are result of an inline subquery.");
case EditionForbiddenReason::COMPOUND_SELECT:
return QObject::tr("Cannot edit columns that are result of compound %1 statements (one that includes %2, %3 or %4 keywords).")
.arg("SELECT", "UNION", "INTERSECT", "EXCEPT");
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h
index 1a347e5..042e336 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h
@@ -28,6 +28,7 @@ class GUI_API_EXPORT SqlQueryModelColumn
EXPRESSION,
SMART_EXECUTION_FAILED,
DISTINCT_RESULTS,
+ RESULT_INLINE_SUBSELECT,
COMMON_TABLE_EXPRESSION,
GENERATED_COLUMN,
VIEW_NOT_EXPANDED
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp
index d9695d7..d815654 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp
@@ -47,7 +47,6 @@ void SqlQueryView::init()
itemDelegate = new SqlQueryItemDelegate();
setItemDelegate(itemDelegate);
setMouseTracking(true);
-// setEditTriggers(QAbstractItemView::AnyKeyPressed);
setEditTriggers(QAbstractItemView::AnyKeyPressed|QAbstractItemView::EditKeyPressed);
setContextMenuPolicy(Qt::CustomContextMenu);
@@ -303,6 +302,7 @@ void SqlQueryView::itemActivated(const QModelIndex& index)
if (!editInEditorIfNecessary(item))
return;
+ item->skipInitialFocusSelection();
edit(getCurrentIndex());
}
@@ -335,7 +335,13 @@ void SqlQueryView::editCurrent()
{
QModelIndex idx = getCurrentIndex();
if (idx.isValid())
+ {
+ SqlQueryItem* item = getModel()->itemFromIndex(idx);
+ if (item)
+ item->skipInitialFocusSelection();
+
edit(idx);
+ }
}
void SqlQueryView::toggleRowsHeightAdjustment(bool enabled)
@@ -547,7 +553,7 @@ void SqlQueryView::goToReferencedRow(const QString& table, const QString& column
QString wrappedTable = wrapObjIfNeeded(table);
QString wrappedColumn = wrapObjIfNeeded(column);
- QString valueStr = wrapValueIfNeeded(value.toString());
+ QString valueStr = valueToSqlLiteral(value.toString());
EditorWindow* win = MAINWINDOW->openSqlEditor(db, sqlTpl.arg(wrappedTable, wrappedColumn, valueStr));
if (!win)
return;
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp
index 50b0c5b..198a45f 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp
@@ -355,10 +355,10 @@ void SqlTableModel::updateColumnsAndValues(const QList<SqlQueryItem*>& itemsInRo
int i = 0;
for (SqlQueryModelColumnPtr modelColumn : modelColumns)
{
+ item = itemsInRow[i++];
if (!modelColumn->canEdit())
continue;
- item = itemsInRow[i++];
if (item->getValue().isNull())
{
if (CFG_UI.General.UseDefaultValueForNull.get() && modelColumn->isDefault())
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlviewmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlviewmodel.cpp
index 1f8422c..23eac36 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlviewmodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlviewmodel.cpp
@@ -20,8 +20,6 @@ void SqlViewModel::setDatabaseAndView(const QString& database, const QString& vi
this->view = view;
//setQuery("SELECT * FROM "+getDataSource());
updateTablesInUse(view);
-
- SchemaResolver resolver(db);
}
QString SqlViewModel::getDataSource()
diff --git a/SQLiteStudio3/guiSQLiteStudio/dataview.cpp b/SQLiteStudio3/guiSQLiteStudio/dataview.cpp
index e7ae9b5..8ec00d0 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dataview.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dataview.cpp
@@ -682,12 +682,6 @@ void DataView::setFormViewEnabled(bool enabled)
setTabEnabled(1, enabled);
}
-void DataView::readData()
-{
- setNavigationState(false);
- model->executeQuery();
-}
-
bool DataView::isUncommitted() const
{
return uncommittedGrid || uncommittedForm;
@@ -718,10 +712,16 @@ void DataView::totalRowsAndPagesAvailable()
updateNavigationState();
}
-void DataView::refreshData()
+void DataView::refreshData(bool keepFocus)
{
totalPagesAvailable = false;
- readData();
+ if (keepFocus)
+ model->rememberFocusedCell();
+ else
+ model->forgetFocusedCell();
+
+ setNavigationState(false);
+ model->executeQuery(!keepFocus);
}
void DataView::insertRow()
diff --git a/SQLiteStudio3/guiSQLiteStudio/dataview.h b/SQLiteStudio3/guiSQLiteStudio/dataview.h
index d8f71dc..43b6507 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dataview.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dataview.h
@@ -138,7 +138,6 @@ class GUI_API_EXPORT DataView : public QTabWidget, public ExtActionContainer
void updateResultsCount(int resultsCount);
void updateCurrentFormViewRow();
void setFormViewEnabled(bool enabled);
- void readData();
void initFormViewForNewRow();
void formViewFocusFirstEditor();
void recreateFilterInputs();
@@ -179,7 +178,7 @@ class GUI_API_EXPORT DataView : public QTabWidget, public ExtActionContainer
signals:
public slots:
- void refreshData();
+ void refreshData(bool keepFocus = true);
private slots:
void dataLoadingEnded(bool successful);
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp
index 6514aa8..c118eb6 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp
@@ -58,6 +58,11 @@ DbTreeItem* DbTreeItem::findItem(DbTreeItem::Type type, const QString& name)
return DbTreeModel::findItem(this, type, name);
}
+DbTreeItem* DbTreeItem::findFirstItem(Type type)
+{
+ return DbTreeModel::findFirstItem(this, type);
+}
+
QStandardItem* DbTreeItem::clone() const
{
return new DbTreeItem(*this);
@@ -293,6 +298,16 @@ void DbTreeItem::setIcon(const Icon& icon)
QStandardItem::setIcon(icon);
}
+bool DbTreeItem::isSchemaReady() const
+{
+ return data(DataRole::SCHEMA_READY).toBool();
+}
+
+void DbTreeItem::setSchemaReady(bool ready)
+{
+ setData(ready, DataRole::SCHEMA_READY);
+}
+
void DbTreeItem::init()
{
Type type = getType();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.h b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.h
index ba230f2..7cce7a2 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.h
@@ -38,6 +38,7 @@ class GUI_API_EXPORT DbTreeItem : public QObject, public QStandardItem
int type() const;
DbTreeItem* findItem(Type type, const QString& name);
+ DbTreeItem* findFirstItem(Type type);
QStandardItem* clone() const;
QList<QStandardItem*> childs() const;
QStringList childNames() const;
@@ -75,6 +76,8 @@ class GUI_API_EXPORT DbTreeItem : public QObject, public QStandardItem
void setHidden(bool hidden);
bool isHidden() const;
void setIcon(const Icon& icon);
+ bool isSchemaReady() const;
+ void setSchemaReady(bool ready);
private:
struct DataRole // not 'enum class' because we need autocasting to int for this one
@@ -84,7 +87,8 @@ class GUI_API_EXPORT DbTreeItem : public QObject, public QStandardItem
TYPE = 1001,
DB = 1002,
ICON_PTR = 1003,
- HIDDEN = 1004
+ HIDDEN = 1004,
+ SCHEMA_READY = 1005
};
};
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
index 6620290..29bf652 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
@@ -280,7 +280,14 @@ void DbTreeModel::expanded(const QModelIndex &index)
return;
}
- if (dynamic_cast<DbTreeItem*>(item)->getType() == DbTreeItem::Type::DIR)
+ DbTreeItem* dbTreeItem = dynamic_cast<DbTreeItem*>(item);
+ if (dbTreeItem->getType() == DbTreeItem::Type::TABLE)
+ loadTableSchema(dbTreeItem);
+
+ if (dbTreeItem->getType() == DbTreeItem::Type::VIEW)
+ loadViewSchema(dbTreeItem);
+
+ if (dbTreeItem->getType() == DbTreeItem::Type::DIR)
itemFromIndex(index)->setIcon(ICONS.DIRECTORY_OPEN);
}
@@ -443,8 +450,9 @@ QString DbTreeModel::getDbToolTip(DbTreeItem* item) const
QString DbTreeModel::getTableToolTip(DbTreeItem* item) const
{
- QStringList rows;
+ const_cast<DbTreeModel*>(this)->loadTableSchema(item); // not nice to const_cast, but nothing better we can do about this
+ QStringList rows;
rows << toolTipHdrRowTmp.arg(ICONS.TABLE.getPath()).arg(tr("Table : %1", "dbtree tooltip").arg(item->text()));
QStandardItem* columnsItem = item->child(0);
@@ -499,20 +507,33 @@ void DbTreeModel::refreshSchema(Db* db, QStandardItem *item)
// Collect all db objects and build the db branch
bool sort = CFG_UI.General.SortObjects.get();
- QStringList tables = resolver.getTables();
- QStringList virtualTables;
- for (const QString& table : tables)
+ QList<SchemaResolver::TableListItem> tableListItems = resolver.getAllTableListItems();
+ QStringList tables;
+ QStringList views;
+ QSet<QString> virtualTables;
+
+ for (SchemaResolver::TableListItem& tableListItem : tableListItems)
{
- if (resolver.isVirtualTable(table))
- virtualTables << table;
+ switch (tableListItem.type)
+ {
+ case SchemaResolver::TableListItem::VIRTUAL_TABLE:
+ virtualTables << tableListItem.name;
+ [[fallthrough]];
+ case SchemaResolver::TableListItem::TABLE:
+ case SchemaResolver::TableListItem::SHADOW_TABLE:
+ tables << tableListItem.name;
+ break;
+ case SchemaResolver::TableListItem::VIEW:
+ views << tableListItem.name;
+ break;
+ case SchemaResolver::TableListItem::UNKNOWN:
+ break;
+ }
}
QList<QStandardItem*> tableItems = refreshSchemaTables(tables, virtualTables, sort);
- StrHash<QList<QStandardItem*>> allTableColumns = refreshSchemaTableColumns(resolver.getAllTableColumns());
- StrHash<QList<QStandardItem*>> indexItems = refreshSchemaIndexes(resolver.getGroupedIndexes(), sort);
- StrHash<QList<QStandardItem*>> triggerItems = refreshSchemaTriggers(resolver.getGroupedTriggers(), sort);
- QList<QStandardItem*> viewItems = refreshSchemaViews(resolver.getViews(), sort);
- refreshSchemaBuild(item, tableItems, indexItems, triggerItems, viewItems, allTableColumns);
+ QList<QStandardItem*> viewItems = refreshSchemaViews(views, sort);
+ refreshSchemaBuild(item, tableItems, viewItems);
populateChildItemsWithDb(item, db);
restoreExpandedState(expandedState, item);
}
@@ -530,7 +551,7 @@ void DbTreeModel::collectExpandedState(QHash<QString, bool> &state, QStandardIte
collectExpandedState(state, parentItem->child(i));
}
-QList<QStandardItem *> DbTreeModel::refreshSchemaTables(const QStringList &tables, const QStringList& virtualTables, bool sort)
+QList<QStandardItem *> DbTreeModel::refreshSchemaTables(const QStringList &tables, const QSet<QString>& virtualTables, bool sort)
{
QStringList sortedTables = tables;
if (sort)
@@ -548,52 +569,44 @@ QList<QStandardItem *> DbTreeModel::refreshSchemaTables(const QStringList &table
return items;
}
-StrHash<QList<QStandardItem*>> DbTreeModel::refreshSchemaTableColumns(const StrHash<QStringList> &columns)
+QList<QStandardItem*> DbTreeModel::refreshSchemaTableColumns(const QStringList& columns)
{
- QStringList sortedColumns;
bool doSort = CFG_UI.General.SortColumns.get();
- StrHash<QList<QStandardItem*>> items;
- for (const QString& key : columns.keys())
- {
- sortedColumns = columns[key];
- if (doSort)
- ::sSort(sortedColumns);
- for (const QString& column : sortedColumns)
- items[key] += DbTreeItemFactory::createColumn(column, this);
- }
+ QStringList sortedColumns = columns;
+ if (doSort)
+ ::sSort(sortedColumns);
+
+ QList<QStandardItem*> items;
+ for (const QString& column : sortedColumns)
+ items += DbTreeItemFactory::createColumn(column, this);
+
return items;
}
-StrHash<QList<QStandardItem *> > DbTreeModel::refreshSchemaIndexes(const StrHash<QStringList> &indexes, bool sort)
+QList<QStandardItem*> DbTreeModel::refreshSchemaIndexes(const QStringList& indexes, bool sort)
{
- StrHash<QList<QStandardItem *> > items;
- QStringList sortedIndexes;
- for (const QString& key : indexes.keys())
- {
- sortedIndexes = indexes[key];
- if (sort)
- sortedIndexes.sort(Qt::CaseInsensitive);
+ QStringList sortedIndexes = indexes;
+ if (sort)
+ sortedIndexes.sort(Qt::CaseInsensitive);
+
+ QList<QStandardItem*> items;
+ for (const QString& index : sortedIndexes)
+ items += DbTreeItemFactory::createIndex(index, this);
- for (const QString& index : sortedIndexes)
- items[key] += DbTreeItemFactory::createIndex(index, this);
- }
return items;
}
-StrHash<QList<QStandardItem*>> DbTreeModel::refreshSchemaTriggers(const StrHash<QStringList> &triggers, bool sort)
+QList<QStandardItem*> DbTreeModel::refreshSchemaTriggers(const QStringList& triggers, bool sort)
{
- StrHash<QList<QStandardItem*>> items;
- QStringList sortedTriggers;
- for (const QString& key : triggers.keys())
- {
- sortedTriggers = triggers[key];
- if (sort)
- sortedTriggers.sort(Qt::CaseInsensitive);
+ QStringList sortedTriggers = triggers;
+ if (sort)
+ sortedTriggers.sort(Qt::CaseInsensitive);
+
+ QList<QStandardItem*> items;
+ for (const QString& trigger : sortedTriggers)
+ items += DbTreeItemFactory::createTrigger(trigger, this);
- for (const QString& trigger : sortedTriggers)
- items[key] += DbTreeItemFactory::createTrigger(trigger, this);
- }
return items;
}
@@ -621,12 +634,68 @@ void DbTreeModel::populateChildItemsWithDb(QStandardItem *parentItem, Db* db)
}
}
+void DbTreeModel::loadTableSchema(DbTreeItem* tableItem)
+{
+ if (tableItem->isSchemaReady())
+ return;
+
+ Db* db = tableItem->getDb();
+ QString table = tableItem->text();
+
+ SchemaResolver resolver(db);
+ resolver.setIgnoreSystemObjects(!CFG_UI.General.ShowSystemObjects.get());
+
+ bool sort = CFG_UI.General.SortObjects.get();
+
+ DbTreeItem* columnsItem = tableItem->findFirstItem(DbTreeItem::Type::COLUMNS);
+ DbTreeItem* indexesItem = tableItem->findFirstItem(DbTreeItem::Type::INDEXES);
+ DbTreeItem* triggersItem = tableItem->findFirstItem(DbTreeItem::Type::TRIGGERS);
+
+ QList<QStandardItem*> tableColumns = refreshSchemaTableColumns(resolver.getTableColumns(table));
+ QList<QStandardItem*> indexItems = refreshSchemaIndexes(resolver.getIndexesForTable(table), sort);
+ QList<QStandardItem*> triggerItems = refreshSchemaTriggers(resolver.getTriggersForTable(table), sort);
+
+ for (QStandardItem* columnItem : tableColumns)
+ columnsItem->appendRow(columnItem);
+
+ for (QStandardItem* indexItem : indexItems)
+ indexesItem->appendRow(indexItem);
+
+ for (QStandardItem* triggerItem : triggerItems)
+ triggersItem->appendRow(triggerItem);
+
+ populateChildItemsWithDb(columnsItem, db);
+ populateChildItemsWithDb(indexesItem, db);
+ populateChildItemsWithDb(triggersItem, db);
+
+ tableItem->setSchemaReady(true);
+}
+
+void DbTreeModel::loadViewSchema(DbTreeItem* viewItem)
+{
+ if (viewItem->isSchemaReady())
+ return;
+
+ Db* db = viewItem->getDb();
+ QString view = viewItem->text();
+
+ SchemaResolver resolver(db);
+ resolver.setIgnoreSystemObjects(!CFG_UI.General.ShowSystemObjects.get());
+
+ bool sort = CFG_UI.General.SortObjects.get();
+
+ DbTreeItem* triggersItem = viewItem->findFirstItem(DbTreeItem::Type::TRIGGERS);
+
+ QList<QStandardItem*> triggerItems = refreshSchemaTriggers(resolver.getTriggersForView(view), sort);
+ for (QStandardItem* triggerItem : triggerItems)
+ triggersItem->appendRow(triggerItem);
+
+ viewItem->setSchemaReady(true);
+}
+
void DbTreeModel::refreshSchemaBuild(QStandardItem *dbItem,
QList<QStandardItem*> tables,
- StrHash<QList<QStandardItem*> > indexes,
- StrHash<QList<QStandardItem*> > triggers,
- QList<QStandardItem*> views,
- StrHash<QList<QStandardItem*> > allTableColumns)
+ QList<QStandardItem*> views)
{
DbTreeItem* tablesItem = DbTreeItemFactory::createTables(this);
DbTreeItem* viewsItem = DbTreeItemFactory::createViews(this);
@@ -649,14 +718,7 @@ void DbTreeModel::refreshSchemaBuild(QStandardItem *dbItem,
tableItem->appendRow(indexesItem);
tableItem->appendRow(triggersItem);
- for (QStandardItem* columnItem : allTableColumns[tableItem->text()])
- columnsItem->appendRow(columnItem);
-
- for (QStandardItem* indexItem : indexes[tableItem->text()])
- indexesItem->appendRow(indexItem);
-
- for (QStandardItem* triggerItem : triggers[tableItem->text()])
- triggersItem->appendRow(triggerItem);
+ dynamic_cast<DbTreeItem*>(tableItem)->setSchemaReady(false);
}
for (QStandardItem* viewItem : views)
{
@@ -664,8 +726,8 @@ void DbTreeModel::refreshSchemaBuild(QStandardItem *dbItem,
triggersItem = DbTreeItemFactory::createTriggers(this);
viewItem->appendRow(triggersItem);
- for (QStandardItem* triggerItem : triggers[viewItem->text()])
- triggersItem->appendRow(triggerItem);
+
+ dynamic_cast<DbTreeItem*>(viewItem)->setSchemaReady(false);
}
}
@@ -680,22 +742,6 @@ void DbTreeModel::restoreExpandedState(const QHash<QString, bool>& expandedState
restoreExpandedState(expandedState, child);
}
-DbTreeItem* DbTreeModel::findFirstItemOfType(DbTreeItem::Type type, QStandardItem* parentItem)
-{
- DbTreeItem* child = nullptr;
- for (int i = 0; i < parentItem->rowCount(); i++)
- {
- child = dynamic_cast<DbTreeItem*>(parentItem->child(i));
- if (child->getType() == type)
- return child;
-
- child = findFirstItemOfType(type, child);
- if (child)
- return child;
- }
- return nullptr;
-}
-
void DbTreeModel::dbConnected(Db* db, bool expandItem)
{
QStandardItem* item = findItem(DbTreeItem::Type::DB, db);
@@ -819,7 +865,7 @@ DbTreeItem *DbTreeModel::findItem(DbTreeItem::Type type, Db* db)
DbTreeItem* DbTreeModel::findFirstItemOfType(DbTreeItem::Type type)
{
- return findFirstItemOfType(type, root());
+ return findFirstItem(root(), type);
}
DbTreeItem *DbTreeModel::findItemBySignature(const QString &signature)
@@ -883,7 +929,7 @@ QList<DbTreeItem*> DbTreeModel::findItems(QStandardItem* parentItem, DbTreeItem:
item = dynamic_cast<DbTreeItem*>(parentItem->child(i));
// Search recursively
- if (item->getType() == DbTreeItem::Type::DIR)
+ if (item->hasChildren())
items += findItems(item, type);
if (item->getType() != type)
@@ -895,6 +941,28 @@ QList<DbTreeItem*> DbTreeModel::findItems(QStandardItem* parentItem, DbTreeItem:
return items;
}
+DbTreeItem* DbTreeModel::findFirstItem(QStandardItem* parentItem, DbTreeItem::Type type)
+{
+ for (int i = 0; i < parentItem->rowCount(); i++)
+ {
+ DbTreeItem* item = dynamic_cast<DbTreeItem*>(parentItem->child(i));
+
+ if (item->hasChildren())
+ {
+ DbTreeItem* child = findFirstItem(item, type);
+ if (child)
+ return child;
+ }
+
+ if (item->getType() != type)
+ continue;
+
+ return item;
+ }
+
+ return nullptr;
+}
+
QStandardItem* DbTreeModel::root() const
{
return invisibleRootItem();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
index 86dc8a6..5fb91ba 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
@@ -57,6 +57,7 @@ class GUI_API_EXPORT DbTreeModel : public QStandardItemModel
static DbTreeItem* findItem(QStandardItem *parentItem, DbTreeItem::Type type, const QString &name);
static DbTreeItem* findItem(QStandardItem* parentItem, DbTreeItem::Type type, Db* db);
static QList<DbTreeItem*> findItems(QStandardItem* parentItem, DbTreeItem::Type type);
+ static DbTreeItem* findFirstItem(QStandardItem* parentItem, DbTreeItem::Type type);
static void staticInit();
static const constexpr char* MIMETYPE = "application/x-sqlitestudio-dbtreeitem";
@@ -69,16 +70,16 @@ class GUI_API_EXPORT DbTreeModel : public QStandardItemModel
void refreshSchema(Db* db, QStandardItem* item);
void collectExpandedState(QHash<QString, bool>& state, QStandardItem* parentItem = nullptr);
QStandardItem* refreshSchemaDb(Db* db);
- QList<QStandardItem*> refreshSchemaTables(const QStringList &tables, const QStringList& virtualTables, bool sort);
- StrHash<QList<QStandardItem*>> refreshSchemaTableColumns(const StrHash<QStringList>& columns);
- StrHash<QList<QStandardItem*>> refreshSchemaIndexes(const StrHash<QStringList>& indexes, bool sort);
- StrHash<QList<QStandardItem*>> refreshSchemaTriggers(const StrHash<QStringList>& triggers, bool sort);
+ QList<QStandardItem*> refreshSchemaTables(const QStringList &tables, const QSet<QString>& virtualTables, bool sort);
+ QList<QStandardItem*> refreshSchemaTableColumns(const QStringList& columns);
+ QList<QStandardItem*> refreshSchemaIndexes(const QStringList& indexes, bool sort);
+ QList<QStandardItem*> refreshSchemaTriggers(const QStringList& triggers, bool sort);
QList<QStandardItem*> refreshSchemaViews(const QStringList &views, bool sort);
void populateChildItemsWithDb(QStandardItem* parentItem, Db* db);
- void refreshSchemaBuild(QStandardItem* dbItem, QList<QStandardItem*> tables, StrHash<QList<QStandardItem*> > indexes,
- StrHash<QList<QStandardItem*> > triggers, QList<QStandardItem*> views, StrHash<QList<QStandardItem*> > allTableColumns);
+ void loadTableSchema(DbTreeItem* tableItem);
+ void loadViewSchema(DbTreeItem* viewItem);
+ void refreshSchemaBuild(QStandardItem* dbItem, QList<QStandardItem*> tables, QList<QStandardItem*> views);
void restoreExpandedState(const QHash<QString, bool>& expandedState, QStandardItem* parentItem);
- DbTreeItem* findFirstItemOfType(DbTreeItem::Type type, QStandardItem* parentItem);
QString getToolTip(DbTreeItem *item) const;
QString getDbToolTip(DbTreeItem *item) const;
QString getTableToolTip(DbTreeItem *item) const;
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp
index a217da6..cf5848a 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp
@@ -9,11 +9,13 @@
#include "constraints/constraintpanel.h"
#include "datatype.h"
#include "uiutils.h"
+#include "common/dialogsizehandler.h"
#include <QDebug>
#include <QCheckBox>
#include <QMessageBox>
#include <QDebug>
#include <QPushButton>
+#include <schemaresolver.h>
ColumnDialog::ColumnDialog(Db* db, QWidget *parent) :
QDialog(parent),
@@ -33,6 +35,7 @@ void ColumnDialog::init()
ui->setupUi(this);
limitDialogWidth(this);
setWindowIcon(ICONS.COLUMN);
+ DialogSizeHandler::applyFor(this);
ui->scale->setStrict(true, true);
ui->precision->setStrict(true, true);
@@ -403,7 +406,7 @@ void ColumnDialog::updateTypeValidations()
setValidState(ui->typeCombo, typeOk, typeErrorMsg);
if (typeOk && integerTypeEnforced)
- setValidStateTooltip(ui->typeCombo, integerEnforcedMsg);
+ setValidStateTooltip(ui->typeCombo, integerEnforcedMsg);
if (!scaleOk || !precisionOk || !typeOk)
{
@@ -437,6 +440,43 @@ bool ColumnDialog::hasAutoIncr() const
return false;
}
+void ColumnDialog::validateFkTypeMatch()
+{
+ QString fkTypeWarningMsg = tr("Referenced column type (%1) is different than type declared in this column. It may cause issues while inserting or updating data.");
+
+ for (SqliteCreateTable::Column::Constraint*& constr : column->getConstraints(SqliteCreateTable::Column::Constraint::FOREIGN_KEY))
+ {
+ if (!constr->foreignKey || constr->foreignKey->indexedColumns.isEmpty() || constr->foreignKey->foreignTable.isNull())
+ continue;
+
+ QString fkTable = constr->foreignKey->foreignTable;
+ QString fkColumn = constr->foreignKey->indexedColumns.first()->name;
+ if (!fkTableTypesCache.contains(fkTable, Qt::CaseInsensitive))
+ {
+ SchemaResolver resolver(db);
+ fkTableTypesCache[fkTable] = resolver.getTableColumnDataTypesByName(fkTable);;
+ }
+
+ StrHash<DataType> fkTypes = fkTableTypesCache.value(fkTable, Qt::CaseInsensitive);
+ if (fkTypes.isEmpty())
+ continue;
+
+ DataType fkType = fkTypes.value(fkColumn, Qt::CaseInsensitive);
+ if (fkType.toString().toLower().trimmed() != ui->typeCombo->currentText().toLower().trimmed())
+ {
+ auto fkButton = getToolButtonForConstraint(constr);
+ if (!fkButton)
+ continue;
+
+ if (isValidStateIndicatorVisible(fkButton))
+ continue;
+
+ setValidStateWarning(fkButton, fkTypeWarningMsg.arg(fkType.toString()));
+ break;
+ }
+ }
+}
+
void ColumnDialog::moveConstraintUp()
{
QModelIndex idx = ui->constraintsView->currentIndex();
@@ -618,6 +658,7 @@ void ColumnDialog::updateValidations()
updateConstraint(constr);
updateTypeValidations();
+ validateFkTypeMatch();
}
void ColumnDialog::updateConstraint(SqliteCreateTable::Column::Constraint* constraint)
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h
index c9faf23..bc02d14 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h
@@ -5,6 +5,7 @@
#include "common/extactioncontainer.h"
#include "constraintdialog.h"
#include "guiSQLiteStudio_global.h"
+#include "common/strhash.h"
#include <QDialog>
#include <QPointer>
@@ -71,6 +72,7 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer
void updateTypeValidations();
void updateTypeForAutoIncr();
bool hasAutoIncr() const;
+ void validateFkTypeMatch();
Ui::ColumnDialog *ui = nullptr;
SqliteCreateTable::ColumnPtr column;
@@ -79,6 +81,7 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer
Db* db = nullptr;
bool integerTypeEnforced = false;
QSet<ConstraintDialog::Constraint> disabledConstraints;
+ StrHash<StrHash<DataType>> fkTableTypesCache;
private slots:
void updateConstraintsToolbarState();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp
index 8c80f6d..425acad 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp
@@ -28,6 +28,7 @@
#include "syntaxhighlighterplugin.h"
#include "sqleditor.h"
#include "style.h"
+#include "common/dialogsizehandler.h"
#include <QSignalMapper>
#include <QLineEdit>
#include <QSpinBox>
@@ -201,6 +202,7 @@ void ConfigDialog::init()
{
ui->setupUi(this);
setWindowIcon(ICONS.CONFIGURE);
+ DialogSizeHandler::applyFor(this);
ui->categoriesTree->setCurrentItem(ui->categoriesTree->topLevelItem(0));
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp
index 0333cbc..84c4cdc 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp
@@ -79,6 +79,8 @@ void ConstraintDialog::init()
}
currentPanel->setDb(db);
+ currentPanel->setCreateTableStmt(createTable.data());
+ currentPanel->setColumnStmt(columnStmt.data());
currentPanel->setConstraint(constrStatement);
connect(currentPanel, SIGNAL(updateValidation()), this, SLOT(validate()));
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp
index e6a53db..2b85be3 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp
@@ -145,6 +145,8 @@ void DbDialog::init()
ui->testConnIcon->setVisible(false);
+ connect(ui->existingDatabaseRadio, SIGNAL(clicked()), this, SLOT(updateCreateMode()));
+ connect(ui->createDatabaseRadio, SIGNAL(clicked()), this, SLOT(updateCreateMode()));
connect(ui->fileEdit, SIGNAL(textChanged(QString)), this, SLOT(fileChanged(QString)));
connect(ui->nameEdit, SIGNAL(textEdited(QString)), this, SLOT(nameModified(QString)));
connect(ui->browseOpenButton, SIGNAL(clicked()), this, SLOT(browseClicked()));
@@ -172,7 +174,9 @@ void DbDialog::updateOptions()
customBrowseHandler = nullptr;
ui->pathGroup->setTitle(tr("File"));
- ui->browseOpenButton->setToolTip(tr("Select new or existing file on local computer"));
+ ui->existingDatabaseRadio->setChecked(true);
+ ui->createDatabaseRadio->setChecked(false);
+ updateCreateMode();
optionWidgets.clear();
optionKeyToWidget.clear();
@@ -209,6 +213,10 @@ void DbDialog::addOption(const DbPluginOption& option, int& row)
// This option does not add any editor, but has it's own label for path edit.
row--;
ui->pathGroup->setTitle(option.label);
+ ui->existingDatabaseRadio->setChecked(true);
+ ui->createDatabaseRadio->setChecked(false);
+ ui->createDatabaseRadio->setVisible(false);
+ updateCreateMode();
if (!option.toolTip.isEmpty())
ui->browseOpenButton->setToolTip(option.toolTip);
@@ -567,6 +575,13 @@ bool DbDialog::validate()
setValidState(ui->fileEdit, false, tr("Enter a database file path."));
fileState = false;
}
+ else if (QFileInfo(getPath()).isRelative())
+ {
+ setValidStateWarning(ui->fileEdit,
+ tr("You're using a relative file path, which will be resolved to \"%1\" according to the application's working directory. It's always better to use absolute file path to avoid unexpected database location.")
+ .arg(QFileInfo(getPath()).absoluteFilePath()));
+ fileState = false;
+ }
if (fileState)
{
@@ -689,7 +704,7 @@ void DbDialog::browseClicked()
else
dir = getFileDialogInitPath();
- QString path = getDbPath(dir);
+ QString path = getDbPath(createMode, dir);
if (path.isNull())
return;
@@ -728,6 +743,15 @@ void DbDialog::nameModified(const QString &value)
updateState();
}
+void DbDialog::updateCreateMode()
+{
+ createMode = ui->createDatabaseRadio->isChecked();
+ ui->browseOpenButton->setToolTip(
+ createMode ? tr("Choose a location for the new database file")
+ : tr("Browse for existing database file on local computer")
+ );
+}
+
void DbDialog::accept()
{
QString name = getName();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.h
index 76cd3ec..a52734b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.h
@@ -74,6 +74,7 @@ class GUI_API_EXPORT DbDialog : public QDialog
bool disableTypeAutodetection = false;
bool doAutoTest = false;
bool nameManuallyEdited = false;
+ bool createMode = false;
ImmediateTooltip* connIconTooltip = nullptr;
static const constexpr int ADDITIONAL_ROWS_BEGIN_INDEX = 1;
@@ -88,6 +89,7 @@ class GUI_API_EXPORT DbDialog : public QDialog
void propertyChanged();
void dbTypeChanged(int index);
void nameModified(const QString &value);
+ void updateCreateMode();
public slots:
void accept();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.ui
index f0ebe2a..880175f 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.ui
@@ -44,21 +44,42 @@
<property name="title">
<string>File</string>
</property>
- <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
<item>
- <widget class="QLineEdit" name="fileEdit"/>
+ <widget class="QRadioButton" name="existingDatabaseRadio">
+ <property name="text">
+ <string>Select an existing database file</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
</item>
<item>
- <widget class="QToolButton" name="browseOpenButton">
+ <widget class="QRadioButton" name="createDatabaseRadio">
<property name="text">
- <string/>
- </property>
- <property name="icon">
- <iconset resource="../icons.qrc">
- <normaloff>:/icons/img/open_sql_file.png</normaloff>:/icons/img/open_sql_file.png</iconset>
+ <string>Create a new database file</string>
</property>
</widget>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QLineEdit" name="fileEdit"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="browseOpenButton">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../icons.qrc">
+ <normaloff>:/icons/img/open_sql_file.png</normaloff>:/icons/img/open_sql_file.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
</layout>
</widget>
</item>
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp
index 3af221f..f3863c8 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/ddlpreviewdialog.cpp
@@ -4,6 +4,7 @@
#include "uiconfig.h"
#include "sqlitestudio.h"
#include "db/db.h"
+#include "common/dialogsizehandler.h"
DdlPreviewDialog::DdlPreviewDialog(Db* db, QWidget *parent) :
QDialog(parent),
@@ -11,6 +12,7 @@ DdlPreviewDialog::DdlPreviewDialog(Db* db, QWidget *parent) :
db(db)
{
ui->setupUi(this);
+ DialogSizeHandler::applyFor(this);
}
DdlPreviewDialog::~DdlPreviewDialog()
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp
index 135bc9d..820e4cc 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp
@@ -16,6 +16,7 @@
#include "services/notifymanager.h"
#include "themetuner.h"
#include "uiconfig.h"
+#include "common/dialogsizehandler.h"
#include <QClipboard>
#include <QDebug>
#include <QDir>
@@ -52,6 +53,7 @@ void ExportDialog::init()
ui->setupUi(this);
THEME_TUNER->darkThemeFix(this);
limitDialogWidth(this);
+ DialogSizeHandler::applyFor(this);
#ifdef Q_OS_MACX
resize(width() + 150, height());
@@ -61,7 +63,9 @@ void ExportDialog::init()
widgetCover = new WidgetCover(this);
widgetCover->initWithInterruptContainer(tr("Cancel"));
connect(widgetCover, SIGNAL(cancelClicked()), EXPORT_MANAGER, SLOT(interrupt()));
+ connect(EXPORT_MANAGER, SIGNAL(finishedStep(int)), widgetCover, SLOT(setProgress(int)));
widgetCover->setVisible(false);
+ widgetCover->displayProgress(0, "%v");
initPageOrder();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp
index f443f18..6c9c8c7 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp
@@ -13,6 +13,7 @@
#include "themetuner.h"
#include "iconmanager.h"
#include "mainwindow.h"
+#include "common/dialogsizehandler.h"
#include <QDir>
#include <QDebug>
#include <QFileDialog>
@@ -102,6 +103,7 @@ void ImportDialog::init()
ui->setupUi(this);
THEME_TUNER->darkThemeFix(this);
limitDialogWidth(this);
+ DialogSizeHandler::applyFor(this);
#ifdef Q_OS_MACX
resize(width() + 150, height());
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp
index d5249d0..ad56f64 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp
@@ -13,6 +13,7 @@
#include "indexexprcolumndialog.h"
#include "windows/editorwindow.h"
#include "services/codeformatter.h"
+#include "common/dialogsizehandler.h"
#include <QDebug>
#include <QGridLayout>
#include <QSignalMapper>
@@ -64,6 +65,7 @@ void IndexDialog::init()
{
ui->setupUi(this);
limitDialogWidth(this);
+ DialogSizeHandler::applyFor(this);
if (!db || !db->isOpen())
{
qCritical() << "Created IndexDialog for null or closed database.";
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp
index 89fff04..734f813 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp
@@ -11,6 +11,7 @@
#include "services/populatemanager.h"
#include "common/widgetcover.h"
#include "common/compatibility.h"
+#include "common/dialogsizehandler.h"
#include <QPushButton>
#include <QGridLayout>
#include <QCheckBox>
@@ -45,6 +46,7 @@ void PopulateDialog::init()
{
ui->setupUi(this);
limitDialogWidth(this);
+ DialogSizeHandler::applyFor(this);
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Populate", "populate dialog button"));
plugins = PLUGINS->getLoadedPlugins<PopulatePlugin>();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/searchtextdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/searchtextdialog.cpp
index 578a253..b8992b4 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/searchtextdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/searchtextdialog.cpp
@@ -2,12 +2,14 @@
#include "ui_searchtextdialog.h"
#include "searchtextlocator.h"
#include "common/unused.h"
+#include "common/dialogsizehandler.h"
SearchTextDialog::SearchTextDialog(SearchTextLocator* textLocator, QWidget *parent) :
QDialog(parent),
ui(new Ui::SearchTextDialog), textLocator(textLocator)
{
ui->setupUi(this);
+ DialogSizeHandler::applyFor(this);
connect(textLocator, SIGNAL(replaceAvailable(bool)), this, SLOT(setReplaceAvailable(bool)));
connect(ui->findEdit, SIGNAL(textChanged(QString)), this, SLOT(markModifiedState()));
connect(ui->caseSensitiveCheck, SIGNAL(toggled(bool)), this, SLOT(markModifiedState()));
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp
index 5091613..61fdadd 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp
@@ -13,6 +13,7 @@
#include "services/config.h"
#include "uiutils.h"
#include "services/codeformatter.h"
+#include "common/dialogsizehandler.h"
#include <QDebug>
#include <QMessageBox>
#include <QPushButton>
@@ -83,6 +84,7 @@ void TriggerDialog::init()
{
ui->setupUi(this);
limitDialogWidth(this);
+ DialogSizeHandler::applyFor(this);
connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(updateDdlTab(int)));
connect(ui->actionColumns, SIGNAL(clicked()), this, SLOT(showColumnsDialog()));
diff --git a/SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp b/SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp
index eba2f4c..28edbe3 100644
--- a/SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp
@@ -31,10 +31,11 @@ bool ExtendedPalette::styleChanged(QStyle *style, const QString &themeName)
{
UNUSED(themeName);
QPalette stdPalette = style->standardPalette();
- if (stdPalette == lastPalette)
+ QVariant paletteVariant = stdPalette;
+ if (paletteVariant == initializedForPalette)
return false;
- lastPalette = stdPalette;
+ initializedForPalette = paletteVariant;
bool isDark = stdPalette.base().color().lightness() < 128;
static const QColor stdStrColor = QColor(Qt::green);
diff --git a/SQLiteStudio3/guiSQLiteStudio/extendedpalette.h b/SQLiteStudio3/guiSQLiteStudio/extendedpalette.h
index 6afaeba..0891ce7 100644
--- a/SQLiteStudio3/guiSQLiteStudio/extendedpalette.h
+++ b/SQLiteStudio3/guiSQLiteStudio/extendedpalette.h
@@ -3,6 +3,7 @@
#include <QBrush>
#include <QPalette>
+#include <QVariant>
class QStyle;
@@ -39,7 +40,7 @@ class ExtendedPalette
QBrush editorCurrentQueryBrush;
QBrush mdiAreaBaseBrush;
- QPalette lastPalette;
+ QVariant initializedForPalette;
};
#endif // EXTENDEDPALETTE_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro b/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro
index 9a436de..fde6802 100644
--- a/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro
+++ b/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro
@@ -33,10 +33,12 @@ DEFINES += GUISQLITESTUDIO_LIBRARY
SOURCES +=\
common/dbcombobox.cpp \
+ common/dialogsizehandler.cpp \
common/immediatetooltip.cpp \
common/mouseshortcut.cpp \
constraints/columngeneratedpanel.cpp \
datagrid/fkcombobox.cpp \
+ datagrid/sqlqueryitemlineedit.cpp \
extendedpalette.cpp \
mainwindow.cpp \
iconmanager.cpp \
@@ -193,10 +195,12 @@ SOURCES +=\
HEADERS += mainwindow.h \
common/dbcombobox.h \
+ common/dialogsizehandler.h \
common/immediatetooltip.h \
common/mouseshortcut.h \
constraints/columngeneratedpanel.h \
datagrid/fkcombobox.h \
+ datagrid/sqlqueryitemlineedit.h \
extendedpalette.h \
iconmanager.h \
dbtree/dbtreemodel.h \
diff --git a/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp b/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp
index d1f1a47..1fb57ec 100644
--- a/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp
@@ -25,6 +25,8 @@
#include "dbtree/dbtreeview.h"
#include "common/lazytrigger.h"
#include "common/extaction.h"
+#include "db/dbsqlite3.h"
+#include "dialogs/dbdialog.h"
#include <QAction>
#include <QMenu>
#include <QTimer>
@@ -35,6 +37,7 @@
#include <QScrollBar>
#include <QFileDialog>
#include <QtConcurrent/QtConcurrent>
+#include <QMessageBox>
#include <QStyle>
CFG_KEYS_DEFINE(SqlEditor)
@@ -727,6 +730,9 @@ void SqlEditor::highlightParenthesis(QList<QTextEdit::ExtraSelection>& selection
void SqlEditor::highlightCurrentQuery(QList<QTextEdit::ExtraSelection>& selections)
{
+ if (!richFeaturesEnabled)
+ return;
+
QTextCursor cursor = textCursor();
int curPos = cursor.position();
QString contents = cursor.document()->toPlainText();
@@ -735,7 +741,7 @@ void SqlEditor::highlightCurrentQuery(QList<QTextEdit::ExtraSelection>& selectio
return;
QTextEdit::ExtraSelection selection;
- selection.format.setBackground(STYLE->extendedPalette().editorCurrentQueryBase());
+ selection.format.setBackground(Cfg::getSyntaxCurrentQueryBg());
cursor.setPosition(boundries.first);
cursor.setPosition(boundries.second, QTextCursor::KeepAnchor);
@@ -1100,7 +1106,7 @@ void SqlEditor::highlightCurrentLine(QList<QTextEdit::ExtraSelection>& selection
if (!isReadOnly() && isEnabled())
{
QTextEdit::ExtraSelection selection;
- selection.format.setBackground(STYLE->extendedPalette().editorLineBase());
+ selection.format.setBackground(Cfg::getSyntaxCurrentLineBg());
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = textCursor();
selection.cursor.clearSelection();
@@ -1197,6 +1203,24 @@ void SqlEditor::loadFromFile()
setFileDialogInitPathByFile(fName);
+ if (DbSqlite3::isDbFile(fName))
+ {
+ DbDialog dialog(DbDialog::ADD, MAINWINDOW);
+ dialog.setPath(fName);
+ dialog.setDoAutoTest(true);
+ dialog.exec();
+ return;
+ }
+
+ if (QFile(fName).size() > HUGE_QUERY_LENGTH)
+ {
+ QMessageBox::StandardButton resp = QMessageBox::question(this, tr("Open file"),
+ tr("This file is huge (over %1 MB). Are you sure you want to load it into SQL query editor?")
+ .arg(HUGE_QUERY_LENGTH / 1024 / 1024));
+ if (resp != QMessageBox::Yes)
+ return;
+ }
+
QString err;
QString sql = readFileContents(fName, &err);
if (sql.isNull() && !err.isNull())
@@ -1205,9 +1229,13 @@ void SqlEditor::loadFromFile()
return;
}
- setPlainText(sql);
-
- loadedFile = fName;
+ if (toPlainText().trimmed().isEmpty())
+ {
+ setPlainText(sql);
+ loadedFile = fName;
+ }
+ else
+ MAINWINDOW->openSqlEditor(db, sql);
}
void SqlEditor::deleteLine()
@@ -1715,10 +1743,11 @@ void SqlEditor::saveSelection()
}
void SqlEditor::restoreSelection()
-{
+{
QTextCursor cur = textCursor();
cur.setPosition(storedSelectionStart);
cur.setPosition(storedSelectionEnd, QTextCursor::KeepAnchor);
+ setTextCursor(cur);
}
QToolBar* SqlEditor::getToolBar(int toolbar) const
diff --git a/SQLiteStudio3/guiSQLiteStudio/sqleditor.h b/SQLiteStudio3/guiSQLiteStudio/sqleditor.h
index 4af89c1..b78b46b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/sqleditor.h
+++ b/SQLiteStudio3/guiSQLiteStudio/sqleditor.h
@@ -124,6 +124,8 @@ class GUI_API_EXPORT SqlEditor : public QPlainTextEdit, public ExtActionContaine
bool getAlwaysEnforceErrorsChecking() const;
void setAlwaysEnforceErrorsChecking(bool newAlwaysEnforceErrorsChecking);
+ static constexpr int HUGE_QUERY_LENGTH = 10 * 1024 * 1024; // 10MB of SQL
+
protected:
void setupDefShortcuts();
void createActions();
diff --git a/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp b/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp
index 2e6a93a..8f3936e 100644
--- a/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp
@@ -55,6 +55,18 @@ QList<QAction*> TaskBar::getTasks() const
void TaskBar::init()
{
setAcceptDrops(true);
+ setStyleSheet(R"(
+ QToolButton:checked {
+ color: white;
+ background-color: #0078D7;
+ border: 2px solid #005A9E;
+ border-radius: 4px;
+ }
+ QToolButton:hover {
+ background-color: #005A9E;
+ color: white;
+ }
+ )");
}
void TaskBar::mousePressed()
diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de_DE.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de_DE.ts
index de05638..a732e3d 100644
--- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de_DE.ts
+++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_de_DE.ts
@@ -5321,13 +5321,13 @@ find next</source>
<location filename="../sqleditor.cpp" line="165"/>
<source>Select file to save SQL</source>
<comment>sql editor</comment>
- <translation>SQL aus Datei laden</translation>
+ <translation>Datei zum Speichern von SQL auswählen</translation>
</message>
<message>
<location filename="../sqleditor.cpp" line="166"/>
<source>Load SQL from file</source>
<comment>sql editor</comment>
- <translation>Zeile löschen</translation>
+ <translation>SQL aus Datei laden</translation>
</message>
<message>
<location filename="../sqleditor.cpp" line="167"/>
diff --git a/SQLiteStudio3/guiSQLiteStudio/uiutils.cpp b/SQLiteStudio3/guiSQLiteStudio/uiutils.cpp
index a73b8ee..cdad77c 100644
--- a/SQLiteStudio3/guiSQLiteStudio/uiutils.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/uiutils.cpp
@@ -35,7 +35,7 @@ const QStringList pageSizes = map<QPageSize::PageSizeId, QString>(pageSizeIds, [
const QStringList pageSizesWithDimensions;
-QString getDbPath(const QString &startWith)
+QString getDbPath(bool newFileMode, const QString &startWith)
{
QString dir = startWith;
if (dir.isNull())
@@ -48,8 +48,15 @@ QString getDbPath(const QString &startWith)
});
QFileDialog dialog(nullptr, QObject::tr("Select database file"), dir, QString());
- dialog.setAcceptMode(QFileDialog::AcceptOpen);
+ dialog.setAcceptMode(newFileMode ? QFileDialog::AcceptSave : QFileDialog::AcceptOpen);
+
+ /* As we don't actually overwrite a selected existing database file, switch off the
+ * overwrite warning.
+ * FIXME: QFileDialog::DontConfirmOverwrite does not work on MacOS native dialogs.
+ * Probably some better UX is needed.
+ */
dialog.setOption(QFileDialog::DontConfirmOverwrite, true);
+
dialog.setLabelText(QFileDialog::Accept, QObject::tr("Select"));
dialog.setLabelText(QFileDialog::FileType, QObject::tr("File type"));
dialog.setNameFilters(filters);
@@ -97,6 +104,11 @@ void setValidStateTooltip(QWidget* widget, const QString& tip)
INDICATOR(widget)->setVisible(widget->isEnabled(), tip);
}
+bool isValidStateIndicatorVisible(QWidget* widget)
+{
+ return EXISTS_INDICATOR(widget) && INDICATOR(widget)->isVisible();
+}
+
QString convertPageSize(QPageSize::PageSizeId size)
{
return QPageSize::name(size);
diff --git a/SQLiteStudio3/guiSQLiteStudio/uiutils.h b/SQLiteStudio3/guiSQLiteStudio/uiutils.h
index 324ed9e..c08cb0b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/uiutils.h
+++ b/SQLiteStudio3/guiSQLiteStudio/uiutils.h
@@ -8,12 +8,13 @@
class QWidget;
class QToolBar;
-GUI_API_EXPORT QString getDbPath(const QString& startWith = QString());
+GUI_API_EXPORT QString getDbPath(bool newFileMode, const QString& startWith = QString());
GUI_API_EXPORT void setValidState(QWidget* widget, bool valid, const QString& message = QString());
GUI_API_EXPORT void setValidStateWihtTooltip(QWidget* widget, const QString& tooltip, bool valid, const QString& message = QString());
GUI_API_EXPORT void setValidStateWarning(QWidget* widget, const QString& warning);
GUI_API_EXPORT void setValidStateInfo(QWidget* widget, const QString& info);
GUI_API_EXPORT void setValidStateTooltip(QWidget* widget, const QString& tip);
+GUI_API_EXPORT bool isValidStateIndicatorVisible(QWidget* widget);
GUI_API_EXPORT const QStringList& getAllPageSizes();
GUI_API_EXPORT QString convertPageSize(QPageSize::PageSizeId size);
GUI_API_EXPORT QPageSize convertPageSize(const QString& size);
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp
index df72db2..6624bc5 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp
@@ -105,14 +105,14 @@ void CollationsEditor::init()
connect(ui->nameEdit, SIGNAL(textChanged(QString)), this, SLOT(updateModified()));
connect(ui->allDatabasesRadio, SIGNAL(clicked()), this, SLOT(updateModified()));
connect(ui->selectedDatabasesRadio, SIGNAL(clicked()), this, SLOT(updateModified()));
+ connect(ui->functionBasedRadio, SIGNAL(clicked()), this, SLOT(updateModified()));
+ connect(ui->extensionBasedRadio, SIGNAL(clicked()), this, SLOT(updateModified()));
connect(ui->langCombo, SIGNAL(currentTextChanged(QString)), this, SLOT(updateModified()));
connect(dbListModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateModified()));
connect(CFG_UI.Fonts.SqlEditor, SIGNAL(changed(QVariant)), this, SLOT(changeFont(QVariant)));
- // Language plugins
- for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins<ScriptingPlugin>())
- ui->langCombo->addItem(plugin->getLanguage());
+ updateLangCombo();
// Syntax highlighting plugins
for (SyntaxHighlighterPlugin* plugin : PLUGINS->getLoadedPlugins<SyntaxHighlighterPlugin>())
@@ -130,9 +130,16 @@ int CollationsEditor::getCurrentCollationRow() const
return idxList.first().row();
}
+CollationManager::CollationType CollationsEditor::getCurrentType() const
+{
+ return ui->extensionBasedRadio->isChecked() ? CollationManager::CollationType::EXTENSION_BASED
+ : CollationManager::CollationType::FUNCTION_BASED;
+}
+
void CollationsEditor::collationDeselected(int row)
{
model->setName(row, ui->nameEdit->text());
+ model->setType(row, getCurrentType());
model->setLang(row, ui->langCombo->currentText());
model->setAllDatabases(row, ui->allDatabasesRadio->isChecked());
model->setCode(row, ui->codeEdit->toPlainText());
@@ -149,6 +156,9 @@ void CollationsEditor::collationSelected(int row)
updatesForSelection = true;
ui->nameEdit->setText(model->getName(row));
ui->codeEdit->setPlainText(model->getCode(row));
+ ui->functionBasedRadio->setChecked(model->getType(row) == CollationManager::CollationType::FUNCTION_BASED);
+ ui->extensionBasedRadio->setChecked(model->getType(row) == CollationManager::CollationType::EXTENSION_BASED);
+ updateLangCombo();
ui->langCombo->setCurrentText(model->getLang(row));
// Databases
@@ -238,7 +248,7 @@ void CollationsEditor::newCollation()
CollationManager::CollationPtr coll = CollationManager::CollationPtr::create();
coll->name = generateUniqueName("collation", model->getCollationNames());
-
+ coll->type = getCurrentType();
if (ui->langCombo->currentIndex() > -1)
coll->lang = ui->langCombo->currentText();
@@ -287,6 +297,8 @@ void CollationsEditor::updateCurrentCollationState()
bool nameOk = model->isAllowedName(row, name) && !name.trimmed().isEmpty();
setValidState(ui->nameEdit, nameOk, tr("Enter a non-empty, unique name of the collation."));
+ updateLangCombo();
+
bool langOk = ui->langCombo->currentIndex() >= 0;
ui->codeGroup->setEnabled(langOk);
ui->databasesGroup->setEnabled(langOk);
@@ -296,7 +308,16 @@ void CollationsEditor::updateCurrentCollationState()
setValidState(ui->langCombo, langOk, tr("Pick the implementation language."));
bool codeOk = !ui->codeEdit->toPlainText().trimmed().isEmpty();
- setValidState(ui->codeEdit, codeOk, tr("Enter a non-empty implementation code."));
+ if (ui->extensionBasedRadio->isChecked())
+ {
+ ui->codeGroup->setTitle(tr("Registration code"));
+ setValidState(ui->codeEdit, codeOk, tr("Enter a non-empty registration code."));
+ }
+ else
+ {
+ ui->codeGroup->setTitle(tr("Implementation code"));
+ setValidState(ui->codeEdit, codeOk, tr("Enter a non-empty implementation code."));
+ }
// Syntax highlighter
QString lang = ui->langCombo->currentText();
@@ -343,6 +364,34 @@ void CollationsEditor::collationSelected(const QItemSelection& selected, const Q
}
}
+void CollationsEditor::updateLangCombo()
+{
+ QComboBox *combo = ui->langCombo;
+ bool alreadyInternalUpdate = updatesForSelection;
+ updatesForSelection = true;
+ if (ui->extensionBasedRadio->isChecked())
+ {
+ if (combo->isEnabled())
+ {
+ combo->setEnabled(false);
+ combo->clear();
+ combo->addItem("SQL");
+ combo->setCurrentIndex(0);
+ }
+ }
+ else
+ {
+ if (!combo->isEnabled())
+ {
+ combo->clear();
+ for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins<ScriptingPlugin>())
+ combo->addItem(plugin->getLanguage());
+ combo->setEnabled(true);
+ }
+ }
+ updatesForSelection = alreadyInternalUpdate;
+}
+
void CollationsEditor::updateModified()
{
if (updatesForSelection)
@@ -353,11 +402,12 @@ void CollationsEditor::updateModified()
{
bool nameDiff = model->getName(row) != ui->nameEdit->text();
bool codeDiff = model->getCode(row) != ui->codeEdit->toPlainText();
+ bool typeDiff = model->getType(row) != getCurrentType();
bool langDiff = model->getLang(row) != ui->langCombo->currentText();
bool allDatabasesDiff = model->getAllDatabases(row) != ui->allDatabasesRadio->isChecked();
bool dbDiff = toSet(getCurrentDatabases()) != toSet(model->getDatabases(row)); // QSet to ignore order
- currentModified = (nameDiff || codeDiff || langDiff || allDatabasesDiff || dbDiff);
+ currentModified = (nameDiff || codeDiff || typeDiff || langDiff || allDatabasesDiff || dbDiff);
}
updateCurrentCollationState();
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h
index 61c9165..7f61a82 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h
@@ -3,6 +3,7 @@
#include "mdichild.h"
#include "common/extactioncontainer.h"
+#include "services/collationmanager.h"
#include <QItemSelection>
#include <QModelIndex>
#include <QWidget>
@@ -61,12 +62,14 @@ class GUI_API_EXPORT CollationsEditor : public MdiChild
private:
void init();
int getCurrentCollationRow() const;
+ CollationManager::CollationType getCurrentType() const;
void collationDeselected(int row);
void collationSelected(int row);
void clearEdits();
void selectCollation(int row);
QStringList getCurrentDatabases() const;
void setFont(const QFont& font);
+ void updateLangCombo();
Ui::CollationsEditor *ui = nullptr;
CollationsEditorModel* model = nullptr;
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui
index 454c12a..123c2ba 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui
@@ -203,13 +203,38 @@
<widget class="QLineEdit" name="nameEdit"/>
</item>
<item row="0" column="1">
+ <widget class="QLabel" name="typeLabel">
+ <property name="text">
+ <string>Collation type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <widget class="QRadioButton" name="functionBasedRadio">
+ <property name="text">
+ <string>Function-based</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="extensionBasedRadio">
+ <property name="text">
+ <string>Extension-based</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="2">
<widget class="QLabel" name="langLabel">
<property name="text">
<string>Implementation language:</string>
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item row="1" column="2">
<widget class="QComboBox" name="langCombo"/>
</item>
</layout>
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp
index f04e023..0587d76 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp
@@ -1,6 +1,7 @@
#include "collationseditormodel.h"
#include "common/unused.h"
#include "common/strhash.h"
+#include "iconmanager.h"
#include "services/pluginmanager.h"
#include "plugins/scriptingplugin.h"
#include "icon.h"
@@ -69,6 +70,16 @@ QString CollationsEditorModel::getName(int row) const
GETTER(collationList[row]->data->name, QString());
}
+void CollationsEditorModel::setType(int row, CollationManager::CollationType type)
+{
+ SETTER(collationList[row]->data->type, type);
+}
+
+CollationManager::CollationType CollationsEditorModel::getType(int row) const
+{
+ GETTER(collationList[row]->data->type, CollationManager::CollationType::FUNCTION_BASED);
+}
+
void CollationsEditorModel::setLang(int row, const QString& lang)
{
SETTER(collationList[row]->data->lang, lang);
@@ -248,13 +259,17 @@ QVariant CollationsEditorModel::data(const QModelIndex& index, int role) const
if (role == Qt::DisplayRole)
return collationList[index.row()]->data->name;
- if (role == Qt::DecorationRole && langToIcon.contains(collationList[index.row()]->data->lang))
+ if (role == Qt::DecorationRole)
{
- QIcon icon = langToIcon[collationList[index.row()]->data->lang];
- if (!collationList[index.row()]->valid)
- icon = Icon::merge(icon, Icon::ERROR);
-
- return icon;
+ auto coll = collationList[index.row()]->data;
+ bool isExtension = coll->type == CollationManager::CollationType::EXTENSION_BASED;
+ if (isExtension || langToIcon.contains(coll->lang))
+ {
+ QIcon icon = isExtension ? ICONS.EXTENSION : langToIcon[coll->lang];
+ if (!collationList[index.row()]->valid)
+ icon = Icon::merge(icon, Icon::ERROR);
+ return icon;
+ }
}
return QVariant();
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h
index 46f7ab5..47b8b08 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h
@@ -21,6 +21,8 @@ class GUI_API_EXPORT CollationsEditorModel : public QAbstractListModel
void setModified(int row, bool modified);
void setName(int row, const QString& name);
QString getName(int row) const;
+ void setType(int row, CollationManager::CollationType type);
+ CollationManager::CollationType getType(int row) const;
void setLang(int row, const QString& lang);
QString getLang(int row) const;
void setAllDatabases(int row, bool allDatabases);
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp
index 23cb651..aa59bb0 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp
@@ -211,7 +211,7 @@ QAction* EditorWindow::getAction(EditorWindow::Action action)
return ExtActionContainer::getAction(action);
}
-QString EditorWindow::getQueryToExecute(bool doSelectCurrentQuery, QueryExecMode querySelectionMode)
+QString EditorWindow::getQueryToExecute(QueryExecMode querySelectionMode)
{
QString sql;
if (ui->sqlEdit->textCursor().hasSelection())
@@ -228,9 +228,8 @@ QString EditorWindow::getQueryToExecute(bool doSelectCurrentQuery, QueryExecMode
ui->sqlEdit->saveSelection();
selectCurrentQuery(true);
sql = ui->sqlEdit->textCursor().selectedText();
+ ui->sqlEdit->restoreSelection();
fixTextCursorSelectedText(sql);
- if (!doSelectCurrentQuery)
- ui->sqlEdit->restoreSelection();
}
else
{
@@ -463,7 +462,7 @@ void EditorWindow::updateShortcutTips()
void EditorWindow::execQuery(bool explain, QueryExecMode querySelectionMode)
{
- QString sql = getQueryToExecute(true, querySelectionMode);
+ QString sql = getQueryToExecute(querySelectionMode);
QHash<QString, QVariant> bindParams;
bool proceed = processBindParams(sql, bindParams);
if (!proceed)
@@ -474,7 +473,7 @@ void EditorWindow::execQuery(bool explain, QueryExecMode querySelectionMode)
resultsModel->setQuery(sql);
resultsModel->setParams(bindParams);
resultsModel->setQueryCountLimitForSmartMode(queryLimitForSmartExecution);
- ui->dataView->refreshData();
+ ui->dataView->refreshData(false);
updateState();
if (resultsDisplayMode == ResultsDisplayMode::SEPARATE_TAB)
@@ -741,7 +740,7 @@ void EditorWindow::createViewFromQuery()
return;
}
- QString sql = getQueryToExecute(true);
+ QString sql = getQueryToExecute();
DbObjectDialogs dialogs(getCurrentDb());
dialogs.addView(sql);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h
index 977784e..0ca2cdf 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h
@@ -100,7 +100,7 @@ class GUI_API_EXPORT EditorWindow : public MdiChild
QSize sizeHint() const;
QAction* getAction(Action action);
- QString getQueryToExecute(bool doSelectCurrentQuery = false, QueryExecMode querySelectionMode = DEFAULT);
+ QString getQueryToExecute(QueryExecMode querySelectionMode = DEFAULT);
bool setCurrentDb(Db* db);
void setContents(const QString& sql);
QString getContents() const;
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp
index 4d964c8..e349525 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp
@@ -170,9 +170,12 @@ int FunctionsEditor::getCurrentFunctionRow() const
void FunctionsEditor::functionDeselected(int row)
{
model->setName(row, ui->nameEdit->text());
+ model->setUndefinedArgs(row, ui->undefArgsCheck->isChecked());
+ if (!ui->undefArgsCheck->isChecked())
+ model->setArguments(row, getCurrentArgList());
+
model->setLang(row, ui->langCombo->currentText());
model->setType(row, getCurrentFunctionType());
- model->setUndefinedArgs(row, ui->undefArgsCheck->isChecked());
model->setAllDatabases(row, ui->allDatabasesRadio->isChecked());
model->setCode(row, ui->mainCodeEdit->toPlainText());
model->setDeterministic(row, ui->deterministicCheck->isChecked());
@@ -189,9 +192,6 @@ void FunctionsEditor::functionDeselected(int row)
model->setFinalCode(row, QString());
}
- if (!ui->undefArgsCheck->isChecked())
- model->setArguments(row, getCurrentArgList());
-
if (ui->selDatabasesRadio->isChecked())
model->setDatabases(row, getCurrentDatabases());
@@ -416,8 +416,10 @@ void FunctionsEditor::updateCurrentFunctionState()
}
QString name = ui->nameEdit->text();
- bool nameOk = model->isAllowedName(row, name) && !name.trimmed().isEmpty();
- setValidState(ui->nameEdit, nameOk, tr("Enter a non-empty, unique name of the function."));
+ QStringList argList = getCurrentArgList();
+ bool undefArgs = ui->undefArgsCheck->isChecked();
+ bool nameOk = model->isAllowedName(row, name, argList, undefArgs) && !name.trimmed().isEmpty();
+ setValidState(ui->nameEdit, nameOk, tr("Enter a unique, non-empty function name. Duplicate names are allowed if the number of input parameters differs."));
bool langOk = ui->langCombo->currentIndex() >= 0;
ui->initCodeGroup->setEnabled(langOk);
@@ -488,8 +490,8 @@ void FunctionsEditor::updateCurrentFunctionState()
currentHighlighterLang = lang;
}
- updateArgsState();
- model->setValid(row, langOk && codeOk && finalCodeOk && nameOk);
+ bool argsOk = updateArgsState();
+ model->setValid(row, langOk && codeOk && finalCodeOk && nameOk && argsOk);
updateState();
}
@@ -576,7 +578,7 @@ void FunctionsEditor::moveFunctionArgDown()
ui->argsList->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::Clear|QItemSelectionModel::SelectCurrent);
}
-void FunctionsEditor::updateArgsState()
+bool FunctionsEditor::updateArgsState()
{
bool argsEnabled = !ui->undefArgsCheck->isChecked();
QModelIndexList indexes = ui->argsList->selectionModel()->selectedIndexes();
@@ -596,6 +598,32 @@ void FunctionsEditor::updateArgsState()
actionMap[ARG_MOVE_UP]->setEnabled(argsEnabled && canMoveUp);
actionMap[ARG_MOVE_DOWN]->setEnabled(argsEnabled && canMoveDown);
ui->argsList->setEnabled(argsEnabled);
+
+ if (argsEnabled)
+ {
+ bool argsOk = true;
+ QSet<QString> usedNames;
+ for (int rowIdx = 0; rowIdx < ui->argsList->model()->rowCount(); rowIdx++)
+ {
+ QListWidgetItem* item = ui->argsList->item(rowIdx);
+ QString argName = item->text().toLower();
+ if (argName.isEmpty())
+ {
+ argsOk = false;
+ break;
+ }
+ if (usedNames.contains(argName))
+ {
+ argsOk = false;
+ break;
+ }
+ usedNames << argName;
+ }
+ setValidState(ui->argsList, argsOk, tr("Function argument cannot be empty and it cannot have duplicated name."));
+ return argsOk;
+ }
+ else
+ return true;
}
void FunctionsEditor::applyFilter(const QString& value)
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.h b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.h
index d3fcf12..d513234 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.h
@@ -105,7 +105,7 @@ class GUI_API_EXPORT FunctionsEditor : public MdiChild
void delFunctionArg();
void moveFunctionArgUp();
void moveFunctionArgDown();
- void updateArgsState();
+ bool updateArgsState();
void applyFilter(const QString& value);
void help();
void changeFont(const QVariant& font);
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp
index 46ae8d9..13ec34f 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp
@@ -266,16 +266,17 @@ QStringList FunctionsEditorModel::getFunctionNames() const
void FunctionsEditorModel::validateNames()
{
- StrHash<QList<int>> counter;
+ QHash<UniqueFunctionName, QList<int>> counter;
int row = 0;
for (Function*& func : functionList)
{
func->valid &= true;
- counter[func->data.name] << row++;
+ UniqueFunctionName uniqueName = func->toUniqueName();
+ counter[uniqueName] << row++;
}
- QHashIterator<QString,QList<int>> cntIt = counter.iterator();
+ QHashIterator<UniqueFunctionName, QList<int>> cntIt(counter);
while (cntIt.hasNext())
{
cntIt.next();
@@ -294,11 +295,18 @@ void FunctionsEditorModel::validateNames()
}
}
-bool FunctionsEditorModel::isAllowedName(int rowToSkip, const QString& nameToValidate)
+bool FunctionsEditorModel::isAllowedName(int rowToSkip, const QString& nameToValidate, const QStringList& argList, bool undefinedArgs)
{
- QStringList names = getFunctionNames();
+ QList<UniqueFunctionName> names = getUniqueFunctionNames();
names.removeAt(rowToSkip);
- return !names.contains(nameToValidate, Qt::CaseInsensitive);
+
+ UniqueFunctionName validatedName;
+ validatedName.name = nameToValidate.toLower();
+ validatedName.undefArg = undefinedArgs;
+ if (!undefinedArgs)
+ validatedName.arguments = argList;
+
+ return !names.contains(validatedName);
}
int FunctionsEditorModel::rowCount(const QModelIndex& parent) const
@@ -347,6 +355,15 @@ void FunctionsEditorModel::emitDataChanged(int row)
emit dataChanged(idx, idx);
}
+QList<FunctionsEditorModel::UniqueFunctionName> FunctionsEditorModel::getUniqueFunctionNames() const
+{
+ QList<UniqueFunctionName> names;
+ for (Function* func : functionList)
+ names << func->toUniqueName();
+
+ return names;
+}
+
FunctionsEditorModel::Function::Function()
{
}
@@ -356,3 +373,29 @@ FunctionsEditorModel::Function::Function(FunctionManager::ScriptFunction* other)
data = FunctionManager::ScriptFunction(*other);
originalName = data.name;
}
+
+FunctionsEditorModel::UniqueFunctionName FunctionsEditorModel::Function::toUniqueName() const
+{
+ UniqueFunctionName uniqName;
+ uniqName.name = data.name.toLower();
+ uniqName.undefArg = data.undefinedArgs;
+ if (!data.undefinedArgs)
+ uniqName.arguments = data.arguments;
+
+ return uniqName;
+}
+
+int FunctionsEditorModel::UniqueFunctionName::argCount() const
+{
+ return undefArg ? -1 : arguments.size();
+}
+
+bool FunctionsEditorModel::UniqueFunctionName::operator==(const UniqueFunctionName &other) const
+{
+ return name == other.name && argCount() == other.argCount();
+}
+
+int qHash(FunctionsEditorModel::UniqueFunctionName fnName)
+{
+ return qHash(fnName.name) ^ fnName.argCount();
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.h b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.h
index 7caf06c..2f90bcc 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.h
@@ -60,17 +60,28 @@ class GUI_API_EXPORT FunctionsEditorModel : public QAbstractListModel
QList<FunctionManager::ScriptFunction*> generateFunctions() const;
QStringList getFunctionNames() const;
void validateNames();
- bool isAllowedName(int rowToSkip, const QString& nameToValidate);
+ bool isAllowedName(int rowToSkip, const QString& nameToValidate, const QStringList &argList, bool undefinedArgs);
bool isValidRowIndex(int row) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role) const;
private:
+ struct UniqueFunctionName
+ {
+ QString name;
+ QStringList arguments;
+ bool undefArg;
+
+ int argCount() const;
+ bool operator==(const UniqueFunctionName& other) const;
+ };
+
struct Function
{
Function();
Function(FunctionManager::ScriptFunction* other);
+ UniqueFunctionName toUniqueName() const;
FunctionManager::ScriptFunction data;
bool modified = false;
@@ -80,6 +91,9 @@ class GUI_API_EXPORT FunctionsEditorModel : public QAbstractListModel
void init();
void emitDataChanged(int row);
+ QList<UniqueFunctionName> getUniqueFunctionNames() const;
+
+ friend int qHash(FunctionsEditorModel::UniqueFunctionName fnName);
QList<Function*> functionList;
@@ -96,4 +110,6 @@ class GUI_API_EXPORT FunctionsEditorModel : public QAbstractListModel
bool listModified = false;
};
+int qHash(FunctionsEditorModel::UniqueFunctionName fnName);
+
#endif // FUNCTIONSEDITORMODEL_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp
index f8dd621..66e6682 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp
@@ -123,6 +123,7 @@ void SqliteExtensionEditor::init()
connect(dbListModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateModified()));
probingDb = DBLIST->createInMemDb(true);
+
if (!probingDb->openQuiet())
qWarning() << "Could not open in-memory dtabase for Extension manager window. Probing files will be impossible.";
@@ -308,6 +309,7 @@ void SqliteExtensionEditor::rollback()
if (model->isValidRowIndex(selectedBefore))
selectExtension(selectedBefore);
+ initStateForAll();
updateState();
}
@@ -337,7 +339,7 @@ void SqliteExtensionEditor::deleteExtension()
void SqliteExtensionEditor::updateState()
{
bool modified = model->isModified() || currentModified;
- bool valid = model->isValid() && validateCurrentExtension();
+ bool valid = model->isValid() && (getCurrentExtensionRow() == -1 || validateCurrentExtension());
actionMap[COMMIT]->setEnabled(modified && valid);
actionMap[ROLLBACK]->setEnabled(modified);
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
index 86f48bf..b42848a 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
@@ -865,6 +865,9 @@ void TableWindow::changesSuccessfullyCommitted()
}
}
}
+
+ if (ui->tabWidget->currentIndex() == getDataTabIdx())
+ ui->dataView->refreshData();
}
void TableWindow::changesFailedToCommit(int errorCode, const QString& errorText)
@@ -1047,7 +1050,7 @@ bool TableWindow::validate(bool skipWarning)
QStringList nonStrictColumns;
for (SqliteCreateTable::Column* column : createTable->columns)
{
- if (DataType::isStrict(column->type->name))
+ if (DataType::isStrict(column->type ? column->type->name : QString()))
continue;
nonStrictColumns << column->name;
@@ -1310,7 +1313,7 @@ void TableWindow::importTable()
ImportDialog dialog(this);
dialog.setDbAndTable(db, table);
if (dialog.exec() == QDialog::Accepted && dataLoaded)
- ui->dataView->refreshData();
+ ui->dataView->refreshData(false);
}
void TableWindow::populateTable()
@@ -1318,7 +1321,7 @@ void TableWindow::populateTable()
PopulateDialog dialog(this);
dialog.setDbAndTable(db, table);
if (dialog.exec() == QDialog::Accepted && dataLoaded)
- ui->dataView->refreshData();
+ ui->dataView->refreshData(false);
}
void TableWindow::createSimilarTable()
@@ -1342,15 +1345,16 @@ void TableWindow::tabChanged(int newTab)
"Do you want to commit the structure, or do you want to go back to the structure tab?"),
tr("Go back to structure tab"), tr("Commit modifications and browse data."));
- ui->tabWidget->setCurrentIndex(0);
if (res == 1)
commitStructure(true);
+ else
+ focusStructureTab();
return;
}
if (!dataLoaded)
- ui->dataView->refreshData();
+ ui->dataView->refreshData(false);
}
}
@@ -1393,8 +1397,11 @@ void TableWindow::strictChanged()
{
for (SqliteCreateTable::Column* column : createTable->columns)
{
- column->type->precision = QVariant();
- column->type->scale = QVariant();
+ if (column->type)
+ {
+ column->type->precision = QVariant();
+ column->type->scale = QVariant();
+ }
}
}
@@ -1644,6 +1651,16 @@ void TableWindow::delColumn(const QString& columnName)
delColumn(colIdx);
}
+void TableWindow::focusStructureTab()
+{
+ ui->tabWidget->setCurrentIndex(getStructureTabIdx());
+}
+
+void TableWindow::focusDataTab()
+{
+ ui->tabWidget->setCurrentIndex(getDataTabIdx());
+}
+
void TableWindow::updateTabsOrder()
{
tabsMoving = true;
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
index e71162d..dda317a 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
@@ -255,6 +255,8 @@ class GUI_API_EXPORT TableWindow : public MdiChild
void addColumn();
void editColumn(const QString& columnName);
void delColumn(const QString& columnName);
+ void focusStructureTab();
+ void focusDataTab();
signals:
void modifyStatusChanged();
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
index 44025e5..73575c4 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
@@ -299,7 +299,7 @@ void ViewWindow::initView()
if (existingView)
{
dataModel->setDb(db);
- dataModel->setQuery(originalCreateView->select->detokenize());
+ dataModel->setQuery(originalCreateView->equivalentSelectTokens().detokenize());
dataModel->setDatabaseAndView(database, view);
ui->dbCombo->setDisabled(true);
}
@@ -619,7 +619,7 @@ void ViewWindow::tabChanged(int tabIdx)
"Do you want to commit the structure, or do you want to go back to the structure tab?"),
tr("Go back to structure tab"), tr("Commit modifications and browse data."));
- ui->tabWidget->setCurrentIndex(0);
+ ui->tabWidget->setCurrentIndex(CFG_UI.General.DataTabAsFirstInViews.get() ? 1 : 0);
if (res == 1)
commitView(true);
@@ -627,7 +627,7 @@ void ViewWindow::tabChanged(int tabIdx)
}
if (!dataLoaded)
- ui->dataView->refreshData();
+ ui->dataView->refreshData(false);
return;
}