aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/guiSQLiteStudio
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2021-12-17 07:06:30 -0500
committerLibravatarUnit 193 <unit193@unit193.net>2021-12-17 07:06:30 -0500
commit1fdc150116cad39aae5c5da407c3312b47a59e3a (patch)
tree123c79a4d7ad2d45781ba03ce939f7539fb428d8 /SQLiteStudio3/guiSQLiteStudio
parentfeda8a7db8d1d7c5439aa8f8feef7cc0dd2b59a0 (diff)
New upstream version 3.3.3+dfsg1.upstream/3.3.3+dfsg1
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio')
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/dbcombobox.cpp26
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/dbcombobox.h23
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp9
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/extlineedit.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp169
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h17
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/configmapper.cpp12
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/configmapper.h4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp8
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp227
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.h44
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.ui92
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp23
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.cpp21
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.ui24
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp47
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp162
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h17
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp473
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h45
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp521
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h56
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp56
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h17
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp96
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp268
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dataview.cpp20
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp24
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbobjlistmodel.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp94
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h8
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitemdelegate.cpp6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp56
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/debugconsole.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp101
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h7
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.ui78
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.cpp17
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.h1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp38
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui686
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.h1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/cssdebugdialog.cpp7
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.cpp218
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.h52
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.ui144
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp68
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/errorsconfirmdialog.cpp3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp133
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.h35
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/indexexprcolumndialog.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.cpp59
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.h6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp33
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.h7
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui110
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp30
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp60
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/extendedpalette.h30
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/formmanager.cpp4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro14
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/icon.cpp6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/icon.h4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/iconmanager.h29
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/icons.qrc24
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/act_search.pngbin781 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/brick_folder.pngbin735 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/configure_constraint.pngbin297 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/database_connected.pngbin725 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/database_file.pngbin701 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/database_network.pngbin619 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/directory_with_db.pngbin663 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/disk_small.pngbin0 -> 409 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/function.pngbin372 -> 218 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/generated.pngbin0 -> 736 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/info_balloon.pngbin745 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/lightning_small.pngbin0 -> 372 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/load_full_value.pngbin0 -> 326 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/load_full_values.pngbin0 -> 564 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/open_forum.pngbin1510 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/quit.pngbin0 -> 660 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/tip.pngbin743 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/user.pngbin744 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/img/user_unknown.pngbin614 -> 0 bytes
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp79
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/mainwindow.h26
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/mdiwindow.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp7
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/qhexedit2/qhexedit_p.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.cpp36
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.h3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/searchtextlocator.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp29
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp87
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/sqleditor.h6
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp48
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.h4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/sqlview.cpp5
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/sqlview.h1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/statusfield.cpp73
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/statusfield.h15
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/style.cpp48
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/style.h29
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/taskbar.cpp2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/themetuner.cpp21
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/themetuner.h14
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts584
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts1053
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/uiconfig.h33
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/uiutils.cpp31
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/uiutils.h4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp9
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp28
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.h1
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp59
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp13
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp9
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp10
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp63
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.h4
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp99
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h7
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui15
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp68
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h3
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui25
145 files changed, 4191 insertions, 3253 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp b/SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp
index 35e99c8..7e115ed 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/common/datawidgetmapper.cpp
@@ -122,7 +122,7 @@ void DataWidgetMapper::submit()
idx = model->index(currentIndex, entry->columnIndex);
value = entry->widget->property(entry->propertyName.toLatin1().constData());
- qDebug() << "copying from form view for idx" << idx << "value:" << value;
+ //qDebug() << "copying from form view for idx" << idx << "value:" << value;
model->setData(idx, value, Qt::EditRole);
}
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/dbcombobox.cpp b/SQLiteStudio3/guiSQLiteStudio/common/dbcombobox.cpp
new file mode 100644
index 0000000..303a37a
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/common/dbcombobox.cpp
@@ -0,0 +1,26 @@
+#include "dbcombobox.h"
+#include "dblistmodel.h"
+#include "db/db.h"
+
+DbComboBox::DbComboBox(QWidget* parent) : QComboBox(parent)
+{
+ dbComboModel = new DbListModel(this);
+ dbComboModel->setCombo(this);
+ setModel(dbComboModel);
+ setEditable(false);
+}
+
+DbListModel* DbComboBox::getModel() const
+{
+ return dbComboModel;
+}
+
+void DbComboBox::setCurrentDb(Db* db)
+{
+ setCurrentIndex(dbComboModel->getIndexForDb(db));
+}
+
+Db* DbComboBox::currentDb() const
+{
+ return dbComboModel->getDb(currentIndex());
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/dbcombobox.h b/SQLiteStudio3/guiSQLiteStudio/common/dbcombobox.h
new file mode 100644
index 0000000..39814a6
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/common/dbcombobox.h
@@ -0,0 +1,23 @@
+#ifndef DBCOMBOBOX_H
+#define DBCOMBOBOX_H
+
+#include <QComboBox>
+
+class QComboBox;
+class DbListModel;
+class Db;
+
+class DbComboBox : public QComboBox
+{
+ public:
+ explicit DbComboBox(QWidget* parent = nullptr);
+
+ DbListModel* getModel() const;
+ void setCurrentDb(Db* db);
+ Db* currentDb() const;
+
+ private:
+ DbListModel* dbComboModel = nullptr;
+};
+
+#endif // DBCOMBOBOX_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp b/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp
index c67cc73..1203582 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/common/extactioncontainer.cpp
@@ -15,8 +15,13 @@ ExtActionContainer::ExtActionContainer()
{
actionIdMapper = new QSignalMapper();
- // We need to explicitly cast QSignalMapper::mapped to tell which overloaded version of function we want
- QObject::connect(actionIdMapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped),
+ QObject::connect(actionIdMapper,
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ &QSignalMapper::mappedInt,
+#else
+ // We need to explicitly cast QSignalMapper::mapped to tell which overloaded version of function we want
+ static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped),
+#endif
[=](int action) {refreshShortcut(action);});
instances << this;
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/extlineedit.cpp b/SQLiteStudio3/guiSQLiteStudio/common/extlineedit.cpp
index ccbc586..2ac6531 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/extlineedit.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/common/extlineedit.cpp
@@ -99,7 +99,7 @@ void ExtLineEdit::handleTextChanged()
return;
// Text width
- int newWidth = fontMetrics().width(txt);
+ int newWidth = fontMetrics().horizontalAdvance(txt);
// Text margins
QMargins margins = textMargins();
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp
index c6823e4..b5b0264 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp
@@ -9,10 +9,10 @@
#include <QEvent>
#include <QHBoxLayout>
#include <QGraphicsDropShadowEffect>
-#include <QSequentialAnimationGroup>
-#include <QPropertyAnimation>
#include <QDebug>
#include <QScrollArea>
+#include <QToolTip>
+#include <QEnterEvent>
QHash<QWidget*,WidgetStateIndicator*> WidgetStateIndicator::instances;
@@ -54,7 +54,6 @@ void WidgetStateIndicator::initEffects()
{
initGlowEffects();
initHighlightingEffects();
- initAnimations();
}
void WidgetStateIndicator::initGlowEffects()
@@ -73,27 +72,6 @@ void WidgetStateIndicator::initHighlightingEffects()
highlightingEffect->setEnabled(false);
}
-void WidgetStateIndicator::initAnimations()
-{
- animation = new QSequentialAnimationGroup(this);
- animation->setLoopCount(-1);
-
- // Animation of glow efect
- QPropertyAnimation* varAnim = new QPropertyAnimation(glowEffect, "blurRadius");
- varAnim->setStartValue(3.0);
- varAnim->setEndValue(14.0);
- varAnim->setEasingCurve(QEasingCurve::InOutCubic);
- varAnim->setDuration(300);
- animation->addAnimation(varAnim);
-
- varAnim = new QPropertyAnimation(glowEffect, "blurRadius");
- varAnim->setStartValue(14.0);
- varAnim->setEndValue(3.0);
- varAnim->setEasingCurve(QEasingCurve::InOutCubic);
- varAnim->setDuration(300);
- animation->addAnimation(varAnim);
-}
-
void WidgetStateIndicator::initPositionMode()
{
if (dynamic_cast<QGroupBox*>(widget))
@@ -106,8 +84,15 @@ void WidgetStateIndicator::initPositionMode()
void WidgetStateIndicator::finalInit()
{
- label->setFixedSize(label->pixmap()->size());
- labelParent->setFixedSize(label->pixmap()->size());
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ QPixmap pixmap = label->pixmap(Qt::ReturnByValue);
+ label->setFixedSize(pixmap.size());
+ labelParent->setFixedSize(pixmap.size());
+#else
+ const QPixmap* pixmap = label->pixmap();
+ label->setFixedSize(pixmap->size());
+ labelParent->setFixedSize(pixmap->size());
+#endif
widgetVisible = widget->isVisible();
labelParent->setVisible(false);
}
@@ -120,7 +105,6 @@ void WidgetStateIndicator::setMessage(const QString& msg)
else
message = paraTpl.arg(msg);
- label->setToolTip(message);
if (!msg.isNull())
label->setCursor(Qt::WhatsThisCursor);
else
@@ -129,7 +113,7 @@ void WidgetStateIndicator::setMessage(const QString& msg)
void WidgetStateIndicator::clearMessage()
{
- message = QString::null;
+ message = QString();
label->setToolTip(message);
label->unsetCursor();
}
@@ -151,13 +135,10 @@ void WidgetStateIndicator::setMode(WidgetStateIndicator::Mode mode)
updateMode();
}
-void WidgetStateIndicator::show(const QString& msg, bool animated)
+void WidgetStateIndicator::show(const QString& msg)
{
visibilityRequested = true;
setMessage(msg);
- if (animated && animation->state() != QAbstractAnimation::Running)
- animation->start();
-
updateVisibility();
}
@@ -165,9 +146,6 @@ void WidgetStateIndicator::hide()
{
visibilityRequested = false;
clearMessage();
- if (animation->state() == QAbstractAnimation::Running)
- animation->stop();
-
updateVisibility();
}
@@ -186,28 +164,28 @@ void WidgetStateIndicator::release()
deleteLater();
}
-void WidgetStateIndicator::info(const QString& msg, bool animated)
+void WidgetStateIndicator::info(const QString& msg)
{
setMode(Mode::INFO);
- show(msg, animated);
+ show(msg);
}
-void WidgetStateIndicator::warn(const QString& msg, bool animated)
+void WidgetStateIndicator::warn(const QString& msg)
{
setMode(Mode::WARNING);
- show(msg, animated);
+ show(msg);
}
-void WidgetStateIndicator::error(const QString& msg, bool animated)
+void WidgetStateIndicator::error(const QString& msg)
{
setMode(Mode::ERROR);
- show(msg, animated);
+ show(msg);
}
-void WidgetStateIndicator::hint(const QString& msg, bool animated)
+void WidgetStateIndicator::hint(const QString& msg)
{
setMode(Mode::HINT);
- show(msg, animated);
+ show(msg);
}
bool WidgetStateIndicator::exists(QWidget* widget)
@@ -226,47 +204,11 @@ WidgetStateIndicator* WidgetStateIndicator::getInstance(QWidget* widget)
bool WidgetStateIndicator::eventFilter(QObject* obj, QEvent* ev)
{
if (obj == widget)
- {
- switch (ev->type())
- {
- case QEvent::Move:
- case QEvent::Resize:
- case QEvent::Scroll:
- updatePosition();
- break;
- case QEvent::Show:
- widgetVisible = true;
- updateVisibility();
- break;
- case QEvent::Hide:
- widgetVisible = false;
- updateVisibility();
- break;
- case QEvent::EnabledChange:
- updateVisibility();
- break;
- default:
- break;
- }
- }
+ return eventFilterFromWidget(ev);
else if (obj == windowParent)
- {
- switch (ev->type())
- {
- case QEvent::ParentChange:
- detectWindowParent();
- break;
- default:
- break;
- }
- }
+ return eventFilterFromParentWidget(ev);
else if (obj == label)
- {
- if (ev->type() == QEvent::Enter)
- highlightingEffect->setEnabled(true);
- else if (ev->type() == QEvent::Leave)
- highlightingEffect->setEnabled(false);
- }
+ return eventFilterFromIndicatorLabel(ev);
return false;
}
@@ -328,7 +270,7 @@ void WidgetStateIndicator::updatePositionGroupBox()
QFont font = gb->font();
QFontMetrics fm(font);
QString txt = gb->title();
- QPoint diff(fm.width(txt), 2);
+ QPoint diff(fm.horizontalAdvance(txt), 2);
labelParent->move(xy + diff);
}
@@ -390,6 +332,67 @@ bool WidgetStateIndicator::shouldShow()
return true;
}
+
+bool WidgetStateIndicator::eventFilterFromWidget(QEvent* ev)
+{
+ switch (ev->type())
+ {
+ case QEvent::Move:
+ case QEvent::Resize:
+ case QEvent::Scroll:
+ updatePosition();
+ break;
+ case QEvent::Show:
+ widgetVisible = true;
+ updateVisibility();
+ break;
+ case QEvent::Hide:
+ widgetVisible = false;
+ updateVisibility();
+ break;
+ case QEvent::EnabledChange:
+ updateVisibility();
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool WidgetStateIndicator::eventFilterFromParentWidget(QEvent* ev)
+{
+ switch (ev->type())
+ {
+ case QEvent::ParentChange:
+ detectWindowParent();
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool WidgetStateIndicator::eventFilterFromIndicatorLabel(QEvent* ev)
+{
+ switch (ev->type())
+ {
+ case QEvent::Enter:
+ {
+ highlightingEffect->setEnabled(true);
+ QEnterEvent* e = dynamic_cast<QEnterEvent*>(ev);
+ QToolTip::showText(e->globalPos(), message);
+ break;
+ }
+ case QEvent::Leave:
+ highlightingEffect->setEnabled(false);
+ QToolTip::hideText();
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
WidgetStateIndicator::PositionMode WidgetStateIndicator::getPositionMode() const
{
return positionMode;
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h
index eee49d5..28c6e0b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h
+++ b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.h
@@ -7,7 +7,6 @@
class QLabel;
class QGraphicsDropShadowEffect;
class QGraphicsColorizeEffect;
-class QSequentialAnimationGroup;
class GUI_API_EXPORT WidgetStateIndicator : public QObject
{
@@ -32,14 +31,14 @@ class GUI_API_EXPORT WidgetStateIndicator : public QObject
~WidgetStateIndicator();
void setMode(Mode mode);
- void show(const QString& msg = QString(), bool animated = true);
+ void show(const QString& msg = QString());
void hide();
void setVisible(bool visible, const QString& msg = QString());
void release();
- void info(const QString& msg, bool animated = true);
- void warn(const QString& msg, bool animated = true);
- void error(const QString& msg, bool animated = true);
- void hint(const QString& msg, bool animated = true);
+ void info(const QString& msg);
+ void warn(const QString& msg);
+ void error(const QString& msg);
+ void hint(const QString& msg);
static bool exists(QWidget* widget);
static WidgetStateIndicator* getInstance(QWidget* widget);
@@ -57,7 +56,6 @@ class GUI_API_EXPORT WidgetStateIndicator : public QObject
void initEffects();
void initGlowEffects();
void initHighlightingEffects();
- void initAnimations();
void initPositionMode();
void finalInit();
void setMessage(const QString& msg);
@@ -66,15 +64,18 @@ class GUI_API_EXPORT WidgetStateIndicator : public QObject
QWidget* findParentWindow(QWidget* w);
bool shouldHide();
bool shouldShow();
+ bool eventFilterFromWidget(QEvent *ev);
+ bool eventFilterFromParentWidget(QEvent *ev);
+ bool eventFilterFromIndicatorLabel(QEvent *ev);
QWidget* labelParent = nullptr;
QLabel* label = nullptr;
Mode mode = Mode::ERROR;
QWidget* widget = nullptr;
QString message;
+ QString processedMessage;
QGraphicsColorizeEffect* highlightingEffect = nullptr;
QGraphicsDropShadowEffect* glowEffect = nullptr;
- QSequentialAnimationGroup* animation = nullptr;
bool widgetVisible = false;
bool visibilityRequested = false;
QWidget* windowParent = nullptr;
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp b/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp
index 3268960..7b17ffe 100644
--- a/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completeritemdelegate.cpp
@@ -124,13 +124,13 @@ void CompleterItemDelegate::paintPrefix(QPainter* painter, const QFontMetrics& m
QString value = text + ".";
painter->drawText(QPoint(x, y), value);
- x += metrics.width(value);
+ x += metrics.horizontalAdvance(value);
}
void CompleterItemDelegate::paintValue(QPainter* painter, const QFontMetrics& metrics, int& x, int y, const QString& text) const
{
painter->drawText(QPoint(x, y), text);
- x += metrics.width(text);
+ x += metrics.horizontalAdvance(text);
}
void CompleterItemDelegate::paintLabel(QPainter* painter, int& x, int y, const QString& text, bool emptyValue) const
diff --git a/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp
index 87ad64c..89a0848 100644
--- a/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/completer/completerwindow.cpp
@@ -42,12 +42,12 @@ void CompleterWindow::init()
void CompleterWindow::reset()
{
model->clear();
- ui->status->showMessage(QString::null);
+ ui->status->showMessage(QString());
}
void CompleterWindow::setData(const CompletionHelper::Results& completionResults)
{
- ui->status->showMessage(QString::null);
+ ui->status->showMessage(QString());
model->setData(completionResults.expectedTokens);
filter = completionResults.partialToken;
wrappedFilter = completionResults.wrappedToken;
@@ -89,7 +89,7 @@ void CompleterWindow::shringFilterBy(int chars)
void CompleterWindow::extendFilterBy(const QString& text)
{
- if (filter.isEmpty() && text.size() == 1 && isWrapperChar(text[0], db->getDialect()))
+ if (filter.isEmpty() && text.size() == 1 && isWrapperChar(text[0]))
{
wrappedFilter = true;
updateFilter();
diff --git a/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp b/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp
index f4098bc..b36d985 100644
--- a/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/configmapper.cpp
@@ -309,7 +309,7 @@ void ConfigMapper::applyConfigToWidget(QWidget* widget, const QHash<QString, Cfg
}
widgetToConfigEntry.insert(widget, cfgEntry);
- configEntryToWidgets.insertMulti(cfgEntry, widget);
+ configEntryToWidgets.insert(cfgEntry, widget);
handleSpecialWidgets(widget, allConfigEntries);
@@ -361,7 +361,7 @@ void ConfigMapper::handleConfigComboBox(QWidget* widget, const QHash<QString, Cf
if (realTimeUpdates)
{
- specialConfigEntryToWidgets.insertMulti(key, widget);
+ specialConfigEntryToWidgets.insert(key, widget);
connect(key, SIGNAL(changed(QVariant)), this, SLOT(updateConfigComboModel(QVariant)));
}
}
@@ -544,7 +544,7 @@ void ConfigMapper::handleBoolDependencySettings(const QString& boolDependency, Q
bool value = cfgValue.toBool();
widget->setEnabled(value);
- QWidget* dependWidget = configEntryToWidgets[cfg];
+ QWidget* dependWidget = configEntryToWidgets.value(cfg);
boolDependencyToDependingWidget[dependWidget] = widget;
}
@@ -682,7 +682,7 @@ void ConfigMapper::updateConfigComboModel(const QVariant& value)
if (!specialConfigEntryToWidgets.contains(key))
return;
- QWidget* w = specialConfigEntryToWidgets[key];
+ QWidget* w = specialConfigEntryToWidgets.value(key);
ConfigComboBox* ccb = dynamic_cast<ConfigComboBox*>(w);
if (!w)
return;
@@ -709,7 +709,7 @@ void ConfigMapper::notifiableConfigKeyChanged()
return;
}
- loadToWidget(key, configEntryToWidgets[key]);
+ loadToWidget(key, configEntryToWidgets.value(key));
}
void ConfigMapper::bindToConfig(QWidget* topLevelWidget)
@@ -742,7 +742,7 @@ void ConfigMapper::removeMainCfgEntry(CfgMain* cfgMain)
QWidget* ConfigMapper::getBindWidgetForConfig(CfgEntry* key) const
{
if (configEntryToWidgets.contains(key))
- return configEntryToWidgets[key];
+ return configEntryToWidgets.value(key);
return nullptr;
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/configmapper.h b/SQLiteStudio3/guiSQLiteStudio/configmapper.h
index 47c1087..ca70918 100644
--- a/SQLiteStudio3/guiSQLiteStudio/configmapper.h
+++ b/SQLiteStudio3/guiSQLiteStudio/configmapper.h
@@ -107,8 +107,8 @@ class GUI_API_EXPORT ConfigMapper : public QObject
QList<CustomConfigWidgetPlugin*> internalCustomConfigWidgets;
bool realTimeUpdates = false;
QHash<QWidget*,CfgEntry*> widgetToConfigEntry;
- QHash<CfgEntry*,QWidget*> configEntryToWidgets;
- QHash<CfgEntry*,QWidget*> specialConfigEntryToWidgets;
+ QMultiHash<CfgEntry*,QWidget*> configEntryToWidgets;
+ QMultiHash<CfgEntry*,QWidget*> specialConfigEntryToWidgets;
bool updatingEntry = false;
QList<QWidget*> extraWidgets;
QList<QWidget*> widgetsToIgnore; // main mapper will ignore plugin's forms, they have their own mappers
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
index 5759f76..bb70c81 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columndefaultpanel.cpp
@@ -152,7 +152,7 @@ void ColumnDefaultPanel::storeExpr(SqliteCreateTable::Column::Constraint* constr
return;
}
- Parser parser(db->getDialect());
+ Parser parser;
SqliteExpr* newExpr = parser.parseExpr(text);
newExpr->setParent(constraint.data());
constr->expr = newExpr;
@@ -162,7 +162,7 @@ void ColumnDefaultPanel::storeLiteral(SqliteCreateTable::Column::Constraint* con
{
QString text = ui->exprEdit->toPlainText();
- Parser parser(db->getDialect());
+ Parser parser;
SqliteCreateTablePtr createTable = parser.parse<SqliteCreateTable>("CREATE TABLE tab (col DEFAULT "+text+");");
if (!createTable || createTable->columns.size() == 0 || createTable->columns.first()->constraints.size() == 0)
{
@@ -240,7 +240,7 @@ void ColumnDefaultPanel::readConstraint()
}
else if (!constr->id.isNull())
{
- ui->exprEdit->setPlainText(wrapObjIfNeeded(constr->id, db->getDialect(), true));
+ ui->exprEdit->setPlainText(wrapObjIfNeeded(constr->id, true));
currentMode = Mode::LITERAL;
}
else if (!constr->ctime.isNull())
@@ -265,7 +265,7 @@ void ColumnDefaultPanel::updateVirtualSql()
{
static QString sql = QStringLiteral("CREATE TABLE tab (col DEFAULT %1)");
ui->exprEdit->setDb(db);
- ui->exprEdit->setVirtualSqlExpression(sql.arg(db->getDialect() == Dialect::Sqlite3 ? "(%1)" : "%1"));
+ ui->exprEdit->setVirtualSqlExpression(sql.arg("(%1)"));
}
QString ColumnDefaultPanel::getTempTable()
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp
index af79331..ea5cb7d 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnforeignkeypanel.cpp
@@ -227,7 +227,7 @@ void ColumnForeignKeyPanel::storeConfiguration()
constr->foreignKey->initially = sqliteInitially(ui->initiallyCombo->currentText());
// Name
- constr->name = QString::null;
+ constr->name = QString();
if (ui->namedCheckBox->isChecked())
constr->name = ui->nameEdit->text();
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp
new file mode 100644
index 0000000..308b868
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.cpp
@@ -0,0 +1,227 @@
+#include "columngeneratedpanel.h"
+#include "ui_columngeneratedpanel.h"
+#include "parser/parser.h"
+#include "parser/keywords.h"
+#include "parser/lexer.h"
+#include "uiutils.h"
+#include "schemaresolver.h"
+#include <QDebug>
+
+ColumnGeneratedPanel::ColumnGeneratedPanel(QWidget *parent) :
+ ConstraintPanel(parent),
+ ui(new Ui::ColumnGeneratedPanel)
+{
+ ui->setupUi(this);
+ init();
+}
+
+ColumnGeneratedPanel::~ColumnGeneratedPanel()
+{
+ delete ui;
+}
+
+void ColumnGeneratedPanel::changeEvent(QEvent *e)
+{
+ QWidget::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+
+bool ColumnGeneratedPanel::validate()
+{
+ if (!ui->exprEdit->isSyntaxChecked())
+ {
+ setValidState(ui->exprEdit, false, tr("Enter the column value generating expression."));
+ return false;
+ }
+
+ // First check if we already validated this text.
+ // This method is called twice, by both errors checking and syntax highlighting,
+ // because signal for textChange() is connected with call to updateValidation().
+ QString text = ui->exprEdit->toPlainText();
+ if (!lastValidatedText.isNull() && lastValidatedText == text)
+ return lastValidationResult;
+
+ lastValidatedText = text;
+
+ bool nameOk = true;
+ if (ui->namedCheck->isChecked() && ui->namedEdit->text().isEmpty())
+ nameOk = false;
+
+ bool exprOk = !ui->exprEdit->toPlainText().trimmed().isEmpty() &&
+ !ui->exprEdit->haveErrors();
+
+ QString exprError;
+ if (exprOk)
+ {
+ // Everything looks fine, so lets do the final check - if the value is correct for use as generated column expression in SQLite.
+ static QString tempDdlExprTpl = QStringLiteral("CREATE TEMP TABLE %1 (aaa, %2 GENERATED ALWAYS AS (%3));");
+ static QString dropTempDdl = QStringLiteral("DROP TABLE %1;");
+
+ SqliteCreateTable::Column* columnStmt = dynamic_cast<SqliteCreateTable::Column*>(constraint->parentStatement());
+ SqliteCreateTable* createTableStmt = dynamic_cast<SqliteCreateTable*>(columnStmt->parentStatement());
+
+ QStringList preparedColNames;
+ QString thisColumnName = columnStmt->name;
+ for (SqliteCreateTable::Column* column : createTableStmt->columns)
+ {
+ if (column->name == thisColumnName)
+ continue;
+
+ preparedColNames << wrapObjIfNeeded(column->name);
+ }
+ preparedColNames << wrapObjIfNeeded(thisColumnName);
+
+ QString tableName = getTempTable();
+ QString tempDdl = tempDdlExprTpl.arg(tableName, preparedColNames.join(", "), ui->exprEdit->toPlainText());
+ SqlQueryPtr res = db->exec(tempDdl);
+ if (res->isError())
+ {
+ exprOk = false;
+ exprError = tr("Invalid value generating expression: %1.")
+ .arg(res->getErrorText());
+ }
+
+ db->exec(dropTempDdl.arg(tableName));
+ } else
+ exprError = tr("Invalid value generating expression.");
+
+ setValidState(ui->exprEdit, exprOk, exprError);
+ setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint."));
+
+ lastValidationResult = (exprOk && nameOk);
+ return lastValidationResult;
+}
+
+bool ColumnGeneratedPanel::validateOnly()
+{
+ ui->exprEdit->checkSyntaxNow();
+ return validate();
+}
+
+void ColumnGeneratedPanel::constraintAvailable()
+{
+ if (constraint.isNull())
+ return;
+
+ readConstraint();
+ updateVirtualSql();
+ validateOnly();
+}
+
+void ColumnGeneratedPanel::storeConfiguration()
+{
+ if (constraint.isNull())
+ return;
+
+ SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data());
+ constr->type = SqliteCreateTable::Column::Constraint::GENERATED;
+ storeExpr(constr);
+
+ if (ui->typeCheck->isChecked())
+ constr->generatedType = SqliteCreateTable::Column::Constraint::generatedTypeFrom(ui->typeCombo->currentText());
+ else
+ constr->generatedType = SqliteCreateTable::Column::Constraint::GeneratedType::null;
+
+ constr->generatedKw = ui->generatedKwCheck->isChecked();
+
+ if (ui->namedCheck->isChecked())
+ constr->name = ui->namedEdit->text();
+}
+
+void ColumnGeneratedPanel::storeExpr(SqliteCreateTable::Column::Constraint* constr)
+{
+ QString text = ui->exprEdit->toPlainText();
+ clear(constr);
+
+ Parser parser;
+ SqliteExpr* newExpr = parser.parseExpr(text);
+ newExpr->setParent(constraint.data());
+ constr->expr = newExpr;
+}
+
+void ColumnGeneratedPanel::clear(SqliteCreateTable::Column::Constraint* constr)
+{
+ if (constr->expr)
+ {
+ delete constr->expr;
+ constr->expr = nullptr;
+ }
+ constr->generatedKw = false;
+ constr->generatedType = SqliteCreateTable::Column::Constraint::GeneratedType::null;
+}
+
+void ColumnGeneratedPanel::init()
+{
+ setFocusProxy(ui->exprEdit);
+ ui->exprEdit->setShowLineNumbers(false);
+
+ connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation()));
+ connect(ui->namedEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation()));
+ connect(ui->exprEdit, SIGNAL(textChanged()), this, SIGNAL(updateValidation()));
+ connect(ui->exprEdit, SIGNAL(errorsChecked(bool)), this, SIGNAL(updateValidation()));
+
+ connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SLOT(updateState()));
+ connect(ui->typeCheck, SIGNAL(toggled(bool)), this, SLOT(updateState()));
+
+ ui->typeCombo->addItems(getGeneratedColumnTypes());
+
+ updateState();
+}
+
+void ColumnGeneratedPanel::readConstraint()
+{
+ SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data());
+
+ constr->rebuildTokens();
+ if (constr->expr)
+ ui->exprEdit->setPlainText(constr->expr->detokenize());
+
+ QString typeValue = SqliteCreateTable::Column::Constraint::toString(constr->generatedType);
+ switch (constr->generatedType) {
+ case SqliteCreateTable::Column::Constraint::GeneratedType::STORED:
+ ui->typeCheck->setChecked(true);
+ break;
+ case SqliteCreateTable::Column::Constraint::GeneratedType::VIRTUAL:
+ ui->typeCheck->setChecked(true);
+ break;
+ case SqliteCreateTable::Column::Constraint::GeneratedType::null:
+ ui->typeCheck->setChecked(false);
+ typeValue = SqliteCreateTable::Column::Constraint::toString(SqliteCreateTable::Column::Constraint::GeneratedType::VIRTUAL);
+ break;
+ }
+ ui->typeCombo->setCurrentText(typeValue);
+
+ ui->generatedKwCheck->setChecked(constr->generatedKw);
+
+ if (!constr->name.isNull())
+ {
+ ui->namedCheck->setChecked(true);
+ ui->namedEdit->setText(constr->name);
+ }
+}
+
+void ColumnGeneratedPanel::updateVirtualSql()
+{
+ static QString sql = QStringLiteral("CREATE TABLE tab (col GENERATED ALWAYS AS (%1))");
+ ui->exprEdit->setDb(db);
+ ui->exprEdit->setVirtualSqlExpression(sql);
+}
+
+QString ColumnGeneratedPanel::getTempTable()
+{
+ SchemaResolver resolver(db);
+ return resolver.getUniqueName("sqlitestudio_temp_table");
+}
+
+void ColumnGeneratedPanel::updateState()
+{
+ ui->namedEdit->setEnabled(ui->namedCheck->isChecked());
+ ui->typeCombo->setEnabled(ui->typeCheck->isChecked());
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.h b/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.h
new file mode 100644
index 0000000..171dab8
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.h
@@ -0,0 +1,44 @@
+#ifndef COLUMNGENERATEDPANEL_H
+#define COLUMNGENERATEDPANEL_H
+
+#include "constraintpanel.h"
+#include "guiSQLiteStudio_global.h"
+#include <QWidget>
+
+namespace Ui {
+ class ColumnGeneratedPanel;
+}
+
+class GUI_API_EXPORT ColumnGeneratedPanel : public ConstraintPanel
+{
+ Q_OBJECT
+
+ public:
+ explicit ColumnGeneratedPanel(QWidget *parent = 0);
+ ~ColumnGeneratedPanel();
+
+ bool validate();
+ bool validateOnly();
+
+ protected:
+ void changeEvent(QEvent *e);
+ void constraintAvailable();
+ void storeConfiguration();
+
+ private:
+ void init();
+ void readConstraint();
+ void updateVirtualSql();
+ QString getTempTable();
+ void storeExpr(SqliteCreateTable::Column::Constraint* constr);
+ void clear(SqliteCreateTable::Column::Constraint* constr);
+
+ Ui::ColumnGeneratedPanel *ui = nullptr;
+ QString lastValidatedText;
+ bool lastValidationResult = false;
+
+ private slots:
+ void updateState();
+};
+
+#endif // COLUMNGENERATEDPANEL_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.ui
new file mode 100644
index 0000000..3d0bcfc
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columngeneratedpanel.ui
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ColumnGeneratedPanel</class>
+ <widget class="QWidget" name="ColumnGeneratedPanel">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>263</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="exprGroup">
+ <property name="title">
+ <string>Generating code:</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="SqlEditor" name="exprEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="typeWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QCheckBox" name="typeCheck">
+ <property name="text">
+ <string>Explicit type:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="typeCombo">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="generatedKwWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="generatedKwCheck">
+ <property name="text">
+ <string>Use &quot;GENERATED ALWAYS&quot; keywords</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="namedWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="namedCheck">
+ <property name="text">
+ <string>Named constraint:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="namedEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SqlEditor</class>
+ <extends>QPlainTextEdit</extends>
+ <header>sqleditor.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp
index f8975d8..fa7b7c3 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/columnprimarykeypanel.cpp
@@ -39,6 +39,9 @@ void ColumnPrimaryKeyPanel::init()
connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation()));
connect(ui->namedEdit, SIGNAL(textChanged(QString)), this, SIGNAL(updateValidation()));
+ connect(ui->sortOrderCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation()));
+ connect(ui->sortOrderCombo, SIGNAL(currentTextChanged(QString)), this, SIGNAL(updateValidation()));
+ connect(ui->autoIncrCheck, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation()));
connect(ui->sortOrderCheck, SIGNAL(toggled(bool)), this, SLOT(updateState()));
connect(ui->namedCheck, SIGNAL(toggled(bool)), this, SLOT(updateState()));
connect(ui->conflictCheck, SIGNAL(toggled(bool)), this, SLOT(updateState()));
@@ -48,8 +51,7 @@ void ColumnPrimaryKeyPanel::init()
void ColumnPrimaryKeyPanel::readConstraint()
{
SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data());
- if (constraint->dialect == Dialect::Sqlite3)
- ui->autoIncrCheck->setChecked(constr->autoincrKw);
+ ui->autoIncrCheck->setChecked(constr->autoincrKw);
if (constr->sortOrder != SqliteSortOrder::null)
{
@@ -77,7 +79,6 @@ void ColumnPrimaryKeyPanel::updateState()
ui->conflictCombo->setEnabled(ui->conflictCheck->isChecked());
}
-
bool ColumnPrimaryKeyPanel::validate()
{
bool nameOk = true;
@@ -86,7 +87,16 @@ bool ColumnPrimaryKeyPanel::validate()
setValidState(ui->namedEdit, nameOk, tr("Enter a name of the constraint."));
- return nameOk;
+ bool sortOk = true;
+ if (ui->autoIncrCheck->isChecked() && ui->sortOrderCombo->isEnabled() &&
+ ui->sortOrderCombo->currentText().toUpper() == "DESC")
+ {
+ sortOk = false;
+ }
+
+ setValidState(ui->sortOrderCombo, sortOk, tr("Descending order is not allowed with AUTOINCREMENT."));
+
+ return nameOk && sortOk;
}
void ColumnPrimaryKeyPanel::constraintAvailable()
@@ -94,8 +104,6 @@ void ColumnPrimaryKeyPanel::constraintAvailable()
if (constraint.isNull())
return;
- ui->autoIncrCheck->setVisible(constraint->dialect == Dialect::Sqlite3);
-
readConstraint();
}
@@ -107,8 +115,7 @@ void ColumnPrimaryKeyPanel::storeConfiguration()
SqliteCreateTable::Column::Constraint* constr = dynamic_cast<SqliteCreateTable::Column::Constraint*>(constraint.data());
constr->type = SqliteCreateTable::Column::Constraint::PRIMARY_KEY;
- if (constraint->dialect == Dialect::Sqlite3)
- constr->autoincrKw = ui->autoIncrCheck->isChecked();
+ constr->autoincrKw = ui->autoIncrCheck->isChecked();
if (ui->sortOrderCheck->isChecked() && ui->sortOrderCombo->currentIndex() > -1)
constr->sortOrder = sqliteSortOrder(ui->sortOrderCombo->currentText());
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.cpp
index adb5e2b..8a71777 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintcheckpanel.cpp
@@ -54,11 +54,8 @@ void ConstraintCheckPanel::constraintAvailable()
if (constraint.isNull())
return;
- if (constraint->dialect == Dialect::Sqlite3)
- {
- ui->onConflictCheck->setVisible(false);
- ui->onConflictCombo->setVisible(false);
- }
+ ui->onConflictCheck->setVisible(false);
+ ui->onConflictCombo->setVisible(false);
readConstraint();
updateVirtualSql();
@@ -76,14 +73,11 @@ void ConstraintCheckPanel::storeConfiguration()
newExpr->setParent(constraint.data());
storeExpr(newExpr);
- QString name = QString::null;
+ QString name = QString();
if (ui->namedCheck->isChecked())
name = ui->namedEdit->text();
storeName(name);
-
- if (constraint->dialect == Dialect::Sqlite2 && ui->onConflictCheck->isChecked())
- storeConflictAlgo(sqliteConflictAlgo(ui->onConflictCombo->currentText()));
}
void ConstraintCheckPanel::init()
@@ -116,13 +110,6 @@ void ConstraintCheckPanel::readConstraint()
ui->namedCheck->setChecked(true);
ui->namedEdit->setText(name);
}
-
- SqliteConflictAlgo onConflict = readConflictAlgo();
- if (constraint->dialect == Dialect::Sqlite2 && onConflict != SqliteConflictAlgo::null)
- {
- ui->onConflictCheck->setChecked(true);
- ui->onConflictCombo->setCurrentText(sqliteConflictAlgo(onConflict));
- }
}
void ConstraintCheckPanel::updateVirtualSql()
@@ -157,7 +144,7 @@ void ConstraintCheckPanel::updateVirtualSql()
SqliteExprPtr ConstraintCheckPanel::parseExpression(const QString& sql)
{
- Parser parser(db->getDialect());
+ Parser parser;
SqliteExpr *expr = parser.parseExpr(sql);
return SqliteExprPtr(expr);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp
index 031fbfe..4f3e350 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/constraintpanel.cpp
@@ -6,6 +6,7 @@
#include "constraints/tablecheckpanel.h"
#include "constraints/columncheckpanel.h"
#include "constraints/columncollatepanel.h"
+#include "constraints/columngeneratedpanel.h"
#include "constraints/columndefaultpanel.h"
#include "constraints/columnforeignkeypanel.h"
#include "constraints/columnnotnullpanel.h"
@@ -81,6 +82,8 @@ ConstraintPanel* ConstraintPanel::produce(SqliteCreateTable::Column::Constraint*
return new ColumnDefaultPanel();
case SqliteCreateTable::Column::Constraint::COLLATE:
return new ColumnCollatePanel();
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return new ColumnGeneratedPanel();
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return new ColumnForeignKeyPanel();
case SqliteCreateTable::Column::Constraint::NULL_:
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp
index 8bc7926..cecf5f4 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.cpp
@@ -72,7 +72,6 @@ bool TableForeignKeyPanel::validate()
void TableForeignKeyPanel::setDb(Db* value)
{
ConstraintPanel::setDb(value);
- ui->sqlite2Warn->setVisible(value->getDialect() == Dialect::Sqlite2);
}
void TableForeignKeyPanel::constraintAvailable()
@@ -361,7 +360,7 @@ void TableForeignKeyPanel::storeConfiguration()
constr->foreignKey->initially = sqliteInitially(ui->initiallyCombo->currentText());
// Name
- constr->name = QString::null;
+ constr->name = QString();
if (ui->namedCheckBox->isChecked())
constr->name = ui->nameEdit->text();
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.ui b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.ui
index 7ecbe06..a0e38ec 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tableforeignkeypanel.ui
@@ -37,26 +37,6 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="sqlite2Warn">
- <property name="font">
- <font>
- <pointsize>8</pointsize>
- <italic>true</italic>
- </font>
- </property>
- <property name="text">
- <string>SQLite 2 does not support foreign keys officially,
-but it's okay to use them anyway.</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <property name="margin">
- <number>5</number>
- </property>
- </widget>
- </item>
- <item>
<widget class="QGroupBox" name="columnsGroup">
<property name="title">
<string>Columns</string>
@@ -110,8 +90,8 @@ but it's okay to use them anyway.</string>
<rect>
<x>0</x>
<y>0</y>
- <width>362</width>
- <height>25</height>
+ <width>358</width>
+ <height>30</height>
</rect>
</property>
</widget>
diff --git a/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp
index 7c1c359..65c4a34 100644
--- a/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/constraints/tablepkanduniquepanel.cpp
@@ -78,7 +78,7 @@ void TablePrimaryKeyAndUniquePanel::buildColumn(SqliteCreateTable::Column* colum
connect(check, SIGNAL(toggled(bool)), this, SIGNAL(updateValidation()));
QComboBox* collation = nullptr;
- if (!constraint.isNull() && constraint->dialect == Dialect::Sqlite3)
+ if (!constraint.isNull())
{
collation = new QComboBox();
collation->setMaximumWidth(ui->colHdrCollation->width());
@@ -125,7 +125,7 @@ void TablePrimaryKeyAndUniquePanel::updateColumnState(int colIdx)
item = columnsLayout->itemAtPosition(colIdx, 1)->widget();
qobject_cast<QComboBox*>(item)->setEnabled(enable);
- if (!constraint.isNull() && constraint->dialect == Dialect::Sqlite3)
+ if (!constraint.isNull())
{
item = columnsLayout->itemAtPosition(colIdx, 2)->widget();
qobject_cast<QComboBox*>(item)->setEnabled(enable);
@@ -182,7 +182,7 @@ void TablePrimaryKeyAndUniquePanel::storeConfiguration()
SqliteCreateTable::Constraint* constr = dynamic_cast<SqliteCreateTable::Constraint*>(constraint.data());
// Name
- constr->name = QString::null;
+ constr->name = QString();
if (ui->namedCheckBox->isChecked())
constr->name = ui->namedLineEdit->text();
@@ -210,21 +210,13 @@ void TablePrimaryKeyAndUniquePanel::storeConfiguration()
name = check->property(UI_PROP_COLUMN).toString();
- if (constr->dialect == Dialect::Sqlite3)
- {
- combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 1)->widget());
- collate = combo->currentText();
- if (collate.isEmpty())
- collate = QString::null;
+ combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 1)->widget());
+ collate = combo->currentText();
+ if (collate.isEmpty())
+ collate = QString();
- combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 2)->widget());
- sortOrder = sqliteSortOrder(combo->currentText());
- }
- else
- {
- combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 1)->widget());
- sortOrder = sqliteSortOrder(combo->currentText());
- }
+ combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(i, 2)->widget());
+ sortOrder = sqliteSortOrder(combo->currentText());
idxCol = new SqliteIndexedColumn(name, collate, sortOrder);
idxCol->setParent(constr);
@@ -266,24 +258,11 @@ void TablePrimaryKeyAndUniquePanel::readConstraint()
check = dynamic_cast<QCheckBox*>(columnsLayout->itemAtPosition(idx, 0)->widget());
check->setChecked(true);
- if (constr->dialect == Dialect::Sqlite3)
- {
- combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 1)->widget());
- combo->setCurrentText(idxCol->collate);
+ combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 1)->widget());
+ combo->setCurrentText(idxCol->collate);
- combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 2)->widget());
- combo->setCurrentText(sqliteSortOrder(idxCol->sortOrder));
- }
- else
- {
- combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 1)->widget());
- combo->setCurrentText(sqliteSortOrder(idxCol->sortOrder));
- }
- }
-
- if (constr->dialect == Dialect::Sqlite2)
- {
- ui->colHdrCollation->setVisible(false);
+ combo = dynamic_cast<QComboBox*>(columnsLayout->itemAtPosition(idx, 2)->widget());
+ combo->setCurrentText(sqliteSortOrder(idxCol->sortOrder));
}
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp
index b8ebf45..ebca434 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.cpp
@@ -6,6 +6,8 @@
#include "sqlqueryview.h"
#include <QDate>
#include <QDebug>
+#include <QApplication>
+#include <QStyle>
SqlQueryItem::SqlQueryItem(QObject *parent) :
QObject(parent)
@@ -46,14 +48,14 @@ void SqlQueryItem::setUncommitted(bool uncommitted)
QStandardItem::setData(QVariant(uncommitted), DataRole::UNCOMMITTED);
if (!uncommitted)
{
- setOldValue(QVariant());
+ clearOldValue();
setCommittingError(false);
}
}
void SqlQueryItem::rollback()
{
- setValue(getOldValue(), true, true);
+ setValue(getOldValue(), getOldValueLimited(), true);
setUncommitted(false);
setDeletedRow(false);
}
@@ -66,6 +68,24 @@ bool SqlQueryItem::isCommittingError() const
void SqlQueryItem::setCommittingError(bool isError)
{
QStandardItem::setData(QVariant(isError), DataRole::COMMITTING_ERROR);
+ if (!isError)
+ setCommittingErrorMessage(QString());
+}
+
+void SqlQueryItem::setCommittingError(bool isError, const QString& msg)
+{
+ setCommittingErrorMessage(msg);
+ setCommittingError(isError);
+}
+
+QString SqlQueryItem::getCommittingErrorMessage() const
+{
+ return QStandardItem::data(DataRole::COMMITTING_ERROR_MESSAGE).toString();
+}
+
+void SqlQueryItem::setCommittingErrorMessage(const QString& value)
+{
+ QStandardItem::setData(QVariant(value), DataRole::COMMITTING_ERROR_MESSAGE);
}
bool SqlQueryItem::isNewRow() const
@@ -96,7 +116,7 @@ bool SqlQueryItem::isDeletedRow() const
void SqlQueryItem::setDeletedRow(bool isDeleted)
{
if (isDeleted && !getOldValue().isValid())
- setOldValue(getValue());
+ rememberOldValue();
QStandardItem::setData(QVariant(isDeleted), DataRole::DELETED);
}
@@ -108,6 +128,13 @@ QVariant SqlQueryItem::getValue() const
void SqlQueryItem::setValue(const QVariant &value, bool limited, bool loadedFromDb)
{
+ if (!valueSettingLock.tryLock())
+ {
+ // Triggered recursively by catching "itemChanged" event,
+ // that was caused by the QStandardItem::setData below.
+ return;
+ }
+
QVariant newValue = adjustVariantType(value);
QVariant origValue = getValue();
@@ -124,7 +151,7 @@ void SqlQueryItem::setValue(const QVariant &value, bool limited, bool loadedFrom
isUncommitted();
if (modified && !getOldValue().isValid())
- setOldValue(origValue);
+ rememberOldValue();
// This is a workaround for an issue in Qt, that uses operator== to compare values in QStandardItem::setData().
// If the old value is null and the new value is empty, then operator == returns true, which is a lie.
@@ -138,46 +165,12 @@ void SqlQueryItem::setValue(const QVariant &value, bool limited, bool loadedFrom
// Value for display (in a cell) will always be limited, for performance reasons
setValueForDisplay("x"); // the same trick as with the DataRole::VALUE
- if (!limited)
- {
- int theLimit = SqlQueryModel::getCellDataLengthLimit();
- switch (value.type())
- {
- case QVariant::ByteArray:
- {
- QByteArray newBytes = newValue.toByteArray();
- if (newBytes.size() > theLimit)
- {
- newBytes.resize(theLimit);
- setValueForDisplay(newBytes);
- }
- else
- setValueForDisplay(newValue);
-
- break;
- }
- case QVariant::String:
- {
- QString newString = newValue.toString();
- if (newString.size() > theLimit)
- {
- newString.resize(theLimit);
- setValueForDisplay(newString);
- }
- else
- setValueForDisplay(newValue);
-
- break;
- }
- default:
- setValueForDisplay(newValue);
- }
- }
- else
- setValueForDisplay(newValue);
+ setValueForDisplay(newValue);
if (modified && getModel())
getModel()->itemValueEdited(this);
+
+ valueSettingLock.unlock();
}
bool SqlQueryItem::isLimitedValue() const
@@ -195,6 +188,16 @@ void SqlQueryItem::setOldValue(const QVariant& value)
QStandardItem::setData(value, DataRole::OLD_VALUE);
}
+bool SqlQueryItem::getOldValueLimited() const
+{
+ return QStandardItem::data(DataRole::OLD_VALUE_LIMITED).toBool();
+}
+
+void SqlQueryItem::setOldValueLimited(bool value)
+{
+ QStandardItem::setData(value, DataRole::OLD_VALUE_LIMITED);
+}
+
QVariant SqlQueryItem::getValueForDisplay() const
{
return QStandardItem::data(DataRole::VALUE_FOR_DISPLAY);
@@ -240,20 +243,27 @@ QString SqlQueryItem::getToolTip() const
static const QString hdrRowTmp = "<tr><td width=16><img src=\"%1\"/></td><th colspan=2 style=\"align: center\">%2 %3</th></tr>";
static const QString constrRowTmp = "<tr><td width=16><img src=\"%1\"/></td><td style=\"white-space: pre\"><b>%2</b></td><td>%3</td></tr>";
static const QString emptyRow = "<tr><td colspan=3></td></tr>";
+ static const QString topErrorRowTmp = "<tr><td width=16><img src=\"%1\"/></td><td style=\"white-space: pre\"><b>%2</b></td><td>%3</td></tr>";
if (!index().isValid())
- return QString::null;
+ return QString();
SqlQueryModelColumn* col = getColumn();
if (!col)
- return QString::null; // happens when simple execution method was performed
+ return QString(); // happens when simple execution method was performed
QStringList rows;
- rows << hdrRowTmp.arg(ICONS.COLUMN.getPath()).arg(tr("Column:", "data view tooltip")).arg(col->column);
- rows << rowTmp.arg(tr("Data type:", "data view")).arg(col->dataType.toString());
+ if (isCommittingError())
+ {
+ rows << topErrorRowTmp.arg(ICONS.STATUS_WARNING.getPath(), tr("Committing error:", "data view tooltip"), getCommittingErrorMessage());
+ rows << emptyRow;
+ }
+
+ rows << hdrRowTmp.arg(ICONS.COLUMN.getPath(), tr("Column:", "data view tooltip"), col->column);
+ rows << rowTmp.arg(tr("Data type:", "data view"), col->dataType.toString());
if (!col->table.isNull())
{
- rows << rowTmp.arg(tr("Table:", "data view tooltip")).arg(col->table);
+ rows << rowTmp.arg(tr("Table:", "data view tooltip"), col->table);
RowId rowId = getRowId();
QString rowIdStr;
@@ -277,20 +287,32 @@ QString SqlQueryItem::getToolTip() const
}
rowIdStr = "[" + values.join(", ") + "]";
}
- rows << rowTmp.arg("ROWID:").arg(rowIdStr);
+ rows << rowTmp.arg("ROWID:", rowIdStr);
}
if (col->constraints.size() > 0)
{
rows << emptyRow;
- rows << hdrRowTmp.arg(ICONS.COLUMN_CONSTRAINT.getPath()).arg(tr("Constraints:", "data view tooltip")).arg("");
+ rows << hdrRowTmp.arg(ICONS.COLUMN_CONSTRAINT.getPath(), tr("Constraints:", "data view tooltip"), "");
for (SqlQueryModelColumn::Constraint* constr : col->constraints)
- rows << constrRowTmp.arg(constr->getIcon()->toUrl()).arg(constr->getTypeString()).arg(constr->getDetails());
+ rows << constrRowTmp.arg(constr->getIcon()->toUrl(), constr->getTypeString(), constr->getDetails());
}
return tableTmp.arg(rows.join(""));
}
+void SqlQueryItem::rememberOldValue()
+{
+ setOldValue(getValue());
+ setOldValueLimited(isLimitedValue());
+}
+
+void SqlQueryItem::clearOldValue()
+{
+ setOldValue(QVariant());
+ setOldValueLimited(false);
+}
+
SqlQueryModelColumn* SqlQueryItem::getColumn() const
{
return QStandardItem::data(DataRole::COLUMN).value<SqlQueryModelColumn*>();
@@ -352,14 +374,14 @@ QVariant SqlQueryItem::data(int role) const
{
QVariant value = getValue();
if (value.isNull())
- return QBrush(CFG_UI.Colors.DataNullFg.get());
+ return QApplication::style()->standardPalette().dark();
break;
}
case Qt::BackgroundRole:
{
if (isDeletedRow())
- return QBrush(CFG_UI.Colors.DataDeletedBg.get());
+ return QApplication::style()->standardPalette().dark();
break;
}
@@ -396,25 +418,6 @@ QVariant SqlQueryItem::data(int role) const
QString SqlQueryItem::loadFullData()
{
SqlQueryModelColumn* col = getColumn();
-
- // Yes, this function won't be called in case of trying to edit the cell - it's handled in the Editor.
- // However this function can be called from the FormView, to display full contents of the read-only property.
- // I'll keep it for some time just in case. To be removed in future.
-// if (col->editionForbiddenReason.size() > 0)
-// {
-// qWarning() << "Tried to load full cell which is not editable. This should be already handled in Editor class when invoking edition action.";
-// return tr("This cell is not editable, because: %1").arg(SqlQueryModelColumn::resolveMessage(col->editionForbiddenReason.values().first()));
-// }
-
- // This should not happen anymore (since WITHOUT ROWID tables should be handled properly now,
- // but we will keep this here for a while, just in case.
-// if (isJustInsertedWithOutRowId())
-// {
-// QString msg = tr("When inserted new row to the WITHOUT ROWID table, using DEFAULT value for PRIMARY KEY, "
-// "the table has to be reloaded in order to edit the new row.");
-// return tr("This cell is not editable, because: %1").arg(msg);
-// }
-
SqlQueryModel *model = getModel();
Db* db = model->getDb();
if (!db->isOpen())
@@ -423,31 +426,36 @@ QString SqlQueryItem::loadFullData()
return tr("Cannot load the data for a cell that refers to the already closed database.");
}
- Dialect dialect = db->getDialect();
-
// Query
QString query;
QHash<QString,QVariant> queryArgs;
- QString column = wrapObjIfNeeded(col->column, dialect);
if (col->editionForbiddenReason.size() > 0)
{
static_qstring(tpl, "SELECT %1 FROM (%2) LIMIT 1 OFFSET %3");
// The query
+ QString colName = !col->alias.isNull() ? col->alias : col->column;
+ if (colName.isNull())
+ colName = col->displayName;
+
+ QString column = wrapObjIfNeeded(colName);
query = tpl.arg(column, model->getQuery(), QString::number(index().row()));
}
else
{
static_qstring(tpl, "SELECT %1 FROM %2 WHERE %3");
+ // Column
+ QString column = wrapObjIfNeeded(col->column);
+
// Db and table
- QString source = wrapObjIfNeeded(col->table, dialect);
+ QString source = wrapObjIfNeeded(col->table);
if (!col->database.isNull())
- source.prepend(wrapObjIfNeeded(col->database, dialect)+".");
+ source.prepend(wrapObjIfNeeded(col->database)+".");
// ROWID
RowIdConditionBuilder rowIdBuilder;
- rowIdBuilder.setRowId(getRowId(), dialect);
+ rowIdBuilder.setRowId(getRowId());
QString rowId = rowIdBuilder.build();
queryArgs = rowIdBuilder.getQueryArgs();
@@ -461,7 +469,7 @@ QString SqlQueryItem::loadFullData()
return results->getErrorText();
setValue(results->getSingleCell(), false, true);
- return QString::null;
+ return QString();
}
QVariant SqlQueryItem::getFullValue()
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h
index 805d275..6ffddfc 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitem.h
@@ -27,7 +27,9 @@ class GUI_API_EXPORT SqlQueryItem : public QObject, public QStandardItem
DELETED = 1008,
OLD_VALUE = 1009,
JUST_INSERTED_WITHOUT_ROWID = 1010,
- VALUE_FOR_DISPLAY = 1011
+ VALUE_FOR_DISPLAY = 1011,
+ COMMITTING_ERROR_MESSAGE = 1012,
+ OLD_VALUE_LIMITED = 1013
};
};
@@ -45,6 +47,10 @@ class GUI_API_EXPORT SqlQueryItem : public QObject, public QStandardItem
bool isCommittingError() const;
void setCommittingError(bool isError);
+ void setCommittingError(bool isError, const QString& msg);
+
+ QString getCommittingErrorMessage() const;
+ void setCommittingErrorMessage(const QString& value);
bool isNewRow() const;
void setNewRow(bool isNew);
@@ -62,12 +68,15 @@ class GUI_API_EXPORT SqlQueryItem : public QObject, public QStandardItem
QVariant getOldValue() const;
void setOldValue(const QVariant& value);
+ bool getOldValueLimited() const;
+ void setOldValueLimited(bool value);
+
QVariant getValueForDisplay() const;
void setValueForDisplay(const QVariant& value);
/**
* @brief loadFullData Reloads entire value of the cell from database.
- * @return QString::null on sucess, or error string on failure.
+ * @return QString() on sucess, or error string on failure.
*/
QString loadFullData();
@@ -91,6 +100,10 @@ class GUI_API_EXPORT SqlQueryItem : public QObject, public QStandardItem
void setLimitedValue(bool limited);
QVariant adjustVariantType(const QVariant& value);
QString getToolTip() const;
+ void rememberOldValue();
+ void clearOldValue();
+
+ QMutex valueSettingLock;
};
#endif // SQLQUERYITEM_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp
index 64d37e4..1ebf06f 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.cpp
@@ -18,12 +18,19 @@
#include <QResizeEvent>
#include <QScrollBar>
#include <limits>
+#include <QToolTip>
+#include <QTextLayout>
+#include <QtMath>
+#include <QScreen>
bool SqlQueryItemDelegate::warnedAboutHugeContents = false;
SqlQueryItemDelegate::SqlQueryItemDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
+ fullValueButtonOption.icon = ICONS.LOAD_FULL_VALUE;
+ fullValueButtonOption.iconSize = QSize(LOAD_FULL_VALUE_ICON_SIZE, LOAD_FULL_VALUE_ICON_SIZE);
+ fullValueButtonOption.state = QStyle::State_Enabled;
}
void SqlQueryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
@@ -33,10 +40,115 @@ void SqlQueryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
if (item->isUncommitted())
{
- painter->setPen(item->isCommittingError() ? CFG_UI.Colors.DataUncommittedError.get() : CFG_UI.Colors.DataUncommitted.get());
+ painter->setPen(item->isCommittingError() ? QColor(Qt::red) : QColor(Qt::blue));
painter->setBrush(Qt::NoBrush);
painter->drawRect(option.rect.x(), option.rect.y(), option.rect.width()-1, option.rect.height()-1);
}
+
+ if (item->isLimitedValue())
+ {
+ QStyleOptionViewItem opt = option;
+ initStyleOption(&opt, index);
+ QString text = displayText(item->getValue(), opt.locale);
+ int textWidth = opt.fontMetrics.horizontalAdvance(text);
+ int margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, opt.widget) + 1; // from QCommonStyle source code
+ if (opt.rect.width() >= (textWidth + LOAD_FULL_VALUE_BUTTON_SIZE + margin))
+ {
+ QStyleOptionButton button = fullValueButtonOption;
+ button.rect = getLoadFullValueButtonRegion(opt.rect);
+ button.state = QStyle::State_Enabled | QStyle::State_MouseOver;
+ if (lmbPressedOnButton)
+ button.state |= QStyle::State_Sunken | QStyle::State_Active;
+
+ QApplication::style()->drawControl(
+ (mouseOverFullDataButton == index) ? QStyle::CE_PushButton : QStyle::CE_PushButtonLabel,
+ &button, painter);
+ }
+ }
+}
+
+bool SqlQueryItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
+{
+ switch (event->type())
+ {
+ case QEvent::MouseButtonDblClick:
+ if (isOverFullValueButton(option.rect, dynamic_cast<QMouseEvent*>(event)) && isLimited(index))
+ return true;
+
+ break;
+ case QEvent::MouseButtonPress:
+ {
+ if (isOverFullValueButton(option.rect, dynamic_cast<QMouseEvent*>(event)) && isLimited(index))
+ {
+ lmbPressedOnButton = true;
+ return true;
+ }
+
+ break;
+ }
+ case QEvent::MouseButtonRelease:
+ if (lmbPressedOnButton && isOverFullValueButton(option.rect, dynamic_cast<QMouseEvent*>(event)) && isLimited(index))
+ {
+ lmbPressedOnButton = false;
+ getItem(index)->loadFullData();
+ return true;
+ }
+ lmbPressedOnButton = false;
+ break;
+ case QEvent::MouseMove:
+ {
+ bool isOverButton = isOverFullValueButton(option.rect, dynamic_cast<QMouseEvent*>(event));
+ if (mouseOverFullDataButton.isValid() != isOverButton)
+ {
+ mouseOverFullDataButton = isOverButton ? index : QModelIndex();
+ dynamic_cast<SqlQueryModel*>(model)->getView()->update(index);
+ }
+
+ if (!isOverButton && showingFullButtonTooltip)
+ {
+ QToolTip::hideText();
+ showingFullButtonTooltip = false;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return QStyledItemDelegate::editorEvent(event, model, option, index);
+}
+
+bool SqlQueryItemDelegate::shouldLoadFullData(const QRect& rect, QMouseEvent* event, const QModelIndex& index)
+{
+ return shouldLoadFullData(rect, event->x(), event->y(), index);
+}
+
+bool SqlQueryItemDelegate::shouldLoadFullData(const QRect& rect, int x, int y, const QModelIndex& index)
+{
+ return isOverFullValueButton(rect, x, y) && isLimited(index);
+}
+
+void SqlQueryItemDelegate::mouseLeftIndex(const QModelIndex& index)
+{
+ if (mouseOverFullDataButton == index)
+ mouseOverFullDataButton = QModelIndex();
+}
+
+bool SqlQueryItemDelegate::isLimited(const QModelIndex& index)
+{
+ return index.data(SqlQueryItem::DataRole::LIMITED_VALUE).toBool();
+}
+
+bool SqlQueryItemDelegate::helpEvent(QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index)
+{
+ if (shouldLoadFullData(option.rect, event->x(), event->y(), index))
+ {
+ QToolTip::showText(view->mapToGlobal(event->pos() - QPoint(0, 15)), tr("Load remaining part of the value"));
+ showingFullButtonTooltip = true;
+ return true;
+ }
+
+ return QStyledItemDelegate::helpEvent(event, view, option, index);
}
QWidget* SqlQueryItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
@@ -98,32 +210,12 @@ void SqlQueryItemDelegate::setEditorData(QWidget* editor, const QModelIndex& ind
void SqlQueryItemDelegate::setEditorDataForFk(QComboBox* cb, const QModelIndex& index) const
{
- const SqlQueryModel* queryModel = dynamic_cast<const SqlQueryModel*>(index.model());
- SqlQueryItem* item = queryModel->itemFromIndex(index);
- QVariant modelData = item->getValue();
-
- SqlQueryModel* cbModel = dynamic_cast<SqlQueryModel*>(cb->model());
- SqlQueryItem* foundItem = cbModel->findAnyInColumn(0, SqlQueryItem::DataRole::VALUE, modelData);
- int idx = -1;
- if (foundItem)
- idx = foundItem->index().row();
-
- if (idx == -1 && modelData.isValid())
- {
- idx = 0;
- QList<QVariant> values;
- values << modelData;
- for (int i = 1; i < cbModel->columnCount(); i++)
- values << QVariant();
-
- cbModel->insertCustomRow(values, idx);
-
- SqlQueryView* view = dynamic_cast<SqlQueryView*>(cb->view());
- view->resizeColumnsToContents();
- view->setMinimumWidth(view->horizontalHeader()->length());
- }
- cb->setCurrentIndex(idx);
- cb->lineEdit()->selectAll();
+ UNUSED(cb);
+ UNUSED(index);
+ // There used to be code here, but it's empty now.
+ // All necessary data population happens in the fkDataReady().
+ // Keeping this method just for this comment and for consistency across different kind of cell editors
+ // (i.e. each editor has method to copy value from model to editor and another to copy from editor to model).
}
void SqlQueryItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
@@ -148,31 +240,59 @@ void SqlQueryItemDelegate::setModelDataForFk(QComboBox* cb, QAbstractItemModel*
if (cbModel->isExecutionInProgress() || !cbModel->isAllDataLoaded())
return;
+ int idx = cb->currentIndex();
+ QModelIndex cbCol0Index = cbModel->index(idx, 0);
QString cbText = cb->currentText();
+ bool customValue = false;
+
+ if (cb->currentIndex() > -1 && !cbModel->itemFromIndex(cbCol0Index))
+ {
+ // Inserted QStandardItem by QComboBox, meaning custom value (out of dropdown model)
+ // With Qt 5.15 (maybe earlier) QComboBox started inserting QStandardItems and setting them as currentIndex.
+ // Here we're extracting this inserted value and remembering this is the custom value.
+ cbText = cbModel->data(cbCol0Index).toString();
+ customValue = true;
+ }
+
+ // Regardless if its preselected value or custom value, we need to honor empty=null setting
if (CFG_UI.General.KeepNullWhenEmptyValue.get() && model->data(index, Qt::EditRole).isNull() && cbText.isEmpty())
return;
- int idx = cb->currentIndex();
- if (idx < 0 || idx >= cbModel->rowCount())
+ SqlQueryModel* dataModel = dynamic_cast<SqlQueryModel*>(model);
+ SqlQueryItem* theItem = dataModel->itemFromIndex(index);
+
+ // If the item of the main data model cannot be found, we use plain QStandardItem method to set item's value.
+ // It's a safety circuit breaker. Shouldn't happend and if does so, it prints Critical debug log.
+ if (!theItem)
{
+ qCritical() << "Confirmed FK edition, but there is no SqlQueryItem for which this was triggered!" << index;
model->setData(index, cbText, Qt::EditRole);
return;
}
+ // Out of index? So it's custom value. Set it and it's done.
+ // If we deal with custom value inserted as item, we also just set it and that's it.
+ if (idx < 0 || idx >= cbModel->rowCount() || customValue)
+ {
+ theItem->setValue(cbText);
+ return;
+ }
+
+ // Otherwise we will have at least 2 columns. 1st column is hidden and is meta-column holding 1/0 (1 for value matching current cell value)
QList<SqlQueryItem *> row = cbModel->getRow(idx);
- if (!row[0])
+ if (row.size() < 2 || !row[1])
{
// This happens when inexisting value is confirmed with "Enter" key,
- // cause rowCount() is apparently incremented, but items not yet.
- model->setData(index, cbText, Qt::EditRole);
+ // and rowCount() is apparently incremented, but items not yet.
+ // Very likely this was addressed in recent Qt versions (5.15 or a bit earlier)
+ // which resulted in value insertion and the "customValue" flag above in this method.
+ qCritical() << "Confirmed FK edition, but there is no combo item in the row for index" << idx << ", the item is" << theItem << ", CB row count is" << cbModel->rowCount();
+ theItem->setValue(cbText);
return;
}
- QVariant comboData = row[0]->getValue();
- if (cbText != comboData.toString())
- comboData = cbText;
-
- model->setData(index, comboData, Qt::EditRole);
+ QVariant comboData = row[1]->getFullValue();
+ theItem->setValue(comboData);
}
void SqlQueryItemDelegate::setModelDataForLineEdit(QLineEdit* editor, QAbstractItemModel* model, const QModelIndex& index) const
@@ -237,24 +357,22 @@ QWidget* SqlQueryItemDelegate::getEditor(int type, QWidget* parent) const
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 %1 FROM %2%3");
- static_qstring(srcColTpl, "%1 AS %2");
- static_qstring(dbColTpl, "%1.%2 AS %3");
+ 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");
- static_qstring(cellLimitTpl, "substr(%2, 0, %1)");
QStringList selectedCols;
- QStringList fkConfitionTables;
+ QStringList fkConditionTables;
QStringList fkConditionCols;
QStringList srcCols;
Db* db = item->getModel()->getDb();
- Dialect dialect = db->getDialect();
SchemaResolver resolver(db);
QList<SqlQueryModelColumn::ConstraintFk*> fkList = item->getColumn()->getFkConstraints();
@@ -262,39 +380,46 @@ QString SqlQueryItemDelegate::getSqlForFkEditor(SqlQueryItem* item) const
QString src;
QString fullSrcCol;
QString col;
+ QString firstSrcCol;
+ QStringList usedNames;
for (SqlQueryModelColumn::ConstraintFk* fk : fkList)
{
- col = wrapObjIfNeeded(fk->foreignColumn, dialect);
- src = wrapObjIfNeeded(fk->foreignTable, dialect);
+ col = wrapObjIfNeeded(fk->foreignColumn);
+ src = wrapObjIfNeeded(fk->foreignTable);
if (i == 0)
{
- selectedCols << dbColTpl.arg(src, col,
- wrapObjIfNeeded(item->getColumn()->column, dialect));
+ 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 (const 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, dialect);
- selectedCols << srcColTpl.arg(cellLimitTpl.arg(CELL_LENGTH_LIMIT).arg(fullSrcCol), wrapObjName(fullSrcCol, dialect));
+ fullSrcCol = src + "." + wrapObjIfNeeded(srcCol);
+ selectedCols << fullSrcCol;
+ usedNames << srcCol;
}
fkConditionCols << col;
- fkConfitionTables << src;
+ fkConditionTables << src;
i++;
}
QStringList conditions;
- QString firstSrc = wrapObjIfNeeded(fkConfitionTables.first(), dialect);
- QString firstCol = wrapObjIfNeeded(fkConditionCols.first(), dialect);
- for (i = 1; i < fkConfitionTables.size(); i++)
+ QString firstSrc = fkConditionTables.first();
+ QString firstCol = fkConditionCols.first();
+ for (i = 1; i < fkConditionTables.size(); i++)
{
- src = wrapObjIfNeeded(fkConfitionTables[i], dialect);
- col = wrapObjIfNeeded(fkConditionCols[i], dialect);
+ src = fkConditionTables[i];
+ col = fkConditionCols[i];
conditions << conditionTpl.arg(firstSrc, firstCol, src, col);
}
@@ -303,7 +428,19 @@ QString SqlQueryItemDelegate::getSqlForFkEditor(SqlQueryItem* item) const
conditionsStr = conditionPrefixTpl.arg(conditions.join(", "));
}
- return sql.arg(selectedCols.join(", "), fkConfitionTables.join(", "), conditionsStr);
+ // Current value column (will be 1 for row which matches current cell value)
+ QVariant fullValue = item->getFullValue();
+ QString currValueColName = generateUniqueName("curr", usedNames);
+ QString currValueExpr = fullValue.isNull() ?
+ currNullValueTpl.arg(firstSrcCol, currValueColName) :
+ currValueTpl.arg(firstSrcCol, wrapValueIfNeeded(fullValue), currValueColName);
+
+ return sql.arg(
+ selectedCols.join(", "),
+ fkConditionTables.join(", "),
+ conditionsStr,
+ currValueExpr
+ );
}
qlonglong SqlQueryItemDelegate::getRowCountForFkEditor(Db* db, const QString& query, bool* isError) const
@@ -318,42 +455,31 @@ qlonglong SqlQueryItemDelegate::getRowCountForFkEditor(Db* db, const QString& qu
return result->getSingleCell().toLongLong();
}
-void SqlQueryItemDelegate::fkDataReady()
+QRect SqlQueryItemDelegate::getLoadFullValueButtonRegion(const QRect& cell)
{
- SqlQueryModel* model = dynamic_cast<SqlQueryModel*>(sender());
- SqlQueryView* queryView = model->getView();
-
- queryView->resizeColumnsToContents();
- queryView->resizeRowsToContents();
-
- int wd = queryView->horizontalHeader()->length();
- if (model->rowCount() > 10) // 10 is default visible item count for combobox
- wd += queryView->verticalScrollBar()->sizeHint().width();
-
- queryView->setMinimumWidth(wd);
-
- // Set selected combo value to initial value from the cell
- QComboBox* cb = modelToFkCombo[model];
- QVariant valueFromQueryModel = modelToFkInitialValue[model];
+ int x = cell.left() + cell.width() - LOAD_FULL_VALUE_BUTTON_SIZE - LOAD_FULL_VALUE_BUTTON_SIDE_MARGIN;
+ int y = cell.top() + (cell.height() / 2) - (LOAD_FULL_VALUE_BUTTON_SIZE / 2);
+ return QRect(x, y, LOAD_FULL_VALUE_BUTTON_SIZE, LOAD_FULL_VALUE_BUTTON_SIZE);
+}
- if (model->rowCount() > 0)
- {
- QModelIndex startIdx = model->index(0, 0);
- QModelIndex endIdx = model->index(model->rowCount() - 1, 0);
- QModelIndexList idxList = model->findIndexes(startIdx, endIdx, SqlQueryItem::DataRole::VALUE, valueFromQueryModel, 1);
+bool SqlQueryItemDelegate::isOverFullValueButton(const QRect& cell, QMouseEvent* event)
+{
+ return isOverFullValueButton(cell, event->x(), event->y());
+}
- if (idxList.size() > 0)
- cb->setCurrentIndex(idxList.first().row());
- else
- cb->setCurrentText(valueFromQueryModel.toString());
- }
- else
- cb->setCurrentText(valueFromQueryModel.toString());
+bool SqlQueryItemDelegate::isOverFullValueButton(const QRect& cell, int x, int y)
+{
+ QRect buttonRect = getLoadFullValueButtonRegion(cell);
+ return buttonRect.contains(x, y);
}
-void SqlQueryItemDelegate::fkDataFailed(const QString &errorText)
+int SqlQueryItemDelegate::getFkViewHeaderWidth(SqlQueryView* fkView, bool includeScrollBar) const
{
- notifyWarn(tr("Cannot edit this cell. Details: %1").arg(errorText));
+ int wd = fkView->horizontalHeader()->length();
+ if (includeScrollBar && fkView->verticalScrollBar()->isVisible())
+ wd += fkView->verticalScrollBar()->width();
+
+ return wd;
}
QWidget* SqlQueryItemDelegate::getFkEditor(SqlQueryItem* item, QWidget* parent, const SqlQueryModel* model) const
@@ -381,49 +507,164 @@ QWidget* SqlQueryItemDelegate::getFkEditor(SqlQueryItem* item, QWidget* parent,
cb->setEditable(true);
// Prepare combo dropdown view.
- SqlQueryView* queryView = new SqlQueryView();
- queryView->setSimpleBrowserMode(true);
- connect(queryView->horizontalHeader(), &QHeaderView::sectionResized, [queryView](int, int, int)
+ SqlQueryView* comboView = new SqlQueryView();
+ comboView->setSimpleBrowserMode(true);
+ comboView->setMaximumWidth(QGuiApplication::primaryScreen()->size().width());
+
+ fkViewParentItemSize = model->getView()->horizontalHeader()->sectionSize(item->index().column());
+ connect(comboView->horizontalHeader(), &QHeaderView::sectionResized, [this, comboView, model](int, int, int)
{
- int wd = queryView->horizontalHeader()->length();
- if (queryView->verticalScrollBar()->isVisible())
- wd += queryView->verticalScrollBar()->width();
+ if (!model->isAllDataLoaded())
+ return;
- queryView->setMinimumWidth(wd);
+ updateComboViewGeometry(comboView, false);
});
- SqlQueryModel* queryModel = new SqlQueryModel(queryView);
- queryModel->setView(queryView);
+ SqlQueryModel* comboModel = new SqlQueryModel(comboView);
+ comboModel->setView(comboView);
// Mapping of model to cb, so we can update combo when data arrives.
- modelToFkInitialValue[queryModel] = item->getValue();
- modelToFkCombo[queryModel] = cb;
- connect(cb, &QComboBox::destroyed, [this, queryModel](QObject*)
+ modelToFkInitialValue[comboModel] = item->getFullValue();
+ modelToFkCombo[comboModel] = cb;
+ connect(cb, &QComboBox::destroyed, [this, comboModel](QObject*)
+ {
+ modelToFkCombo.remove(comboModel);
+ modelToFkInitialValue.remove(comboModel);
+ });
+
+ connect(cb, QOverload<int>::of(&QComboBox::currentIndexChanged), [this, comboModel](int idx)
{
- modelToFkCombo.remove(queryModel);
- modelToFkInitialValue.remove(queryModel);
+ if (idx > -1 && idx < comboModel->getTotalRowsReturned() && comboModel->isAllDataLoaded())
+ comboModel->itemFromIndex(idx, 1)->loadFullData();
});
// When execution is done, update combo.
- connect(queryModel, SIGNAL(executionSuccessful()), this, SLOT(fkDataReady()));
- connect(queryModel, SIGNAL(executionFailed(QString)), this, SLOT(fkDataFailed(QString)));
+ connect(comboModel, SIGNAL(executionSuccessful()), this, SLOT(fkDataReady()));
+ connect(comboModel, SIGNAL(executionFailed(QString)), this, SLOT(fkDataFailed(QString)));
// Setup combo, model, etc.
- cb->setModel(queryModel);
- cb->setView(queryView);
- cb->setModelColumn(0);
+ cb->setModel(comboModel);
+ cb->setView(comboView);
+ cb->setModelColumn(1);
+ cb->view()->viewport()->installEventFilter(new FkComboFilter(this, comboView, cb));
+ cb->view()->viewport()->installEventFilter(new FkComboShowFilter(this, comboView, cb));
+ cb->view()->verticalScrollBar()->installEventFilter(new FkComboShowFilter(this, comboView, cb));
+
+ comboModel->setHardRowLimit(MAX_ROWS_FOR_FK);
+ comboModel->setCellDataLengthLimit(FK_CELL_LENGTH_LIMIT);
+ comboModel->setDb(db);
+ comboModel->setQuery(sql);
+ comboModel->setAsyncMode(false);
+ comboModel->executeQuery();
+
+ comboView->verticalHeader()->setVisible(false);
+ comboView->horizontalHeader()->setVisible(true);
+ comboView->setSelectionMode(QAbstractItemView::SingleSelection);
+ comboView->setSelectionBehavior(QAbstractItemView::SelectRows);
- queryModel->setHardRowLimit(MAX_ROWS_FOR_FK);
- queryModel->setDb(db);
- queryModel->setQuery(sql);
- queryModel->setAsyncMode(false);
- queryModel->executeQuery();
+ return cb;
+}
- queryView->verticalHeader()->setVisible(false);
- queryView->horizontalHeader()->setVisible(true);
- queryView->setSelectionMode(QAbstractItemView::SingleSelection);
- queryView->setSelectionBehavior(QAbstractItemView::SelectRows);
+void SqlQueryItemDelegate::fkDataReady()
+{
+ SqlQueryModel* model = dynamic_cast<SqlQueryModel*>(sender());
+ SqlQueryView* queryView = model->getView();
- return cb;
+ queryView->horizontalHeader()->setSectionHidden(0, true);
+ queryView->resizeColumnsToContents();
+ queryView->resizeRowsToContents();
+
+ updateComboViewGeometry(queryView, true);
+
+ // Set selected combo value to initial value from the cell
+ QComboBox* cb = modelToFkCombo[model];
+ QVariant valueFromQueryModel = modelToFkInitialValue[model];
+
+ if (model->rowCount() > 0)
+ {
+ QModelIndex startIdx = model->index(0, 0);
+ QModelIndex endIdx = model->index(model->rowCount() - 1, 0);
+ QModelIndexList idxList = model->findIndexes(startIdx, endIdx, SqlQueryItem::DataRole::VALUE, 1, 1);
+
+ if (idxList.size() > 0)
+ {
+ model->itemFromIndex(idxList.first().row(), 1)->loadFullData();
+ cb->setCurrentIndex(idxList.first().row());
+ }
+ else
+ {
+ cb->setCurrentIndex(-1);
+ cb->setEditText(valueFromQueryModel.toString());
+ }
+ }
+ else
+ cb->setEditText(valueFromQueryModel.toString());
+
+ cb->lineEdit()->selectAll();
+}
+
+void SqlQueryItemDelegate::fkDataFailed(const QString &errorText)
+{
+ notifyWarn(tr("Cannot edit this cell. Details: %1").arg(errorText));
}
+void SqlQueryItemDelegate::updateComboViewGeometry(SqlQueryView* comboView, bool initial) const
+{
+ int wd = getFkViewHeaderWidth(comboView, true);
+ comboView->setMinimumWidth(qMin(qMax(fkViewParentItemSize, wd), comboView->maximumWidth()));
+
+ if (initial && wd < comboView->minimumWidth())
+ {
+ // First time, upon showing up
+ int currentSize = comboView->horizontalHeader()->sectionSize(1);
+ int gap = comboView->minimumWidth() - wd;
+ comboView->horizontalHeader()->resizeSection(1, currentSize + gap);
+ }
+
+ QWidget* container = comboView->parentWidget();
+ if (container->width() > comboView->minimumWidth())
+ {
+ container->setMaximumWidth(comboView->minimumWidth());
+ container->resize(comboView->minimumWidth(), container->height());
+ }
+}
+
+
+SqlQueryItemDelegate::FkComboFilter::FkComboFilter(const SqlQueryItemDelegate* delegate, SqlQueryView* comboView, QObject* parent)
+ : QObject(parent), delegate(delegate), comboView(comboView)
+{
+}
+
+bool SqlQueryItemDelegate::FkComboFilter::eventFilter(QObject* obj, QEvent* event)
+{
+ UNUSED(obj);
+ if (event->type() == QEvent::MouseButtonRelease)
+ {
+ QMouseEvent* e = dynamic_cast<QMouseEvent*>(event);
+ QModelIndex idx = comboView->indexAt(QPoint(e->pos()));
+ if (!idx.isValid())
+ return false;
+
+ SqlQueryItem* item = comboView->getModel()->itemFromIndex(idx);
+ if (shouldLoadFullData(comboView->visualRect(idx), e, idx))
+ {
+ item->loadFullData();
+ return true;
+ }
+ }
+ return false;
+}
+
+SqlQueryItemDelegate::FkComboShowFilter::FkComboShowFilter(const SqlQueryItemDelegate* delegate, SqlQueryView* comboView, QObject* parent)
+ : QObject(parent), delegate(delegate), comboView(comboView)
+{
+}
+
+bool SqlQueryItemDelegate::FkComboShowFilter::eventFilter(QObject* obj, QEvent* event)
+{
+ UNUSED(obj);
+ if (event->type() == QEvent::Show)
+ delegate->updateComboViewGeometry(comboView, true);
+
+ return false;
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h
index a35ef9a..dbd2192 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryitemdelegate.h
@@ -10,6 +10,7 @@ class SqlQueryItem;
class QComboBox;
class QStandardItemModel;
class SqlQueryModel;
+class SqlQueryView;
class GUI_API_EXPORT SqlQueryItemDelegate : public QStyledItemDelegate
{
@@ -18,12 +19,44 @@ class GUI_API_EXPORT SqlQueryItemDelegate : public QStyledItemDelegate
explicit SqlQueryItemDelegate(QObject *parent = 0);
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
+ bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
+ bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index);
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, 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;
+ void mouseLeftIndex(const QModelIndex& index);
private:
+ class FkComboFilter : public QObject
+ {
+ public:
+ explicit FkComboFilter(const SqlQueryItemDelegate* delegate, SqlQueryView* comboView, QObject* parent = 0);
+ bool eventFilter(QObject *obj, QEvent *event);
+
+ private:
+ const SqlQueryItemDelegate* delegate = nullptr;
+ SqlQueryView* comboView = nullptr;
+ };
+
+ class FkComboShowFilter : public QObject
+ {
+ public:
+ explicit FkComboShowFilter(const SqlQueryItemDelegate* delegate, SqlQueryView* comboView, QObject* parent = 0);
+ bool eventFilter(QObject *obj, QEvent *event);
+
+ private:
+ const SqlQueryItemDelegate* delegate = nullptr;
+ SqlQueryView* comboView = nullptr;
+ };
+
+ static QRect getLoadFullValueButtonRegion(const QRect& cell);
+ static bool isOverFullValueButton(const QRect& cell, QMouseEvent* event);
+ static bool isOverFullValueButton(const QRect& cell, int x, int y);
+ static bool shouldLoadFullData(const QRect& rect, QMouseEvent* event, const QModelIndex& index);
+ static bool shouldLoadFullData(const QRect& rect, int x, int y, const QModelIndex& index);
+ static bool isLimited(const QModelIndex &index);
+
SqlQueryItem* getItem(const QModelIndex &index) const;
QWidget* getEditor(int type, QWidget* parent) const;
QWidget* getFkEditor(SqlQueryItem* item, QWidget* parent, const SqlQueryModel *model) const;
@@ -33,14 +66,24 @@ class GUI_API_EXPORT SqlQueryItemDelegate : public QStyledItemDelegate
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;
+ void updateComboViewGeometry(SqlQueryView* comboView, bool initial) const;
+ QStyleOptionButton fullValueButtonOption;
QSet<QWidget*> editorsWithAsyncExecution;
+ QModelIndex mouseOverFullDataButton;
+ bool showingFullButtonTooltip = false;
+ bool lmbPressedOnButton = false;
+ mutable int fkViewParentItemSize = 0;
mutable QHash<SqlQueryModel*, QComboBox*> modelToFkCombo;
mutable QHash<SqlQueryModel*, QVariant> modelToFkInitialValue;
static bool warnedAboutHugeContents;
+ static const int LOAD_FULL_VALUE_BUTTON_SIZE = 18;
+ static const int LOAD_FULL_VALUE_BUTTON_SIDE_MARGIN = 2;
+ static const int LOAD_FULL_VALUE_ICON_SIZE = 12;
static const qlonglong MAX_ROWS_FOR_FK = 10000L;
- static const int CELL_LENGTH_LIMIT = 30;
+ static const int FK_CELL_LENGTH_LIMIT = 30;
static const int HUGE_CONTENTS_WARNING_LIMIT = 32767; // pow(2, 16) / 2 - 1
private slots:
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp
index ff025df..dd3f655 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.cpp
@@ -12,6 +12,9 @@
#include "datagrid/sqlqueryrownummodel.h"
#include "services/dbmanager.h"
#include "querygenerator.h"
+#include "parser/lexer.h"
+#include "common/compatibility.h"
+#include "mainwindow.h"
#include <QHeaderView>
#include <QDebug>
#include <QApplication>
@@ -100,14 +103,14 @@ void SqlQueryModel::executeQueryInternal()
{
if (!db || !db->isValid())
{
- notifyWarn("Cannot execute query on undefined or invalid database.");
+ notifyWarn(tr("Cannot execute query on undefined or invalid database."));
internalExecutionStopped();
return;
}
- if (query.isEmpty())
+ if (isEmptyQuery())
{
- notifyWarn("Cannot execute empty query.");
+ notifyWarn(tr("Cannot execute empty query."));
internalExecutionStopped();
return;
}
@@ -138,6 +141,23 @@ void SqlQueryModel::executeQueryInternal()
queryExecutor->exec();
}
+bool SqlQueryModel::isEmptyQuery() const
+{
+ if (query.trimmed().isEmpty())
+ return true;
+
+ TokenList tokens = Lexer::tokenize(query);
+ auto foundIter = std::find_if(tokens.begin(), tokens.end(), [](const TokenPtr& token)
+ {
+ return token->isMeaningful();
+ });
+
+ if (foundIter != tokens.end())
+ return false;
+
+ return true;
+}
+
void SqlQueryModel::internalExecutionStopped()
{
reloading = false;
@@ -189,6 +209,12 @@ int SqlQueryModel::getCellDataLengthLimit()
return cellDataLengthLimit;
}
+void SqlQueryModel::setCellDataLengthLimit(int value)
+{
+ cellDataLengthLimit = value;
+ queryExecutor->setDataLengthLimit(value);
+}
+
QModelIndexList SqlQueryModel::findIndexes(int role, const QVariant& value, int hits) const
{
QModelIndex startIdx = index(0, 0);
@@ -258,6 +284,26 @@ QList<QList<SqlQueryItem*> > SqlQueryModel::groupItemsByRows(const QList<SqlQuer
return itemsByRow.values();
}
+QHash<AliasedTable, QVector<SqlQueryModelColumn*>> SqlQueryModel::groupColumnsByTable(const QVector<SqlQueryModelColumn*>& columns)
+{
+ QHash<AliasedTable, QVector<SqlQueryModelColumn*>> columnsByTable;
+ AliasedTable table;
+ for (SqlQueryModelColumn* col : columns)
+ {
+ if (!col->column.isNull())
+ {
+ table.setDatabase(col->database.toLower());
+ table.setTable(col->table.toLower());
+ table.setTableAlias(col->tableAlias.toLower());
+ columnsByTable[table] << col;
+ }
+ else
+ columnsByTable[AliasedTable()] << col;
+ }
+
+ return columnsByTable;
+}
+
QHash<AliasedTable, QList<SqlQueryItem*> > SqlQueryModel::groupItemsByTable(const QList<SqlQueryItem*>& items)
{
QHash<AliasedTable,QList<SqlQueryItem*>> itemsByTable;
@@ -325,7 +371,7 @@ void SqlQueryModel::commit(const QList<SqlQueryItem*>& items)
commitInternal(filterOutCommittedItems(items));
}
-bool SqlQueryModel::commitRow(const QList<SqlQueryItem*>& itemsInRow)
+bool SqlQueryModel::commitRow(const QList<SqlQueryItem*>& itemsInRow, QList<SqlQueryModel::CommitSuccessfulHandler>& successfulCommitHandlers)
{
const SqlQueryItem* item = itemsInRow.at(0);
if (!item)
@@ -334,11 +380,11 @@ bool SqlQueryModel::commitRow(const QList<SqlQueryItem*>& itemsInRow)
return true;
}
if (item->isNewRow())
- return commitAddedRow(getRow(item->row())); // we need to get all items again, in case of selective commit
+ return commitAddedRow(getRow(item->row()), successfulCommitHandlers); // we need to get all items again, in case of selective commit
else if (item->isDeletedRow())
- return commitDeletedRow(getRow(item->row())); // we need to get all items again, in case of selective commit
+ return commitDeletedRow(getRow(item->row()), successfulCommitHandlers); // we need to get all items again, in case of selective commit
else
- return commitEditedRow(itemsInRow);
+ return commitEditedRow(itemsInRow, successfulCommitHandlers);
}
void SqlQueryModel::rollbackRow(const QList<SqlQueryItem*>& itemsInRow)
@@ -357,6 +403,127 @@ void SqlQueryModel::rollbackRow(const QList<SqlQueryItem*>& itemsInRow)
rollbackEditedRow(itemsInRow);
}
+void SqlQueryModel::refreshGeneratedColumns(const QList<SqlQueryItem*>& items)
+{
+ QHash<SqlQueryItem*, QVariant> resultValues;
+ refreshGeneratedColumns(items, resultValues, RowId());
+ for (auto resultIt = resultValues.begin(); resultIt != resultValues.end(); resultIt++)
+ {
+ SqlQueryItem* item = resultIt.key();
+ item->setValue(resultIt.value(), false, true);
+ item->setTextAlignment(findValueAlignment(resultIt.value(), item->getColumn()));
+ }
+}
+
+void SqlQueryModel::refreshGeneratedColumns(const QList<SqlQueryItem*>& items, QHash<SqlQueryItem*, QVariant>& values, const RowId& insertedRowId)
+{
+ // Find out which columns are generated
+ int colIdx = 0;
+ QVector<SqlQueryModelColumn*> generatedColumns;
+ QHash<SqlQueryModelColumn*, int> generatedColumnIdx;
+ for (const SqlQueryModelColumnPtr& column : columns)
+ {
+ if (column->isGenerated())
+ {
+ generatedColumns << column.data();
+ generatedColumnIdx[column.data()] = colIdx;
+ }
+ colIdx++;
+ }
+ if (generatedColumns.isEmpty())
+ return;
+
+ QHash<AliasedTable, QVector<SqlQueryModelColumn*>> columnsByTable = groupColumnsByTable(generatedColumns);
+
+ // Filter out deleted items - we won't update generated values for them
+ QList<SqlQueryItem*> insertedOrAlteredItems = filter<SqlQueryItem*>(items, [&](SqlQueryItem* item) -> bool
+ {
+ if (item->isNewRow())
+ return !insertedRowId.isEmpty();
+
+ return !item->isDeletedRow();
+ });
+
+ SelectCellsQueryBuilder builder;
+ QHash<AliasedTable, QList<SqlQueryItem*>> itemsByTable = groupItemsByTable(insertedOrAlteredItems);
+ for (auto itemsIt = itemsByTable.begin(); itemsIt != itemsByTable.end(); itemsIt++)
+ {
+ const AliasedTable table = itemsIt.key();
+ QVector<SqlQueryModelColumn*> tableColumns = columnsByTable[table];
+ if (tableColumns.isEmpty())
+ continue;
+
+ builder.setDatabase(wrapObjIfNeeded(table.getDatabase()));
+ builder.setTable(wrapObjIfNeeded(table.getTable()));
+
+ QHash<RowId, QSet<SqlQueryItem*>> itemsPerRowId;
+ for (SqlQueryItem* item : itemsIt.value())
+ {
+ RowId rowId = insertedRowId.isEmpty() ? item->getRowId() : insertedRowId;
+ builder.addRowId(rowId);
+ for (SqlQueryModelColumn* tableCol : tableColumns)
+ itemsPerRowId[rowId] << itemFromIndex(item->row(), generatedColumnIdx[tableCol]);
+ }
+
+ for (SqlQueryModelColumn* tableCol : tableColumns)
+ builder.addColumn(tableCol->column);
+
+ unite(values, readCellValues(builder, itemsPerRowId));
+ builder.clear();
+ }
+}
+
+QHash<SqlQueryItem*, QVariant> SqlQueryModel::readCellValues(SelectCellsQueryBuilder& queryBuilder, const QHash<RowId, QSet<SqlQueryItem*>>& itemsPerRowId)
+{
+ QHash<SqlQueryItem*, QVariant> values;
+
+ // Executing query
+ SqlQueryPtr results = db->exec(queryBuilder.build(), queryBuilder.getQueryArgs(), Db::Flag::PRELOAD);
+
+ // Handling error
+ if (results->isError())
+ {
+ qCritical() << "Could not load cell values for table" << queryBuilder.getTable() << ", so defaulting them with NULL. Error from database was:"
+ << results->getErrorText();
+
+ for (SqlQueryItem* item : concatSet(itemsPerRowId.values()))
+ values[item] = QVariant();
+
+ return values;
+ }
+
+ if (!results->hasNext())
+ {
+ qCritical() << "Could not load cell values for table" << queryBuilder.getTable() << ", so defaulting them with NULL. There were no result rows.";
+
+ for (SqlQueryItem* item : concatSet(itemsPerRowId.values()))
+ values[item] = QVariant();
+
+ return values;
+ }
+
+ // Reading a row
+ while (results->hasNext())
+ {
+ SqlResultsRowPtr row = results->next();
+ if (row->valueList().size() != queryBuilder.getColumnCount())
+ {
+ qCritical() << "Could not load cell values for table" << queryBuilder.getTable() << ", so defaulting them with NULL. Number of columns from results was invalid:"
+ << row->valueList().size() << ", while expected:" << queryBuilder.getColumnCount();
+
+ for (SqlQueryItem* item : concatSet(itemsPerRowId.values()))
+ values[item] = QVariant();
+
+ return values;
+ }
+
+ for (SqlQueryItem* item : itemsPerRowId[queryBuilder.readRowId(row)])
+ values[item] = row->value(item->getColumn()->column);
+ }
+
+ return values;
+}
+
void SqlQueryModel::rollback()
{
QList<SqlQueryItem*> items = findItems(SqlQueryItem::DataRole::UNCOMMITTED, true);
@@ -399,14 +566,13 @@ void SqlQueryModel::commitInternal(const QList<SqlQueryItem*>& items)
int step = 1;
rowsDeletedSuccessfullyInTheCommit.clear();
+ QList<CommitSuccessfulHandler> successfulCommitHandlers; // list of lambdas to execute after all rows were committed successfully
bool ok = true;
for (const QList<SqlQueryItem*>& itemsInRow : groupedItems)
{
- if (!commitRow(itemsInRow))
- {
+ if (!commitRow(itemsInRow, successfulCommitHandlers))
ok = false;
- break;
- }
+
emit committingStepFinished(step++);
}
@@ -431,6 +597,13 @@ void SqlQueryModel::commitInternal(const QList<SqlQueryItem*>& items)
}
else
{
+ // Call all successfull commit handler to refresh cell metadata, etc.
+ for (CommitSuccessfulHandler& handler : successfulCommitHandlers)
+ handler();
+
+ // Refresh generated columns of altered rows
+ refreshGeneratedColumns(itemsLeft);
+
// Committed successfully
for (SqlQueryItem* item : itemsLeft)
{
@@ -438,7 +611,8 @@ void SqlQueryModel::commitInternal(const QList<SqlQueryItem*>& items)
item->setNewRow(false);
}
- qSort(rowsDeletedSuccessfullyInTheCommit);
+ // Physically delete rows
+ std::sort(rowsDeletedSuccessfullyInTheCommit.begin(), rowsDeletedSuccessfullyInTheCommit.end());
int removeOffset = 0;
for (int row : rowsDeletedSuccessfullyInTheCommit)
removeRow(row - removeOffset++); // deleting row decrements all rows below
@@ -585,13 +759,14 @@ int SqlQueryModel::getCurrentPage(bool includeOneBeingLoaded) const
return result < 0 ? 0 : result;
}
-bool SqlQueryModel::commitAddedRow(const QList<SqlQueryItem*>& itemsInRow)
+bool SqlQueryModel::commitAddedRow(const QList<SqlQueryItem*>& itemsInRow, QList<SqlQueryModel::CommitSuccessfulHandler>& successfulCommitHandlers)
{
UNUSED(itemsInRow);
+ UNUSED(successfulCommitHandlers);
return false;
}
-bool SqlQueryModel::commitEditedRow(const QList<SqlQueryItem*>& itemsInRow)
+bool SqlQueryModel::commitEditedRow(const QList<SqlQueryItem*>& itemsInRow, QList<SqlQueryModel::CommitSuccessfulHandler>& successfulCommitHandlers)
{
if (itemsInRow.size() == 0)
{
@@ -599,8 +774,6 @@ bool SqlQueryModel::commitEditedRow(const QList<SqlQueryItem*>& itemsInRow)
return true;
}
- Dialect dialect = db->getDialect();
-
QHash<AliasedTable,QList<SqlQueryItem*>> itemsByTable = groupItemsByTable(itemsInRow);
// Values
@@ -631,15 +804,15 @@ bool SqlQueryModel::commitEditedRow(const QList<SqlQueryItem*>& itemsInRow)
// RowId
queryBuilder.clear();
rowId = items.first()->getRowId();
- queryBuilder.setRowId(rowId, dialect);
+ queryBuilder.setRowId(rowId);
newRowId = getNewRowId(rowId, items); // if any of item updates any of rowid columns, then this will be different than initial rowid
// Database and table
- queryBuilder.setTable(wrapObjIfNeeded(table.getTable(), dialect));
+ queryBuilder.setTable(wrapObjIfNeeded(table.getTable()));
if (!table.getDatabase().isNull())
{
QString tableDb = getDatabaseForCommit(table.getDatabase());
- queryBuilder.setDatabase(wrapObjIfNeeded(tableDb, dialect));
+ queryBuilder.setDatabase(wrapObjIfNeeded(tableDb));
}
for (SqlQueryItem* item : items)
@@ -647,12 +820,14 @@ bool SqlQueryModel::commitEditedRow(const QList<SqlQueryItem*>& itemsInRow)
col = item->getColumn();
if (col->editionForbiddenReason.size() > 0 || item->isJustInsertedWithOutRowId())
{
- notifyError(tr("Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it."));
+ QString errMsg = tr("Tried to commit a cell which is not editable (yet modified and waiting for commit)! This is a bug. Please report it.");
+ item->setCommittingError(true, errMsg);
+ notifyError(errMsg);
return false;
}
// Column
- queryBuilder.addColumn(wrapObjIfNeeded(col->column, dialect));
+ queryBuilder.addColumn(wrapObjIfNeeded(col->column));
}
// Completing query
@@ -670,23 +845,31 @@ bool SqlQueryModel::commitEditedRow(const QList<SqlQueryItem*>& itemsInRow)
SqlQueryPtr results = db->exec(query, queryArgs);
if (results->isError())
{
+ QString errMsg = tr("An error occurred while committing the data: %1").arg(results->getErrorText());
for (SqlQueryItem* item : items)
- item->setCommittingError(true);
+ item->setCommittingError(true, errMsg);
- notifyError(tr("An error occurred while committing the data: %1").arg(results->getErrorText()));
+ notifyError(errMsg);
return false;
}
// After successful commit, check if RowId was modified and upadate it accordingly
if (rowId != newRowId)
- updateRowIdForAllItems(table, rowId, newRowId);
+ {
+ // ...and do it with deferred lambda, so only after all rows were successully committed
+ successfulCommitHandlers << [this, table, rowId, newRowId]()
+ {
+ updateRowIdForAllItems(table, rowId, newRowId);
+ };
+ }
}
return true;
}
-bool SqlQueryModel::commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow)
+bool SqlQueryModel::commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow, QList<SqlQueryModel::CommitSuccessfulHandler>& successfulCommitHandlers)
{
+ UNUSED(successfulCommitHandlers);
if (itemsInRow.size() == 0)
{
qCritical() << "No items passed to SqlQueryModel::commitDeletedRow().";
@@ -766,7 +949,7 @@ bool SqlQueryModel::loadData(SqlQueryPtr results)
view->horizontalHeader()->show();
// Read columns first. It will be needed later.
- readColumns();
+ bool rowsLimited = readColumns();
// Load data
SqlResultsRowPtr row;
@@ -782,7 +965,7 @@ bool SqlQueryModel::loadData(SqlQueryPtr results)
if (!row)
break;
- rowList << loadRow(row);
+ rowList << loadRow(row, results);
if ((rowIdx % 50) == 0)
{
@@ -794,6 +977,12 @@ bool SqlQueryModel::loadData(SqlQueryPtr results)
rowIdx++;
}
+ if (rowsLimited && rowIdx >= columnRatioBasedRowLimit)
+ {
+ NOTIFY_MANAGER->info(tr("Number of rows per page was decreased to %1 due to number of columns (%2) in the data view.")
+ .arg(columnRatioBasedRowLimit).arg(columns.size()));
+ }
+
rowIdx = 0;
for (const QList<QStandardItem*>& row : rowList)
insertRow(rowIdx++, row);
@@ -802,8 +991,11 @@ bool SqlQueryModel::loadData(SqlQueryPtr results)
return true;
}
-QList<QStandardItem*> SqlQueryModel::loadRow(SqlResultsRowPtr row)
+QList<QStandardItem*> SqlQueryModel::loadRow(SqlResultsRowPtr row, SqlQueryPtr results)
{
+ QStringList columnNames = results->getColumnNames();
+ BiStrHash typeColumnToResColumn = queryExecutor->getTypeColumns();
+
QList<QStandardItem*> itemList;
SqlQueryItem* item = nullptr;
RowId rowId;
@@ -812,7 +1004,7 @@ QList<QStandardItem*> SqlQueryModel::loadRow(SqlResultsRowPtr row)
{
item = new SqlQueryItem();
rowId = getRowIdValue(row, colIdx);
- updateItem(item, value, colIdx, rowId);
+ updateItem(item, value, colIdx, rowId, row, columnNames, typeColumnToResColumn);
itemList << item;
colIdx++;
}
@@ -847,15 +1039,54 @@ RowId SqlQueryModel::getRowIdValue(SqlResultsRowPtr row, int columnIdx)
return rowId;
}
+
+void SqlQueryModel::updateItem(SqlQueryItem* item, const QVariant& value, int columnIndex, const RowId& rowId, SqlResultsRowPtr row,
+ const QStringList& columnNames, const BiStrHash& typeColumnToResColumn)
+{
+ if (columnIndex >= columnNames.size())
+ {
+ updateItem(item, value, columnIndex, rowId);
+ return;
+ }
+
+ QString colName = columnNames[columnIndex];
+ if (typeColumnToResColumn.isEmpty() || !typeColumnToResColumn.containsRight(colName))
+ {
+ updateItem(item, value, columnIndex, rowId);
+ return;
+ }
+
+ QString colTypeColumnName = typeColumnToResColumn.valueByRight(colName);
+ QString colTypeStr = row->value(colTypeColumnName).toString();
+ SqliteDataType sqliteDataType = toSqliteDataType(colTypeStr);
+
+ switch (sqliteDataType)
+ {
+ case SqliteDataType::INTEGER:
+ case SqliteDataType::REAL:
+ updateItem(item, value, columnIndex, rowId, Qt::AlignRight);
+ break;
+ case SqliteDataType::_NULL:
+ case SqliteDataType::TEXT:
+ case SqliteDataType::BLOB:
+ updateItem(item, value, columnIndex, rowId, Qt::AlignLeft);
+ break;
+ case SqliteDataType::UNKNOWN:
+ updateItem(item, value, columnIndex, rowId);
+ break;
+ }
+}
+
void SqlQueryModel::updateItem(SqlQueryItem* item, const QVariant& value, int columnIndex, const RowId& rowId)
{
SqlQueryModelColumnPtr column = columns[columnIndex];
- Qt::Alignment alignment;
+ Qt::Alignment alignment = findValueAlignment(value, column.data());
+ updateItem(item, value, columnIndex, rowId, alignment);
+}
- if (column->isNumeric() && isNumeric(value))
- alignment = Qt::AlignRight|Qt::AlignVCenter;
- else
- alignment = Qt::AlignLeft|Qt::AlignVCenter;
+void SqlQueryModel::updateItem(SqlQueryItem* item, const QVariant& value, int columnIndex, const RowId& rowId, Qt::Alignment alignment)
+{
+ SqlQueryModelColumnPtr column = columns[columnIndex];
// This should be equal at most, unless we have UTF-8 string, than there might be more bytes.
// If less, than it's not limited.
@@ -868,6 +1099,14 @@ void SqlQueryModel::updateItem(SqlQueryItem* item, const QVariant& value, int co
item->setRowId(rowId);
}
+Qt::Alignment SqlQueryModel::findValueAlignment(const QVariant& value, SqlQueryModelColumn* column)
+{
+ if ((column->isNumeric() || column->isNull()) && isNumeric(value))
+ return Qt::AlignRight|Qt::AlignVCenter;
+ else
+ return Qt::AlignLeft|Qt::AlignVCenter;
+}
+
RowId SqlQueryModel::getNewRowId(const RowId& currentRowId, const QList<SqlQueryItem*> items)
{
if (currentRowId.size() > 1)
@@ -941,7 +1180,7 @@ bool SqlQueryModel::supportsModifyingQueriesInMenu() const
return false;
}
-void SqlQueryModel::readColumns()
+bool SqlQueryModel::readColumns()
{
columns.clear();
tableToRowIdColumn.clear();
@@ -980,15 +1219,15 @@ void SqlQueryModel::readColumns()
// Rows limit to avoid out of memory problems
columnRatioBasedRowLimit = -1;
int rowsPerPage = getRowsPerPage();
- if (!columns.isEmpty())
- columnRatioBasedRowLimit = 150000 / columns.size();
+ if (!columns.isEmpty() && CFG_UI.General.LimitRowsForManyColumns.get())
+ columnRatioBasedRowLimit = 50000 / columns.size();
- if (columnRatioBasedRowLimit > -1 && columnRatioBasedRowLimit < rowsPerPage)
- NOTIFY_MANAGER->info(tr("Number of rows per page was decreased to %1 due to number of columns (%2) in the data view.")
- .arg(columnRatioBasedRowLimit).arg(columns.size()));
+ bool rowsLimited = (columnRatioBasedRowLimit > -1 && columnRatioBasedRowLimit < rowsPerPage);
// We have fresh info about columns
structureOutOfDate = false;
+
+ return rowsLimited;
}
void SqlQueryModel::readColumnDetails()
@@ -1037,6 +1276,8 @@ void SqlQueryModel::readColumnDetails()
modelConstraint = SqlQueryModelColumn::Constraint::create(constrPtr);
if (modelConstraint)
modelColumn->constraints << modelConstraint;
+
+ modelColumn->postProcessConstraints();
}
// Table constraints
@@ -1060,7 +1301,6 @@ QHash<AliasedTable, SqlQueryModel::TableDetails> SqlQueryModel::readTableDetails
QHash<AliasedTable, TableDetails> results;
SqliteQueryPtr query;
SqliteCreateTablePtr createTable;
- Dialect dialect = db->getDialect();
SchemaResolver resolver(getDb());
QString database;
AliasedTable table;
@@ -1092,7 +1332,7 @@ QHash<AliasedTable, SqlQueryModel::TableDetails> SqlQueryModel::readTableDetails
{
// Column details
TableDetails::ColumnDetails columnDetails;
- columnName = stripObjName(columnStmt->name, dialect);
+ columnName = stripObjName(columnStmt->name);
// Column type
if (columnStmt->type)
@@ -1229,9 +1469,14 @@ void SqlQueryModel::handleExecFailed(int code, QString errorMessage)
void SqlQueryModel::resultsCountingFinished(quint64 rowsAffected, quint64 rowsReturned, int totalPages)
{
+ // TotalPages provided by QueryExecutor is wrong if there are tons of columns in results, as row limit is applied
+ // to prevent memory exhaustion. QueryExecutor is not aware of the limit at the moment of execution, so it calculates
+ // total number of pages incorrectly.
+ UNUSED(totalPages);
+
this->rowsAffected = rowsAffected;
this->totalRowsReturned = rowsReturned;
- this->totalPages = totalPages;
+ this->totalPages = (int)qCeil(((double)totalRowsReturned) / ((double)getRowsPerPage()));
detachDatabases();
emit totalRowsAndPagesAvailable();
emit storeExecutionInHistory();
@@ -1356,9 +1601,10 @@ void SqlQueryModel::storeStep1NumbersFromExecution()
if (!queryExecutor->getSkipRowCounting())
{
- totalPages = queryExecutor->getTotalPages();
if (!queryExecutor->isRowCountingRequired())
totalRowsReturned = queryExecutor->getTotalRowsReturned();
+
+ totalPages = (int)qCeil(((double)totalRowsReturned) / ((double)getRowsPerPage()));
}
}
@@ -1572,7 +1818,7 @@ int SqlQueryModel::getRowsPerPage() const
if (hardRowLimit > -1)
rowsPerPage = hardRowLimit;
- if (columnRatioBasedRowLimit > -1 && columnRatioBasedRowLimit < rowsPerPage)
+ if (CFG_UI.General.LimitRowsForManyColumns.get() && columnRatioBasedRowLimit > -1 && columnRatioBasedRowLimit < rowsPerPage)
rowsPerPage = columnRatioBasedRowLimit;
return rowsPerPage;
@@ -1611,7 +1857,7 @@ void SqlQueryModel::setDesiredColumnWidth(int colIdx, int width)
return;
}
- Column column(columnModel->database, columnModel->table, columnModel->column);
+ AliasedColumn column(columnModel->database, columnModel->table, columnModel->column, columnModel->displayName);
columnWidths[column] = width;
}
@@ -1621,7 +1867,7 @@ int SqlQueryModel::getDesiredColumnWidth(int colIdx)
if (!columnModel)
return -1;
- Column column(columnModel->database, columnModel->table, columnModel->column);
+ AliasedColumn column(columnModel->database, columnModel->table, columnModel->column, columnModel->displayName);
if (!columnWidths.contains(column))
return -1;
@@ -1683,11 +1929,20 @@ void SqlQueryModel::deleteSelectedRows()
{
QList<SqlQueryItem*> selectedItems = view->getSelectedItems();
QSet<int> rows;
+ QSet<int> newRows;
for (SqlQueryItem* item : selectedItems)
- rows << item->index().row();
+ {
+ int row = item->index().row();
+ if (item->isNewRow())
+ newRows << row;
+
+ rows << row;
+ }
- QList<int> rowList = rows.toList();
- qSort(rowList);
+ QList<int> rowList = rows.values();
+ QList<int> newRowList = newRows.values();
+ sSort(rowList);
+ sSort(newRowList);
QList<SqlQueryItem*> newItemsToDelete;
int cols = columnCount();
@@ -1707,8 +1962,25 @@ void SqlQueryModel::deleteSelectedRows()
}
}
- for (SqlQueryItem* item : newItemsToDelete)
- removeRow(item->index().row());
+ if (newItemsToDelete.size() > 0)
+ {
+ QStringList rowNumbers;
+ int rowBase = getRowsPerPage() * getCurrentPage();
+ for (int row : newRowList)
+ rowNumbers << QString::number(rowBase + row + 1); // +1 for visual representation of row, which in code is 0-based
+
+ QMessageBox::StandardButton userResponse = QMessageBox::question(MAINWINDOW, tr("Delete rows"),
+ tr("You're about to delete newly inserted rows that are not committed yet. Row numbers: %1\n"
+ "Such deletion will be permanent. Are you sure you want to delete them?")
+ .arg(rowNumbers.join(", ")));
+
+ if (userResponse == QMessageBox::Yes)
+ {
+ for (SqlQueryItem* item : newItemsToDelete)
+ removeRow(item->index().row());
+ }
+ }
+
emit commitStatusChanged(getUncommittedItems().size() > 0);
}
@@ -1832,6 +2104,39 @@ void SqlQueryModel::loadFullDataForEntireRow(int row)
}
}
+void SqlQueryModel::loadFullDataForEntireColumn(int column)
+{
+ int rowCnt = rowCount();
+ SqlQueryItem *item = nullptr;
+ for (int row = 0; row < rowCnt; row++)
+ {
+ item = itemFromIndex(row, column);
+ if (!item)
+ continue;
+
+ if (!item->isLimitedValue())
+ continue;
+
+ item->loadFullData();
+ }
+}
+
+bool SqlQueryModel::doesColumnHaveLimitedValues(int column) const
+{
+ int rowCnt = rowCount();
+ SqlQueryItem *item = nullptr;
+ for (int row = 0; row < rowCnt; row++)
+ {
+ item = itemFromIndex(row, column);
+ if (!item)
+ continue;
+
+ if (item->isLimitedValue())
+ return true;
+ }
+ return false;
+}
+
void SqlQueryModel::CommitUpdateQueryBuilder::clear()
{
database.clear();
@@ -1889,3 +2194,115 @@ QStringList SqlQueryModel::CommitUpdateQueryBuilder::getAssignmentArgs() const
{
return assignmentArgs;
}
+
+void SqlQueryModel::SelectCellsQueryBuilder::addRowId(const RowId& rowId)
+{
+ if (includedRowIds.contains(rowId))
+ return;
+
+ static_qstring(argTempalate, ":rowIdArg%1");
+
+ QStringList parts;
+ QString arg;
+ QHashIterator<QString,QVariant> it(rowId);
+ while (it.hasNext())
+ {
+ it.next();
+ arg = argTempalate.arg(argSquence++);
+ queryArgs[arg] = it.value();
+ parts << wrapObjIfNeeded(it.key()) + " = " + arg;
+ }
+ conditions << parts.join(" AND ");
+
+ if (rowIdColumns.isEmpty())
+ {
+ rowIdColumns = toSet(rowId.keys());
+ for (const QString& col : rowIdColumns)
+ columns << wrapObjIfNeeded(col);
+ }
+
+ includedRowIds << rowId;
+}
+
+QString SqlQueryModel::SelectCellsQueryBuilder::build()
+{
+ QString conditionsString = conditions.join(" OR ");
+
+ QString dbAndTable;
+ if (!database.isNull())
+ dbAndTable += database + ".";
+
+ dbAndTable += table;
+
+ QStringList selectColumns;
+ for (const QString& col : columns)
+ {
+ // Explicit "ROWID" alias, because - if ROWID column
+ // is the INTEGER PRIMARY KEY column - SQLite reports
+ // column name as its table column name and it does not
+ // match the RowId columns when requested in #readRowId().
+ if (col.toUpper() == "ROWID")
+ selectColumns << "ROWID AS ROWID";
+ else
+ selectColumns << col;
+ }
+
+
+ static_qstring(sql, "SELECT %1 FROM %2 WHERE %3;");
+ return sql.arg(
+ selectColumns.join(", "),
+ dbAndTable,
+ conditionsString
+ );
+}
+
+void SqlQueryModel::SelectCellsQueryBuilder::clear()
+{
+ database = QString();
+ table = QString();
+ rowIdColumns.clear();
+ columns.clear();
+ conditions.clear();
+ queryArgs.clear();
+ includedRowIds.clear();
+ argSquence = 0;
+}
+
+void SqlQueryModel::SelectCellsQueryBuilder::setDatabase(const QString& database)
+{
+ this->database = database;
+}
+
+void SqlQueryModel::SelectCellsQueryBuilder::setTable(const QString& table)
+{
+ this->table = table;
+}
+
+void SqlQueryModel::SelectCellsQueryBuilder::addColumn(const QString& column)
+{
+ this->columns << column;
+}
+
+RowId SqlQueryModel::SelectCellsQueryBuilder::readRowId(SqlResultsRowPtr row) const
+{
+ RowId rowId;
+ for (const QString& column : rowIdColumns)
+ rowId[column] = row->value(column);
+
+ return rowId;
+}
+
+int SqlQueryModel::SelectCellsQueryBuilder::getColumnCount() const
+{
+ return columns.size();
+}
+
+QString SqlQueryModel::SelectCellsQueryBuilder::getTable() const
+{
+ return table;
+}
+
+QString SqlQueryModel::SelectCellsQueryBuilder::getDatabase() const
+{
+ return database;
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h
index 6c17740..9a89205 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodel.h
@@ -31,13 +31,14 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
};
Q_DECLARE_FLAGS(Features, Feature)
+ typedef std::function<void()> CommitSuccessfulHandler;
+
friend class SqlQueryItemDelegate;
explicit SqlQueryModel(QObject *parent = 0);
virtual ~SqlQueryModel();
static void staticInit();
- static int getCellDataLengthLimit();
QString getQuery() const;
void setQuery(const QString &value);
@@ -63,6 +64,8 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
bool isExecutionInProgress() const;
void loadFullDataForEntireRow(int row);
+ void loadFullDataForEntireColumn(int column);
+ bool doesColumnHaveLimitedValues(int column) const;
StrHash<QString> attachDependencyTables();
void detachDependencyTables();
@@ -143,6 +146,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
void gotoPage(int newPage);
bool canReload();
virtual bool supportsModifyingQueriesInMenu() const;
+ Qt::Alignment findValueAlignment(const QVariant& value, SqlQueryModelColumn* column);
QueryExecutor::SortList getSortOrder() const;
void setSortOrder(const QueryExecutor::SortList& newSortOrder);
@@ -159,6 +163,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
static QList<QList<SqlQueryItem*>> groupItemsByRows(const QList<SqlQueryItem*>& items);
static QHash<AliasedTable, QList<SqlQueryItem*> > groupItemsByTable(const QList<SqlQueryItem*>& items);
+ static QHash<AliasedTable, QVector<SqlQueryModelColumn*> > groupColumnsByTable(const QVector<SqlQueryModelColumn*>& columns);
bool getSimpleExecutionMode() const;
void setSimpleExecutionMode(bool value);
@@ -178,6 +183,9 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
void setDesiredColumnWidth(int colIdx, int width);
int getDesiredColumnWidth(int colIdx);
+ void setCellDataLengthLimit(int value);
+ int getCellDataLengthLimit();
+
protected:
class CommitUpdateQueryBuilder : public RowIdConditionBuilder
{
@@ -199,6 +207,29 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
QStringList assignmentArgs;
};
+ class SelectCellsQueryBuilder : public RowIdConditionBuilder
+ {
+ public:
+ void addRowId(const RowId& rowId);
+ QString build();
+ void clear();
+ void setDatabase(const QString& database);
+ void setTable(const QString& table);
+ QString getDatabase() const;
+ QString getTable() const;
+ void addColumn(const QString& column);
+ RowId readRowId(SqlResultsRowPtr row) const;
+ int getColumnCount() const;
+
+ protected:
+ QSet<QString> rowIdColumns;
+ QString database;
+ QString table;
+ QSet<QString> columns;
+ QSet<RowId> includedRowIds;
+ int argSquence = 0;
+ };
+
/**
* @brief commitAddedRow Inserts new row to a table.
* @param itemsInRow All cells for the new row.
@@ -209,7 +240,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
* and insert them into the actual database table. It also has to update items in the model,
* so they are no longer "new" and have the same data as inserted into the database.
*/
- virtual bool commitAddedRow(const QList<SqlQueryItem*>& itemsInRow);
+ virtual bool commitAddedRow(const QList<SqlQueryItem*>& itemsInRow, QList<CommitSuccessfulHandler>& successfulCommitHandlers);
/**
* @brief commitEditedRow Updates table row with new values.
@@ -220,7 +251,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
* unless the cell doesn't referr to the table, but in that case the cell should not be editable for user anyway.
* <b>Important</b> thing to pay attention to is that the item list passed in arguments contains <b>only modified items</b>.
*/
- virtual bool commitEditedRow(const QList<SqlQueryItem*>& itemsInRow);
+ virtual bool commitEditedRow(const QList<SqlQueryItem*>& itemsInRow, QList<CommitSuccessfulHandler>& successfulCommitHandlers);
/**
* @brief commitDeletedRow Deletes row from the table.
@@ -230,7 +261,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
* Inheriting class can reimplement this, so for example model specialized for single table can delete rows.
* The method implementation should delete the row from the database.
*/
- virtual bool commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow);
+ virtual bool commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow, QList<CommitSuccessfulHandler>& successfulCommitHandlers);
/**
* @brief rollbackAddedRow
@@ -258,10 +289,15 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
SqlQueryModelColumnPtr getColumnModel(const QString& table, const QString& column);
QList<SqlQueryModelColumnPtr> getTableColumnModels(const QString& database, const QString& table);
QList<SqlQueryModelColumnPtr> getTableColumnModels(const QString& table);
+ void updateItem(SqlQueryItem* item, const QVariant& value, int columnIndex, const RowId& rowId, SqlResultsRowPtr row,
+ const QStringList& columnNames, const BiStrHash& typeColumnToResColumn);
void updateItem(SqlQueryItem* item, const QVariant& value, int columnIndex, const RowId& rowId);
+ void updateItem(SqlQueryItem* item, const QVariant& value, int columnIndex, const RowId& rowId, Qt::Alignment alignment);
RowId getNewRowId(const RowId& currentRowId, const QList<SqlQueryItem*> items);
void updateRowIdForAllItems(const AliasedTable& table, const RowId& rowId, const RowId& newRowId);
QHash<QString, QVariantList> toValuesGroupedByColumns(const QList<SqlQueryItem*>& items);
+ void refreshGeneratedColumns(const QList<SqlQueryItem*>& items);
+ void refreshGeneratedColumns(const QList<SqlQueryItem*>& items, QHash<SqlQueryItem*, QVariant>& values, const RowId& insertedRowId);
QueryExecutor* queryExecutor = nullptr;
Db* db = nullptr;
@@ -282,7 +318,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
* Having this set to 10000 gives about 290 MB of memory consumption
* while having 30 columns and 1000 result rows loaded, all with 10000 bytes.
*/
- static const int cellDataLengthLimit = 100;
+ int cellDataLengthLimit = 100;
private:
struct TableDetails
@@ -304,9 +340,9 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
*/
bool loadData(SqlQueryPtr results);
- QList<QStandardItem*> loadRow(SqlResultsRowPtr row);
+ QList<QStandardItem*> loadRow(SqlResultsRowPtr row, SqlQueryPtr results);
RowId getRowIdValue(SqlResultsRowPtr row, int columnIdx);
- void readColumns();
+ bool readColumns();
void readColumnDetails();
void updateColumnsHeader();
void updateColumnHeaderLabels();
@@ -316,8 +352,9 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
QList<AliasedTable> getTablesForColumns();
QList<bool> getColumnEditionEnabledList();
QList<SqlQueryItem*> toItemList(const QModelIndexList& indexes) const;
- bool commitRow(const QList<SqlQueryItem*>& itemsInRow);
+ bool commitRow(const QList<SqlQueryItem*>& itemsInRow, QList<CommitSuccessfulHandler>& successfulCommitHandlers);
void rollbackRow(const QList<SqlQueryItem*>& itemsInRow);
+ QHash<SqlQueryItem*, QVariant> readCellValues(SelectCellsQueryBuilder& queryBuilder, const QHash<RowId, QSet<SqlQueryItem*> >& itemsPerRowId);
void storeStep1NumbersFromExecution();
void storeStep2NumbersFromExecution();
void restoreNumbersToQueryExecutor();
@@ -333,6 +370,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
int getInsertRowIndex();
void notifyItemEditionEnded(const QModelIndex& idx);
int getRowsPerPage() const;
+ bool isEmptyQuery() const;
QString query;
QHash<QString, QVariant> queryParams;
@@ -400,7 +438,7 @@ class GUI_API_EXPORT SqlQueryModel : public QStandardItemModel
QueryExecutor::SortList sortOrder;
QHash<Column,SqlQueryModelColumnPtr> columnMap;
- QHash<Column,int> columnWidths;
+ QHash<AliasedColumn,int> columnWidths;
QHash<AliasedTable,QHash<QString,QString>> tableToRowIdColumn;
QStringList headerColumns;
int rowNumBase = 0;
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp
index 688e05a..8171154 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.cpp
@@ -6,6 +6,7 @@ SqlQueryModelColumn::SqlQueryModelColumn(const QueryExecutor::ResultColumnPtr& r
{
displayName = resultColumn->displayName;
column = resultColumn->column;
+ alias = resultColumn->alias;
table = resultColumn->table;
tableAlias = resultColumn->tableAlias;
database = resultColumn->database.isEmpty() ? "main": resultColumn->database;
@@ -80,9 +81,17 @@ QString SqlQueryModelColumn::resolveMessage(SqlQueryModelColumn::EditionForbidde
return QObject::tr("Cannot edit columns that are result of %1 statement.").arg("SELECT DISTINCT");
case EditionForbiddenReason::COMMON_TABLE_EXPRESSION:
return QObject::tr("Cannot edit columns that are result of common table expression statement (%1).").arg("WITH ... SELECT ...");
+ case EditionForbiddenReason::GENERATED_COLUMN:
+ return QObject::tr("Cannot edit table generated columns.");
}
qCritical() << "Reached null text message for SqlQueryModel::EditionForbiddenReason. This should not happen!";
- return QString::null;
+ return QString();
+}
+
+void SqlQueryModelColumn::postProcessConstraints()
+{
+ if (isGenerated())
+ editionForbiddenReason << EditionForbiddenReason::GENERATED_COLUMN;
}
bool SqlQueryModelColumn::isNumeric()
@@ -90,6 +99,11 @@ bool SqlQueryModelColumn::isNumeric()
return dataType.isNumeric();
}
+bool SqlQueryModelColumn::isNull()
+{
+ return dataType.isNull();
+}
+
bool SqlQueryModelColumn::canEdit()
{
return editionForbiddenReason.size() == 0;
@@ -98,11 +112,11 @@ bool SqlQueryModelColumn::canEdit()
QString SqlQueryModelColumn::getEditionForbiddenReason()
{
if (canEdit())
- return QString::null;
+ return QString();
// We sort reasons to get most significant reason at first position.
- QList<EditionForbiddenReason> list = editionForbiddenReason.toList();
- qSort(list);
+ QList<EditionForbiddenReason> list = editionForbiddenReason.values();
+ std::sort(list.begin(), list.end());
return resolveMessage(list[0]);
}
@@ -157,6 +171,11 @@ bool SqlQueryModelColumn::isCollate() const
return getConstraints<ConstraintCollate*>().size() > 0;
}
+bool SqlQueryModelColumn::isGenerated() const
+{
+ return getConstraints<ConstraintGenerated*>().size() > 0;
+}
+
QList<SqlQueryModelColumn::ConstraintFk*> SqlQueryModelColumn::getFkConstraints() const
{
return getConstraints<ConstraintFk*>();
@@ -305,6 +324,14 @@ SqlQueryModelColumn::Constraint* SqlQueryModelColumn::Constraint::create(SqliteC
constr->type = Type::COLLATE;
break;
}
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ {
+ ConstraintGenerated* generate = new ConstraintGenerated();
+ generate->generatedType = columnConstraint->generatedType;
+ constr = generate;
+ constr->type = Type::GENERATED;
+ break;
+ }
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
{
if (columnConstraint->foreignKey->indexedColumns.size() == 0)
@@ -392,7 +419,7 @@ QString SqlQueryModelColumn::ConstraintUnique::getDetails() const
if (onConflict != SqliteConflictAlgo::null)
return "("+QObject::tr("on conflict: %1", "data view tooltip").arg(sqliteConflictAlgo(onConflict))+")";
- return QString::null;
+ return QString();
}
Icon* SqlQueryModelColumn::ConstraintUnique::getIcon() const
@@ -410,7 +437,7 @@ QString SqlQueryModelColumn::ConstraintNotNull::getDetails() const
if (onConflict != SqliteConflictAlgo::null)
return "("+QObject::tr("on conflict: %1", "data view tooltip").arg(sqliteConflictAlgo(onConflict))+")";
- return QString::null;
+ return QString();
}
Icon* SqlQueryModelColumn::ConstraintNotNull::getIcon() const
@@ -468,3 +495,20 @@ Icon* SqlQueryModelColumn::ConstraintCollate::getIcon() const
{
return ICONS.CONSTRAINT_COLLATION;
}
+
+QString SqlQueryModelColumn::ConstraintGenerated::getTypeString() const
+{
+ return "GENERATED";
+}
+
+QString SqlQueryModelColumn::ConstraintGenerated::getDetails() const
+{
+ return "("+QObject::tr("generated column type: %1", "data view tooltip")
+ .arg(SqliteCreateTable::Column::Constraint::toString(generatedType))+")";
+}
+
+Icon* SqlQueryModelColumn::ConstraintGenerated::getIcon() const
+{
+ return generatedType == SqliteCreateTable::Column::Constraint::GeneratedType::STORED ?
+ ICONS.CONSTRAINT_GENERATED_STORED : ICONS.CONSTRAINT_GENERATED_VIRTUAL;
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h
index e0f11e0..8e05fd5 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlquerymodelcolumn.h
@@ -28,7 +28,8 @@ class GUI_API_EXPORT SqlQueryModelColumn
EXPRESSION,
SMART_EXECUTION_FAILED,
DISTINCT_RESULTS,
- COMMON_TABLE_EXPRESSION
+ COMMON_TABLE_EXPRESSION,
+ GENERATED_COLUMN
};
struct Constraint
@@ -41,6 +42,7 @@ class GUI_API_EXPORT SqlQueryModelColumn
CHECK,
DEFAULT,
COLLATE,
+ GENERATED,
FOREIGN_KEY,
null
};
@@ -131,6 +133,15 @@ class GUI_API_EXPORT SqlQueryModelColumn
QString collationName;
};
+ struct ConstraintGenerated : public Constraint
+ {
+ QString getTypeString() const;
+ QString getDetails() const;
+ Icon* getIcon() const;
+
+ SqliteCreateTable::Column::Constraint::GeneratedType generatedType = SqliteCreateTable::Column::Constraint::GeneratedType::null;
+ };
+
SqlQueryModelColumn(const QueryExecutor::ResultColumnPtr& resultColumn);
virtual ~SqlQueryModelColumn();
@@ -138,7 +149,9 @@ class GUI_API_EXPORT SqlQueryModelColumn
static EditionForbiddenReason convert(QueryExecutor::EditionForbiddenReason reason);
static EditionForbiddenReason convert(QueryExecutor::ColumnEditionForbiddenReason reason);
static QString resolveMessage(EditionForbiddenReason reason);
+ void postProcessConstraints();
bool isNumeric();
+ bool isNull();
bool canEdit();
QString getEditionForbiddenReason();
bool isPk() const;
@@ -149,11 +162,13 @@ class GUI_API_EXPORT SqlQueryModelColumn
bool isFk() const;
bool isDefault() const;
bool isCollate() const;
+ bool isGenerated() const;
QList<ConstraintFk*> getFkConstraints() const;
ConstraintDefault* getDefaultConstraint() const;
QString displayName;
QString column;
+ QString alias;
QString table;
QString database;
QString tableAlias;
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp
index 4364986..9d3ea96 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.cpp
@@ -107,6 +107,7 @@ void SqlQueryView::createActions()
createAction(INSERT_ROW, ICONS.INSERT_ROW, tr("Insert row"), this, SIGNAL(requestForRowInsert()), this);
createAction(INSERT_MULTIPLE_ROWS, ICONS.INSERT_ROWS, tr("Insert multiple rows"), this, SIGNAL(requestForMultipleRowInsert()), this);
createAction(DELETE_ROW, ICONS.DELETE_ROW, tr("Delete selected row"), this, SIGNAL(requestForRowDelete()), this);
+ createAction(LOAD_FULL_VALUES, ICONS.LOAD_FULL_VALUES, tr("Load full values"), this, SLOT(loadFullValuesForColumn()), this);
actionMap[RESET_SORTING]->setEnabled(false);
}
@@ -121,8 +122,6 @@ void SqlQueryView::setupDefShortcuts()
void SqlQueryView::setupActionsForMenu(SqlQueryItem* currentItem, const QList<SqlQueryItem*>& selectedItems)
{
- UNUSED(currentItem);
-
// Selected items count
int selCount = selectedItems.size();
@@ -136,7 +135,7 @@ void SqlQueryView::setupActionsForMenu(SqlQueryItem* currentItem, const QList<Sq
if (selItem->getColumn()->editionForbiddenReason.size() > 0)
editableSelCount--;
- bool currentItemEditable = (getCurrentItem()->getColumn()->editionForbiddenReason.size() == 0);
+ bool currentItemEditable = (currentItem && currentItem->getColumn()->editionForbiddenReason.size() == 0);
// Uncommitted & selected items count
int uncommittedSelCount = 0;
@@ -173,7 +172,7 @@ void SqlQueryView::setupActionsForMenu(SqlQueryItem* currentItem, const QList<Sq
contextMenu->addSeparator();
}
- if (selCount == 1 && selectedItems.first() == currentItem)
+ if (selCount == 1 && currentItem && selectedItems.first() == currentItem)
addFkActionsToContextMenu(currentItem);
if (selCount > 0)
@@ -210,6 +209,8 @@ void SqlQueryView::setupHeaderMenu()
headerContextMenu = new QMenu(horizontalHeader());
headerContextMenu->addAction(actionMap[SORT_DIALOG]);
headerContextMenu->addAction(actionMap[RESET_SORTING]);
+ headerContextMenu->addSeparator();
+ headerContextMenu->addAction(actionMap[LOAD_FULL_VALUES]);
}
QList<SqlQueryItem*> SqlQueryView::getSelectedItems()
@@ -223,7 +224,7 @@ QList<SqlQueryItem*> SqlQueryView::getSelectedItems()
if (idxList.size() == 0)
return items;
- qSort(idxList);
+ std::sort(idxList.begin(), idxList.end());
const SqlQueryModel* model = dynamic_cast<const SqlQueryModel*>(idxList.first().model());
for (const QModelIndex& idx : idxList)
items << model->itemFromIndex(idx);
@@ -318,6 +319,11 @@ void SqlQueryView::generateDelete()
MAINWINDOW->openSqlEditor(getModel()->getDb(), sql);
}
+void SqlQueryView::loadFullValuesForColumn()
+{
+ getModel()->loadFullDataForEntireColumn(headerContextMenuSection);
+}
+
bool SqlQueryView::editInEditorIfNecessary(SqlQueryItem* item)
{
if (item->getColumn()->dataType.getType() == DataType::BLOB)
@@ -340,11 +346,24 @@ void SqlQueryView::paste(const QList<QList<QVariant> >& data)
return;
}
+ if (getModel()->isStructureOutOfDate())
+ {
+ notifyWarn(tr("Cannot paste data. Details: %1").arg(tr("Structure of at least one table used has changed since last data was loaded. Reload the data to proceed.")));
+ return;
+ }
+
+ QSet<QString> warnedColumns;
+ bool warnedRowDeletion = false;
if (data.size() == 1 && data[0].size() == 1)
{
QVariant theValue = data[0][0];
for (SqlQueryItem* item : selectedItems)
+ {
+ if (!validatePasting(warnedColumns, warnedRowDeletion, item))
+ continue;
+
item->setValue(theValue, false, false);
+ }
return;
}
@@ -377,21 +396,47 @@ void SqlQueryView::paste(const QList<QList<QVariant> >& data)
qDebug() << "Tried to paste more columns than available in the grid.";
break;
}
- item = getModel()->itemFromIndex(rowIdx, colIdx);
+ item = getModel()->itemFromIndex(rowIdx, colIdx++);
- // Set value to the cell
- item->setValue(cell, false, false);
+ // Set value to the cell, if possible
+ if (!validatePasting(warnedColumns, warnedRowDeletion, item))
+ continue;
- // Go to next cell
- colIdx++;
+ item->setValue(cell, false, false);
}
- // Go to next row, first cell
+ // Go to next row, first column
rowIdx++;
colIdx = topLeft->column();
}
}
+bool SqlQueryView::validatePasting(QSet<QString>& warnedColumns, bool& warnedRowDeletion, SqlQueryItem* item)
+{
+ if (item->isDeletedRow())
+ {
+ if (!warnedRowDeletion)
+ {
+ warnedRowDeletion = true;
+ notifyWarn(tr("Cannot paste to a cell. Details: %1").arg(tr("The row is marked for deletion.")));
+ }
+ return false;
+ }
+
+ if (!item->getColumn()->canEdit())
+ {
+ QString colName = item->getColumn()->displayName;
+ if (!warnedColumns.contains(colName))
+ {
+ warnedColumns << colName;
+ notifyWarn(tr("Cannot paste to column %1. Details: %2").arg(colName).arg(item->getColumn()->getEditionForbiddenReason()));
+ }
+ return false;
+ }
+
+ return true;
+}
+
void SqlQueryView::addFkActionsToContextMenu(SqlQueryItem* currentItem)
{
QList<SqlQueryModelColumn::ConstraintFk*> fkList = currentItem->getColumn()->getFkConstraints();
@@ -430,9 +475,8 @@ void SqlQueryView::goToReferencedRow(const QString& table, const QString& column
static_qstring(sqlTpl, "SELECT * FROM %1 WHERE %2 = %3");
- Dialect dialect = db->getDialect();
- QString wrappedTable = wrapObjIfNeeded(table, dialect);
- QString wrappedColumn = wrapObjIfNeeded(column, dialect);
+ QString wrappedTable = wrapObjIfNeeded(table);
+ QString wrappedColumn = wrapObjIfNeeded(column);
QString valueStr = wrapValueIfNeeded(value.toString());
EditorWindow* win = MAINWINDOW->openSqlEditor(db, sqlTpl.arg(wrappedTable, wrappedColumn, valueStr));
if (!win)
@@ -464,7 +508,8 @@ void SqlQueryView::copy(bool withHeader)
// Header
if (withHeader)
{
- for (SqlQueryModelColumnPtr col : getModel()->getColumns().mid(0, groupedItems.first().size()))
+ int leftMostColumn = groupedItems.first().first()->column();
+ for (SqlQueryModelColumnPtr col : getModel()->getColumns().mid(leftMostColumn, groupedItems.first().size()))
{
theDataRow << col->displayName;
cells << col->displayName;
@@ -540,6 +585,20 @@ void SqlQueryView::scrollContentsBy(int dx, int dy)
emit scrolledBy(dx, dy);
}
+void SqlQueryView::mouseMoveEvent(QMouseEvent* event)
+{
+ QAbstractItemView::mouseMoveEvent(event);
+
+ QModelIndex idx = indexAt(QPoint(event->x(), event->y()));
+ if (idx != indexUnderCursor)
+ {
+ if (indexUnderCursor.isValid())
+ itemDelegate->mouseLeftIndex(indexUnderCursor);
+
+ indexUnderCursor = idx;
+ }
+}
+
void SqlQueryView::updateCommitRollbackActions(bool enabled)
{
actionMap[COMMIT]->setEnabled(enabled);
@@ -570,6 +629,11 @@ void SqlQueryView::headerContextMenuRequested(const QPoint& pos)
if (simpleBrowserMode)
return;
+ headerContextMenuSection = horizontalHeader()->visualIndexAt(pos.x());
+
+ bool hasLimitedValues = getModel()->doesColumnHaveLimitedValues(headerContextMenuSection);
+ actionMap[LOAD_FULL_VALUES]->setEnabled(hasLimitedValues);
+
headerContextMenu->popup(horizontalHeader()->mapToGlobal(pos));
}
@@ -712,7 +776,7 @@ void SqlQueryView::setNull()
if (selItem->getColumn()->editionForbiddenReason.size() > 0)
continue;
- selItem->setValue(QVariant(QString::null), false, false);
+ selItem->setValue(QVariant(QString()), false, false);
}
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h
index 98e2783..5e50ed1 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqlqueryview.h
@@ -58,6 +58,7 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer
OPEN_VALUE_EDITOR,
SORT_DIALOG,
RESET_SORTING,
+ LOAD_FULL_VALUES,
GENERATE_SELECT,
GENERATE_INSERT,
GENERATE_UPDATE,
@@ -85,6 +86,7 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer
protected:
void scrollContentsBy(int dx, int dy);
+ void mouseMoveEvent(QMouseEvent *event);
private:
class Header : public QHeaderView
@@ -104,6 +106,7 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer
void setupHeaderMenu();
bool editInEditorIfNecessary(SqlQueryItem* item);
void paste(const QList<QList<QVariant>>& data);
+ bool validatePasting(QSet<QString>& warnedColumns, bool& warnedRowDeletion, SqlQueryItem* item);
void addFkActionsToContextMenu(SqlQueryItem* currentItem);
void goToReferencedRow(const QString& table, const QString& column, const QVariant& value);
void copy(bool withHeaders);
@@ -122,6 +125,8 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer
bool simpleBrowserMode = false;
bool ignoreColumnWidthChanges = false;
int beforeExecutionHorizontalPosition = -1;
+ int headerContextMenuSection = -1;
+ QModelIndex indexUnderCursor;
private slots:
void updateCommitRollbackActions(bool enabled);
@@ -136,6 +141,7 @@ class GUI_API_EXPORT SqlQueryView : public QTableView, public ExtActionContainer
void generateInsert();
void generateUpdate();
void generateDelete();
+ void loadFullValuesForColumn();
public slots:
void executionStarted();
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp
index ed9a3a4..50db973 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.cpp
@@ -3,6 +3,7 @@
#include "sqlqueryitem.h"
#include "services/notifymanager.h"
#include "uiconfig.h"
+#include "common/unused.h"
#include <QDebug>
#include <QApplication>
#include <schemaresolver.h>
@@ -45,7 +46,7 @@ SqlQueryModel::Features SqlTableModel::features() const
return INSERT_ROW|DELETE_ROW|FILTERING;
}
-bool SqlTableModel::commitAddedRow(const QList<SqlQueryItem*>& itemsInRow)
+bool SqlTableModel::commitAddedRow(const QList<SqlQueryItem*>& itemsInRow, QList<SqlQueryModel::CommitSuccessfulHandler>& successfulCommitHandlers)
{
QList<SqlQueryModelColumnPtr> modelColumns = getTableColumnModels(table);
if (modelColumns.size() != itemsInRow.size())
@@ -76,10 +77,11 @@ bool SqlTableModel::commitAddedRow(const QList<SqlQueryItem*>& itemsInRow)
// Handle error
if (result->isError())
{
+ QString errMsg = tr("Error while committing new row: %1").arg(result->getErrorText());
for (SqlQueryItem* item : itemsInRow)
- item->setCommittingError(true);
+ item->setCommittingError(true, errMsg);
- notifyError(tr("Error while committing new row: %1").arg(result->getErrorText()));
+ notifyError(errMsg);
return false;
}
@@ -99,11 +101,16 @@ bool SqlTableModel::commitAddedRow(const QList<SqlQueryItem*>& itemsInRow)
else
rowId = result->getInsertRowId();
- updateRowAfterInsert(itemsInRow, modelColumns, rowId);
+ // After all items are committed successfully, update data/metadata for inserted rows/items
+ successfulCommitHandlers << [this, itemsInRow, modelColumns, rowId]()
+ {
+ updateRowAfterInsert(itemsInRow, modelColumns, rowId);
+ };
+
return true;
}
-bool SqlTableModel::commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow)
+bool SqlTableModel::commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow, QList<SqlQueryModel::CommitSuccessfulHandler>& successfulCommitHandlers)
{
if (itemsInRow.size() == 0)
{
@@ -125,11 +132,9 @@ bool SqlTableModel::commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow)
if (rowId.isEmpty())
return false;
- Dialect dialect = db->getDialect();
-
CommitDeleteQueryBuilder queryBuilder;
- queryBuilder.setTable(wrapObjIfNeeded(table, dialect));
- queryBuilder.setRowId(rowId, dialect);
+ queryBuilder.setTable(wrapObjIfNeeded(table));
+ queryBuilder.setRowId(rowId);
QString sql = queryBuilder.build();
QHash<QString, QVariant> args = queryBuilder.getQueryArgs();
@@ -137,11 +142,15 @@ bool SqlTableModel::commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow)
SqlQueryPtr result = db->exec(sql, args);
if (result->isError())
{
- notifyError(tr("Error while deleting row from table %1: %2").arg(table).arg(result->getErrorText()));
+ QString errMsg = tr("Error while deleting row from table %1: %2").arg(table, result->getErrorText());
+ for (SqlQueryItem* item : itemsInRow)
+ item->setCommittingError(true, errMsg);
+
+ notifyError(errMsg);
return false;
}
- if (!SqlQueryModel::commitDeletedRow(itemsInRow))
+ if (!SqlQueryModel::commitDeletedRow(itemsInRow, successfulCommitHandlers))
qCritical() << "Could not delete row from SqlQueryView while committing row deletion.";
return true;
@@ -157,10 +166,9 @@ void SqlTableModel::applyFilter(const QString& value, FilterValueProcessor value
return;
}
- Dialect dialect = db->getDialect();
QStringList conditions;
for (SqlQueryModelColumnPtr column : columns)
- conditions << wrapObjIfNeeded(column->column, dialect)+" "+valueProc(value);
+ conditions << wrapObjIfNeeded(column->column)+" "+valueProc(value);
setQuery(sql.arg(getDataSource(), conditions.join(" OR ")));
executeQuery();
@@ -182,14 +190,13 @@ void SqlTableModel::applyFilter(const QStringList& values, FilterValueProcessor
return;
}
- Dialect dialect = db->getDialect();
QStringList conditions;
for (int i = 0, total = columns.size(); i < total; ++i)
{
if (values[i].isEmpty())
continue;
- conditions << wrapObjIfNeeded(columns[i]->column, dialect)+" "+valueProc(values[i]);
+ conditions << wrapObjIfNeeded(columns[i]->column)+" "+valueProc(values[i]);
}
setQuery(sql.arg(getDataSource(), conditions.join(" AND ")));
@@ -286,107 +293,35 @@ QString SqlTableModel::generateDeleteQueryForItems(const QList<SqlQueryItem*>& i
void SqlTableModel::updateRowAfterInsert(const QList<SqlQueryItem*>& itemsInRow, const QList<SqlQueryModelColumnPtr>& modelColumns, RowId rowId)
{
- Dialect dialect = db->getDialect();
-
// Update cells with data just like it was entered. Only DEFAULT and PRIMARY KEY AUTOINCREMENT will have special values.
// If the DEFAULT is not an explicit literal, but an expression and db is SQLite3, we have to read the inserted value from DB.
QHash<SqlQueryModelColumnPtr,SqlQueryItem*> columnsToReadFromDb;
- Parser parser(dialect);
- SqliteExpr* expr = nullptr;
+ Parser parser;
QHash<SqlQueryItem*,QVariant> values;
SqlQueryItem* item = nullptr;
int i = 0;
for (const SqlQueryModelColumnPtr& modelColumn : modelColumns)
{
item = itemsInRow[i++];
-// qDebug() << "Item is for column" << item->getColumn()->column << ", column iterated:" << modelColumn->column;
- if (item->getValue().isNull())
- {
- if (modelColumn->isDefault())
- {
- if (dialect == Dialect::Sqlite3)
- {
- expr = parser.parseExpr(modelColumn->getDefaultConstraint()->defaultValue);
- if (expr && expr->mode != SqliteExpr::Mode::LITERAL_VALUE)
- {
- if (isWithOutRowIdTable && rowId.isEmpty())
- {
- qWarning() << "Inserted expression as DEFAULT value for table WITHOUT ROWID and actually no ROWID."
- << "This is currently unsupported to refresh such cell value instantly.";
- values[item] = QVariant();
- }
- else
- columnsToReadFromDb[modelColumn] = item;
-
- continue;
- }
- }
- values[item] = modelColumn->getDefaultConstraint()->defaultValue;
- continue;
- }
-
- // If this is the PK AUTOINCR column we use RowId as value, because it was skipped when setting values to items
- if (modelColumn->isPk() && modelColumn->isAutoIncr())
- {
- values[item] = rowId["ROWID"];
- continue;
- }
- }
+ if (processNullValueAfterInsert(item, values[item], modelColumn, columnsToReadFromDb, rowId, parser))
+ continue;
values[item] = item->getValue();
}
// Reading values for DEFAULT values being an expression
if (columnsToReadFromDb.size() > 0)
- {
- // Preparing query
- static_qstring(limitedColTpl, "substr(%1, 1, %2)");
- SelectColumnsQueryBuilder queryBuilder;
- queryBuilder.setTable(wrapObjIfNeeded(table, dialect));
- queryBuilder.setRowId(rowId, dialect);
- QList<SqlQueryModelColumnPtr> columnKeys = columnsToReadFromDb.keys();
- for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
- queryBuilder.addColumn(limitedColTpl.arg(wrapObjIfNeeded(modelColumn->column, dialect), QString::number(cellDataLengthLimit)));
+ processDefaultValueAfterInsert(columnsToReadFromDb, values, rowId);
- // Executing query
- SqlQueryPtr defColValues = db->exec(queryBuilder.build(), queryBuilder.getQueryArgs(), Db::Flag::PRELOAD);
-
- // Handling error
- if (defColValues->isError())
- {
- qCritical() << "Could not load inserted values for DEFAULT expression in the table, so filling them with NULL. Error from database was:"
- << defColValues->getErrorText();
-
- for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
- values[columnsToReadFromDb[modelColumn]] = QVariant();
- }
- else if (!defColValues->hasNext())
- {
- qCritical() << "Could not load inserted values for DEFAULT expression in the table, so filling them with NULL. There were no result rows.";
-
- for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
- values[columnsToReadFromDb[modelColumn]] = QVariant();
- }
- else
- {
- // Reading a row
- SqlResultsRowPtr row = defColValues->next();
- if (row->valueList().size() != columnKeys.size())
- {
- qCritical() << "Could not load inserted values for DEFAULT expression in the table, so filling them with NULL. Number of columns from results was invalid:"
- << row->valueList().size() << ", while expected:" << columnKeys.size();
-
- for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
- values[columnsToReadFromDb[modelColumn]] = QVariant();
- }
- else
- {
- int colIdx = 0;
- for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
- values[columnsToReadFromDb[modelColumn]] = row->value(colIdx++);
- }
- }
+ // Reading values for GENERATED columns
+ i = 0;
+ QList<SqlQueryItem*> generatedColumnItems;
+ for (const SqlQueryModelColumnPtr& modelColumn : modelColumns)
+ {
+ if (modelColumn->isGenerated())
+ generatedColumnItems << itemsInRow[i++];
}
+ refreshGeneratedColumns(generatedColumnItems, values, rowId);
// Update cell data with results
int colIdx = 0;
@@ -401,32 +336,128 @@ void SqlTableModel::updateRowAfterInsert(const QList<SqlQueryItem*>& itemsInRow,
}
}
+bool SqlTableModel::processNullValueAfterInsert(SqlQueryItem* item, QVariant& value, const SqlQueryModelColumnPtr& modelColumn,
+ QHash<SqlQueryModelColumnPtr, SqlQueryItem*>& columnsToReadFromDb, RowId rowId, Parser& parser)
+{
+// qDebug() << "Item is for column" << item->getColumn()->column << ", column iterated:" << modelColumn->column;
+ if (!item->getValue().isNull())
+ return false;
+
+ // If this is the PK AUTOINCR column we use RowId as value, because it was skipped when setting values to items
+ if (modelColumn->isPk() && modelColumn->isAutoIncr())
+ {
+ value = rowId["ROWID"];
+ return true;
+ }
+
+ if (!CFG_UI.General.UseDefaultValueForNull.get() || !modelColumn->isDefault())
+ return false;
+
+ SqliteExpr* expr = parser.parseExpr(modelColumn->getDefaultConstraint()->defaultValue);
+ if (expr && expr->mode != SqliteExpr::Mode::LITERAL_VALUE)
+ {
+ if (isWithOutRowIdTable && rowId.isEmpty())
+ {
+ qWarning() << "Inserted expression as DEFAULT value for table WITHOUT ROWID and actually no ROWID."
+ << "This is currently unsupported to refresh such cell value instantly.";
+ value = QVariant();
+ }
+ else
+ columnsToReadFromDb[modelColumn] = item;
+
+ return true;
+ }
+
+ if (expr)
+ value = expr->literalValue;
+ else
+ value = modelColumn->getDefaultConstraint()->defaultValue;
+
+ if (value.userType() == QVariant::String)
+ value = stripString(value.toString());
+
+ return true;
+}
+
+void SqlTableModel::processDefaultValueAfterInsert(QHash<SqlQueryModelColumnPtr, SqlQueryItem*>& columnsToReadFromDb, QHash<SqlQueryItem*, QVariant>& values, RowId rowId)
+{
+ // Preparing query
+ static_qstring(limitedColTpl, "substr(%1, 1, %2)");
+ SelectColumnsQueryBuilder queryBuilder;
+ queryBuilder.setTable(wrapObjIfNeeded(table));
+ queryBuilder.setRowId(rowId);
+ QList<SqlQueryModelColumnPtr> columnKeys = columnsToReadFromDb.keys();
+ for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
+ queryBuilder.addColumn(limitedColTpl.arg(wrapObjIfNeeded(modelColumn->column), QString::number(cellDataLengthLimit)));
+
+ // Executing query
+ SqlQueryPtr defColValues = db->exec(queryBuilder.build(), queryBuilder.getQueryArgs(), Db::Flag::PRELOAD);
+
+ // Handling error
+ if (defColValues->isError())
+ {
+ qCritical() << "Could not load inserted values for DEFAULT expression in the table, so filling them with NULL. Error from database was:"
+ << defColValues->getErrorText();
+
+ for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
+ values[columnsToReadFromDb[modelColumn]] = QVariant();
+
+ return;
+ }
+
+
+ if (!defColValues->hasNext())
+ {
+ qCritical() << "Could not load inserted values for DEFAULT expression in the table, so filling them with NULL. There were no result rows.";
+
+ for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
+ values[columnsToReadFromDb[modelColumn]] = QVariant();
+
+ return;
+ }
+
+
+ // Reading a row
+ SqlResultsRowPtr row = defColValues->next();
+ if (row->valueList().size() != columnKeys.size())
+ {
+ qCritical() << "Could not load inserted values for DEFAULT expression in the table, so filling them with NULL. Number of columns from results was invalid:"
+ << row->valueList().size() << ", while expected:" << columnKeys.size();
+
+ for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
+ values[columnsToReadFromDb[modelColumn]] = QVariant();
+
+ return;
+ }
+
+ int colIdx = 0;
+ for (const SqlQueryModelColumnPtr& modelColumn : columnKeys)
+ values[columnsToReadFromDb[modelColumn]] = row->value(colIdx++);
+}
+
QString SqlTableModel::getDatabasePrefix()
{
if (database.isNull())
- return "main.";
+ return ""; // not "main.", because the "main." doesn't work for TEMP tables, such as sqlite_temp_master
- return wrapObjIfNeeded(database, db->getDialect()) + ".";
+ return wrapObjIfNeeded(database) + ".";
}
QString SqlTableModel::getDataSource()
{
- return getDatabasePrefix() + wrapObjIfNeeded(table, db->getDialect());
+ return getDatabasePrefix() + wrapObjIfNeeded(table);
}
QString SqlTableModel::getInsertSql(const QList<SqlQueryModelColumnPtr>& modelColumns, QStringList& colNameList,
QStringList& sqlValues, QList<QVariant>& args)
{
- Dialect dialect = db->getDialect();
-
- QString sql = "INSERT INTO "+wrapObjIfNeeded(table, dialect);
+ UNUSED(modelColumns);
+ UNUSED(args);
+ QString sql = "INSERT INTO "+wrapObjIfNeeded(table);
if (colNameList.size() == 0)
{
// There are all null values passed to the query. We need to use Sqlite3 special syntax, or find at least one default value
- if (dialect == Dialect::Sqlite2)
- updateColumnsAndValuesWithDefaultValues(modelColumns, colNameList, sqlValues, args);
- else // Sqlite3 has default values syntax for that case
- sql += " DEFAULT VALUES";
+ sql += " DEFAULT VALUES";
}
else
sql += " ("+colNameList.join(", ")+") VALUES ("+sqlValues.join(", ")+")";
@@ -437,12 +468,13 @@ QString SqlTableModel::getInsertSql(const QList<SqlQueryModelColumnPtr>& modelCo
void SqlTableModel::updateColumnsAndValues(const QList<SqlQueryItem*>& itemsInRow, const QList<SqlQueryModelColumnPtr>& modelColumns,
QStringList& colNameList, QStringList& sqlValues, QList<QVariant>& args)
{
- Dialect dialect = db->getDialect();
-
SqlQueryItem* item = nullptr;
int i = 0;
for (SqlQueryModelColumnPtr modelColumn : modelColumns)
{
+ if (!modelColumn->canEdit())
+ continue;
+
item = itemsInRow[i++];
if (item->getValue().isNull())
{
@@ -456,7 +488,7 @@ void SqlTableModel::updateColumnsAndValues(const QList<SqlQueryItem*>& itemsInRo
continue;
}
- colNameList << wrapObjIfNeeded(modelColumn->column, dialect);
+ colNameList << wrapObjIfNeeded(modelColumn->column);
sqlValues << ":arg" + QString::number(i);
args << item->getFullValue();
}
@@ -465,14 +497,12 @@ void SqlTableModel::updateColumnsAndValues(const QList<SqlQueryItem*>& itemsInRo
void SqlTableModel::updateColumnsAndValuesWithDefaultValues(const QList<SqlQueryModelColumnPtr>& modelColumns, QStringList& colNameList,
QStringList& sqlValues, QList<QVariant>& args)
{
- Dialect dialect = db->getDialect();
-
// First try to find the one with DEFAULT value
for (SqlQueryModelColumnPtr modelColumn : modelColumns)
{
if (modelColumn->isDefault())
{
- colNameList << wrapObjIfNeeded(modelColumn->column, dialect);
+ colNameList << wrapObjIfNeeded(modelColumn->column);
sqlValues << ":defValue";
args << modelColumn->getDefaultConstraint()->defaultValue;
return;
@@ -484,15 +514,15 @@ void SqlTableModel::updateColumnsAndValuesWithDefaultValues(const QList<SqlQuery
{
if (modelColumn->isPk() && modelColumn->isAutoIncr())
{
- QString colName = wrapObjIfNeeded(modelColumn->column, dialect);
- QString tableName = wrapObjIfNeeded(table, dialect);
+ QString colName = wrapObjIfNeeded(modelColumn->column);
+ QString tableName = wrapObjIfNeeded(table);
SqlQueryPtr results = db->exec("SELECT max("+colName+") FROM "+tableName);
qint64 rowid = 0;
QVariant cellValue = results->getSingleCell();
if (!cellValue.isNull())
rowid = cellValue.toLongLong();
- colNameList << wrapObjIfNeeded(modelColumn->column, dialect);
+ colNameList << wrapObjIfNeeded(modelColumn->column);
sqlValues << ":defValue";
args << rowid;
return;
@@ -501,7 +531,7 @@ void SqlTableModel::updateColumnsAndValuesWithDefaultValues(const QList<SqlQuery
// No luck with AUTOINCR either, put NULL and if there's a NOT NULL in any column,
// user will get the proper error message from Sqlite.
- colNameList << wrapObjIfNeeded(modelColumns[0]->column, dialect);
+ colNameList << wrapObjIfNeeded(modelColumns[0]->column);
sqlValues << ":defValue";
args << QVariant();
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h
index b904343..3a1ab36 100644
--- a/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/datagrid/sqltablemodel.h
@@ -28,8 +28,8 @@ class GUI_API_EXPORT SqlTableModel : public SqlQueryModel
bool supportsModifyingQueriesInMenu() const;
protected:
- bool commitAddedRow(const QList<SqlQueryItem*>& itemsInRow);
- bool commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow);
+ bool commitAddedRow(const QList<SqlQueryItem*>& itemsInRow, QList<CommitSuccessfulHandler>& successfulCommitHandlers);
+ bool commitDeletedRow(const QList<SqlQueryItem*>& itemsInRow, QList<CommitSuccessfulHandler>& successfulCommitHandlers);
private:
class CommitDeleteQueryBuilder : public CommitUpdateQueryBuilder
@@ -59,6 +59,12 @@ class GUI_API_EXPORT SqlTableModel : public SqlQueryModel
QString getInsertSql(const QList<SqlQueryModelColumnPtr>& modelColumns, QStringList& colNameList, QStringList& sqlValues,
QList<QVariant>& args);
void updateRowAfterInsert(const QList<SqlQueryItem*>& itemsInRow, const QList<SqlQueryModelColumnPtr>& modelColumns, RowId rowId);
+ bool processNullValueAfterInsert(SqlQueryItem* item, QVariant& value, const SqlQueryModelColumnPtr& modelColumn,
+ QHash<SqlQueryModelColumnPtr,SqlQueryItem*>& columnsToReadFromDb, RowId rowId,
+ Parser& parser);
+ void processDefaultValueAfterInsert(QHash<SqlQueryModelColumnPtr,SqlQueryItem*>& columnsToReadFromDb, QHash<SqlQueryItem*,QVariant>& values,
+ RowId rowId);
+
QString getDatabasePrefix();
QString getDataSource();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dataview.cpp b/SQLiteStudio3/guiSQLiteStudio/dataview.cpp
index 9012c1c..568954c 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dataview.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dataview.cpp
@@ -311,9 +311,13 @@ void DataView::resizeColumnsInitiallyToContents()
}
if (wd > CFG_UI.General.MaxInitialColumnWith.get())
+ {
gridView->setColumnWidth(i, CFG_UI.General.MaxInitialColumnWith.get());
+ }
else if (wd < 60)
+ {
gridView->setColumnWidth(i, 60);
+ }
}
gridView->setIgnoreColumnWidthChanges(false);
}
@@ -522,7 +526,7 @@ void DataView::coverForGridCommit(int total)
void DataView::updateGridCommitCover(int value)
{
- if (!widgetCover->isVisible())
+ if (!widgetCover->isVisible() || (value % 10) != 0)
return;
widgetCover->setProgress(value);
@@ -544,6 +548,9 @@ void DataView::adjustColumnWidth(SqlQueryItem* item)
return;
int col = item->column();
+ if (model->getDesiredColumnWidth(col) > -1)
+ return;
+
gridView->resizeColumnToContents(col);
if (gridView->columnWidth(col) > CFG_UI.General.MaxInitialColumnWith.get())
gridView->setColumnWidth(col, CFG_UI.General.MaxInitialColumnWith.get());
@@ -606,6 +613,9 @@ void DataView::goToPage(const QString& pageStr)
page--; // Converting from visual page representation to logical
+ if (page == model->getCurrentPage(true))
+ return;
+
// We need to get this synchronized against event loop, cause changeing action status (probably) calls event loop update,
// so this method was sometimes called twice at the time (until setResultsNavigationState() call below),
// but the page in results model wasn't updated yet. We cannot simply move setResultsNavigationState() below gotoPage(),
@@ -616,9 +626,6 @@ void DataView::goToPage(const QString& pageStr)
if (!manualPageChangeMutex.tryLock())
return;
- if (page == model->getCurrentPage(true))
- return;
-
setNavigationState(false);
model->gotoPage(page);
manualPageChangeMutex.unlock();
@@ -643,8 +650,8 @@ void DataView::updateResultsCount(int resultsCount)
QString msg = QObject::tr("Total rows loaded: %1").arg(resultsCount);
rowCountLabel->setText(msg);
formViewRowCountLabel->setText(msg);
- rowCountLabel->setToolTip(QString::null);
- formViewRowCountLabel->setToolTip(QString::null);
+ rowCountLabel->setToolTip(QString());
+ formViewRowCountLabel->setToolTip(QString());
}
else
{
@@ -1007,6 +1014,7 @@ void DataView::createFilteringActions()
actionMap[FILTER]->setIcon(actionMap[FILTER_STRING]->icon());
+ gridView->getHeaderContextMenu()->addSeparator();
gridView->getHeaderContextMenu()->addAction(actionMap[FILTER_PER_COLUMN]);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp
index b6203da..a03675f 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dblistmodel.cpp
@@ -114,19 +114,19 @@ void DbListModel::sort()
case DbListModel::SortMode::LikeDbTree:
{
DbTreeComparer comparer;
- qSort(dbList.begin(), dbList.end(), comparer);
+ std::sort(dbList.begin(), dbList.end(), comparer);
break;
}
case DbListModel::SortMode::Alphabetical:
{
AlphaComparer comparer;
- qSort(dbList.begin(), dbList.end(), comparer);
+ std::sort(dbList.begin(), dbList.end(), comparer);
break;
}
case DbListModel::SortMode::AlphabeticalCaseInsensitive:
{
AlphaComparer comparer(Qt::CaseInsensitive);
- qSort(dbList.begin(), dbList.end(), comparer);
+ std::sort(dbList.begin(), dbList.end(), comparer);
break;
}
case DbListModel::SortMode::ConnectionOrder:
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp b/SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp
index 7dd45fd..05b614b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbobjectdialogs.cpp
@@ -52,12 +52,12 @@ void DbObjectDialogs::editIndex(const QString& index)
void DbObjectDialogs::addTriggerOnTable(const QString& table)
{
- addTrigger(table, QString::null);
+ addTrigger(table, QString());
}
void DbObjectDialogs::addTriggerOnView(const QString& view)
{
- addTrigger(QString::null, view);
+ addTrigger(QString(), view);
}
void DbObjectDialogs::addTrigger(const QString& table, const QString& view)
@@ -161,8 +161,7 @@ bool DbObjectDialogs::dropObject(const QString& database, const QString& name)
static const QString dropSql2 = "DROP %1 %2;";
static const QString dropSql3 = "DROP %1 %2.%3;";
- Dialect dialect = db->getDialect();
- QString dbName = wrapObjIfNeeded(database, dialect);
+ QString dbName = wrapObjIfNeeded(database);
Type type = getObjectType(database, name);
QString title;
@@ -206,11 +205,7 @@ bool DbObjectDialogs::dropObject(const QString& database, const QString& name)
SqlQueryPtr results;
- QString finalSql;
- if (dialect == Dialect::Sqlite3)
- finalSql = dropSql3.arg(typeForSql, dbName, wrapObjIfNeeded(name, dialect));
- else
- finalSql = dropSql2.arg(typeForSql, wrapObjIfNeeded(name, dialect));
+ QString finalSql = dropSql3.arg(typeForSql, dbName, wrapObjIfNeeded(name));
results = db->exec(finalSql);
if (results->isError())
@@ -273,7 +268,6 @@ bool DbObjectDialogs::dropObjects(const QHash<QString, QStringList>& objects)
static const QString dropSql2 = "DROP %1 IF EXISTS %2;";
static const QString dropSql3 = "DROP %1 IF EXISTS %2.%3;";
- Dialect dialect = db->getDialect();
QStringList names = concat(objects.values());
QHash<QString, QHash<QString, QStringList>> groupedObjects = groupObjects(objects);
@@ -298,16 +292,13 @@ bool DbObjectDialogs::dropObjects(const QHash<QString, QStringList>& objects)
QHash<QString, QStringList> typeToNames;
for (QHash<QString, QHash<QString, QStringList>>::const_iterator dbIt = groupedObjects.begin(); dbIt != groupedObjects.end(); ++dbIt)
{
- dbName = wrapObjIfNeeded(dbIt.key(), dialect);
+ dbName = wrapObjIfNeeded(dbIt.key());
typeToNames = dbIt.value();
for (QHash<QString, QStringList>::const_iterator typeIt = typeToNames.begin(); typeIt != typeToNames.end(); ++typeIt)
{
for (const QString& name : typeIt.value())
{
- if (dialect == Dialect::Sqlite3)
- finalSql = dropSql3.arg(typeIt.key(), dbName, wrapObjIfNeeded(name, dialect));
- else
- finalSql = dropSql2.arg(typeIt.key(), wrapObjIfNeeded(name, dialect));
+ finalSql = dropSql3.arg(typeIt.key(), dbName, wrapObjIfNeeded(name));
results = db->exec(finalSql);
if (results->isError())
@@ -339,8 +330,7 @@ DbObjectDialogs::Type DbObjectDialogs::getObjectType(const QString& database, co
static const QString typeSql = "SELECT type FROM %1.sqlite_master WHERE name = ?;";
static const QStringList types = {"table", "index", "trigger", "view"};
- Dialect dialect = db->getDialect();
- QString dbName = wrapObjIfNeeded(database, dialect);
+ QString dbName = wrapObjIfNeeded(database);
SqlQueryPtr results = db->exec(typeSql.arg(dbName), {name});
if (results->isError())
{
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbobjlistmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/dbobjlistmodel.cpp
index 00914a1..d5c72ee 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbobjlistmodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbobjlistmodel.cpp
@@ -110,7 +110,7 @@ QString DbObjListModel::typeString() const
case ObjectType::null:
break;
}
- return QString::null;
+ return QString();
}
bool DbObjListModel::getIncludeSystemObjects() const
{
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
index ba8ccc1..85a7047 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
@@ -26,10 +26,10 @@
#include "windows/editorwindow.h"
#include "uiconfig.h"
#include "themetuner.h"
-#include "dialogs/dbconverterdialog.h"
#include "querygenerator.h"
#include "dialogs/execfromfiledialog.h"
#include "dialogs/fileexecerrorsdialog.h"
+#include "common/compatibility.h"
#include <QApplication>
#include <QClipboard>
#include <QAction>
@@ -44,6 +44,7 @@
#include <QDesktopServices>
#include <QDir>
#include <QFileDialog>
+#include <QElapsedTimer>
#include <QtConcurrent/QtConcurrentRun>
CFG_KEYS_DEFINE(DbTree)
@@ -104,6 +105,7 @@ void DbTree::init()
connect(this, &DbTree::updateFileExecProgress, this, &DbTree::setFileExecProgress, Qt::QueuedConnection);
connect(this, &DbTree::fileExecCoverToBeClosed, this, &DbTree::hideFileExecCover, Qt::QueuedConnection);
connect(this, &DbTree::fileExecErrors, this, &DbTree::showFileExecErrors, Qt::QueuedConnection);
+ connect(this, SIGNAL(schemaNeedsRefreshing(Db*)), this, SLOT(refreshSchema(Db*)), Qt::QueuedConnection);
treeModel = new DbTreeModel();
treeModel->setTreeView(ui->treeView);
@@ -144,7 +146,6 @@ void DbTree::createActions()
createAction(DISCONNECT_FROM_DB, ICONS.DATABASE_DISCONNECT, tr("&Disconnect from the database"), this, SLOT(disconnectFromDb()), this);
createAction(IMPORT_INTO_DB, ICONS.IMPORT, tr("Import"), this, SLOT(import()), this);
createAction(EXPORT_DB, ICONS.DATABASE_EXPORT, tr("&Export the database"), this, SLOT(exportDb()), this);
- createAction(CONVERT_DB, ICONS.CONVERT_DB, tr("Con&vert database type"), this, SLOT(convertDb()), this);
createAction(VACUUM_DB, ICONS.VACUUM_DB, tr("Vac&uum"), this, SLOT(vacuumDb()), this);
createAction(INTEGRITY_CHECK, ICONS.INTEGRITY_CHECK, tr("&Integrity check"), this, SLOT(integrityCheck()), this);
createAction(ADD_TABLE, ICONS.TABLE_ADD, tr("Create a &table"), this, SLOT(addTable()), this);
@@ -207,7 +208,7 @@ void DbTree::updateActionStates(const QStandardItem *item)
enabled << DELETE_DB << EDIT_DB;
if (dbTreeItem->getDb()->isOpen())
{
- enabled << DISCONNECT_FROM_DB << ADD_TABLE << ADD_VIEW << IMPORT_INTO_DB << EXPORT_DB << REFRESH_SCHEMA << CONVERT_DB
+ enabled << DISCONNECT_FROM_DB << IMPORT_INTO_DB << EXPORT_DB << REFRESH_SCHEMA
<< VACUUM_DB << INTEGRITY_CHECK;
isDbOpen = true;
}
@@ -340,8 +341,14 @@ void DbTree::updateActionStates(const QStandardItem *item)
}
if (treeModel->rowCount() > 0)
+ {
enabled << SELECT_ALL; // if there's at least 1 item, enable this
+ // Table/view always enabled, as long as there is at least 1 db on the list. #4017
+ if (treeModel->findFirstItemOfType(DbTreeItem::Type::DB))
+ enabled << ADD_TABLE << ADD_VIEW;
+ }
+
enabled << REFRESH_SCHEMAS;
for (int action : actionMap.keys())
@@ -413,7 +420,6 @@ void DbTree::setupActionsForMenu(DbTreeItem* currItem, QMenu* contextMenu)
actions += ActionEntry(REFRESH_SCHEMA);
actions += ActionEntry(IMPORT_INTO_DB);
actions += ActionEntry(EXPORT_DB);
- actions += ActionEntry(CONVERT_DB);
actions += ActionEntry(VACUUM_DB);
actions += ActionEntry(INTEGRITY_CHECK);
actions += ActionEntry(EXEC_SQL_FROM_FILE);
@@ -715,7 +721,7 @@ bool DbTree::areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTre
{DbTreeItem::Type::INDEX, DbTreeItem::Type::INDEXES}
};
- if (!forPasting && srcTypes.toSet().size() == 1 && srcDbs.size() == 1 && dstItem &&
+ if (!forPasting && toSet(srcTypes).size() == 1 && srcDbs.size() == 1 && dstItem &&
*(srcDbs.begin()) == dstItem->getDb() && reorderingTypeToParent[srcTypes.first()] == dstType)
return true;
@@ -794,7 +800,7 @@ Db* DbTree::getSelectedOpenDb()
TableWindow* DbTree::openTable(DbTreeItem* item)
{
- QString database = QString::null; // TODO implement this when named databases (attached) are handled by dbtree.
+ QString database = QString(); // TODO implement this when named databases (attached) are handled by dbtree.
Db* db = item->getDb();
return openTable(db, database, item->text());
}
@@ -807,7 +813,7 @@ TableWindow* DbTree::openTable(Db* db, const QString& database, const QString& t
void DbTree::editIndex(DbTreeItem* item)
{
- //QString database = QString::null; // TODO implement this when named databases (attached) are handled by dbtree.
+ //QString database = QString(); // TODO implement this when named databases (attached) are handled by dbtree.
Db* db = item->getDb();
DbObjectDialogs dialogs(db);
@@ -816,7 +822,7 @@ void DbTree::editIndex(DbTreeItem* item)
ViewWindow* DbTree::openView(DbTreeItem* item)
{
- QString database = QString::null; // TODO implement this when named databases (attached) are handled by dbtree.
+ QString database = QString(); // TODO implement this when named databases (attached) are handled by dbtree.
Db* db = item->getDb();
return openView(db, database, item->text());
}
@@ -827,25 +833,21 @@ ViewWindow* DbTree::openView(Db* db, const QString& database, const QString& vie
return dialogs.editView(database, view);
}
-TableWindow* DbTree::newTable(DbTreeItem* item)
+TableWindow* DbTree::newTable(Db* db)
{
- Db* db = item->getDb();
-
DbObjectDialogs dialogs(db);
return dialogs.addTable();
}
-ViewWindow* DbTree::newView(DbTreeItem* item)
+ViewWindow* DbTree::newView(Db* db)
{
- Db* db = item->getDb();
-
DbObjectDialogs dialogs(db);
return dialogs.addView();
}
void DbTree::editTrigger(DbTreeItem* item)
{
- //QString database = QString::null; // TODO implement this when named databases (attached) are handled by dbtree.
+ //QString database = QString(); // TODO implement this when named databases (attached) are handled by dbtree.
Db* db = item->getDb();
DbObjectDialogs dialogs(db);
@@ -1161,7 +1163,7 @@ void DbTree::editDb()
void DbTree::removeDb()
{
- QList<Db*> dbList = getSelectedDatabases().toList();
+ QList<Db*> dbList = getSelectedDatabases().values();
if (dbList.isEmpty())
return;
@@ -1248,10 +1250,16 @@ void DbTree::addTable()
{
Db* db = getSelectedOpenDb();
if (!db || !db->isValid())
+ {
+ DbTreeItem* item = treeModel->findFirstItemOfType(DbTreeItem::Type::DB);
+ if (item)
+ db = item->getDb();
+ }
+
+ if (!db || !db->isValid())
return;
- DbTreeItem* item = ui->treeView->currentItem();
- newTable(item);
+ newTable(db);
}
void DbTree::editTable()
@@ -1267,7 +1275,7 @@ void DbTree::editTable()
return;
}
- openTable(db, QString::null, table); // TODO put database name when supported
+ openTable(db, QString(), table); // TODO put database name when supported
}
void DbTree::delTable()
@@ -1340,10 +1348,16 @@ void DbTree::addView()
{
Db* db = getSelectedOpenDb();
if (!db || !db->isValid())
+ {
+ DbTreeItem* item = treeModel->findFirstItemOfType(DbTreeItem::Type::DB);
+ if (item)
+ db = item->getDb();
+ }
+
+ if (!db || !db->isValid())
return;
- DbTreeItem* item = ui->treeView->currentItem();
- newView(item);
+ newView(db);
}
void DbTree::editView()
@@ -1463,17 +1477,6 @@ void DbTree::delColumn()
delColumn(item);
}
-void DbTree::convertDb()
-{
- Db* db = getSelectedDb();
- if (!db || !db->isValid())
- return;
-
- DbConverterDialog dialog(this);
- dialog.setDb(db);
- dialog.exec();
-}
-
void DbTree::vacuumDb()
{
Db* db = getSelectedDb();
@@ -1569,11 +1572,10 @@ void DbTree::eraseTableData()
return;
static_qstring(DELETE_SQL, "DELETE FROM %1;");
- Dialect dialect = db->getDialect();
SqlQueryPtr res;
for (const QString& table : tables)
{
- res = db->exec(DELETE_SQL.arg(wrapObjIfNeeded(table, dialect)));
+ res = db->exec(DELETE_SQL.arg(wrapObjIfNeeded(table)));
if (res->isError())
{
notifyError(tr("An error occurred while trying to delete data from table '%1': %2").arg(table, res->getErrorText()));
@@ -1898,7 +1900,7 @@ void DbTree::execFromFileAsync(const QString& path, Db* db, bool ignoreErrors, c
int executed = 0;
bool ok = true;
- QTime timer;
+ QElapsedTimer timer;
timer.start();
QList<QPair<QString, QString>> errors = executeFileQueries(db, stream, executed, attemptedExecutions, ok, ignoreErrors, fileSize);
int millis = timer.elapsed();
@@ -1935,8 +1937,11 @@ QList<QPair<QString, QString>> DbTree::executeFileQueries(Db* db, QTextStream& s
}
}
- if (sql.trimmed().isEmpty())
+ if (shouldSkipQueryFromFileExecution(sql))
+ {
+ sql.clear();;
continue;
+ }
results = db->exec(sql);
attemptedExecutions++;
@@ -1961,6 +1966,18 @@ QList<QPair<QString, QString>> DbTree::executeFileQueries(Db* db, QTextStream& s
return errors;
}
+bool DbTree::shouldSkipQueryFromFileExecution(const QString& sql)
+{
+ if (sql.trimmed().isEmpty())
+ return true;
+
+ QString upper = sql.toUpper().trimmed().split("\n").last().trimmed();
+ return (upper.startsWith("BEGIN") ||
+ upper.startsWith("COMMIT") ||
+ upper.startsWith("ROLLBACK") ||
+ upper.startsWith("END"));
+}
+
void DbTree::handleFileQueryExecution(Db* db, int executed, int attemptedExecutions, bool ok, bool ignoreErrors, int millis)
{
bool doCommit = ok ? true : ignoreErrors;
@@ -1968,17 +1985,20 @@ void DbTree::handleFileQueryExecution(Db* db, int executed, int attemptedExecuti
{
if (!db->commit())
{
- db->rollback();
notifyError(tr("Could not execute SQL, because application has failed to commit the transaction: %1").arg(db->getErrorText()));
+ db->rollback();
}
else if (!ok) // committed with errors
{
notifyInfo(tr("Finished executing %1 queries in %2 seconds. %3 were not executed due to errors.")
.arg(executed).arg(millis / 1000.0).arg(attemptedExecutions - executed));
+
+ emit schemaNeedsRefreshing(db);
}
else
{
notifyInfo(tr("Finished executing %1 queries in %2 seconds.").arg(executed).arg(millis / 1000.0));
+ emit schemaNeedsRefreshing(db);
}
}
else
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h
index f72ebda..62ef0df 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h
@@ -60,7 +60,6 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
DISCONNECT_FROM_DB,
IMPORT_INTO_DB,
EXPORT_DB,
- CONVERT_DB,
VACUUM_DB,
INTEGRITY_CHECK,
ADD_TABLE,
@@ -133,10 +132,10 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
void setActionEnabled(int action, bool enabled);
TableWindow* openTable(DbTreeItem* item);
TableWindow* openTable(Db* db, const QString& database, const QString& table);
- TableWindow* newTable(DbTreeItem* item);
+ TableWindow* newTable(Db* db);
ViewWindow* openView(DbTreeItem* item);
ViewWindow* openView(Db* db, const QString& database, const QString& view);
- ViewWindow* newView(DbTreeItem* item);
+ ViewWindow* newView(Db* db);
void editIndex(DbTreeItem* item);
void editTrigger(DbTreeItem* item);
void delSelectedObject();
@@ -156,6 +155,7 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
bool execQueryFromFile(Db* db, const QString& sql);
void handleFileQueryExecution(Db* db, int executed, int attemptedExecutions, bool ok, bool ignoreErrors, int millis);
QList<QPair<QString, QString>> executeFileQueries(Db* db, QTextStream& stream, int& executed, int& attemptedExecutions, bool& ok, bool ignoreErrors, qint64 fileSize);
+ bool shouldSkipQueryFromFileExecution(const QString& sql);
static bool areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTreeItem* dstItem, bool forPasting = false);
static bool areUrlsValidForItem(const QList<QUrl>& srcUrls, const DbTreeItem* dstItem);
@@ -210,7 +210,6 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
void addColumn();
void editColumn();
void delColumn();
- void convertDb();
void vacuumDb();
void integrityCheck();
void createSimilarTable();
@@ -241,6 +240,7 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
void updateFileExecProgress(int value);
void fileExecCoverToBeClosed();
void fileExecErrors(const QList<QPair<QString, QString>>& errors, bool rolledBack);
+ void schemaNeedsRefreshing(Db* db);
};
int qHash(DbTree::Action action);
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp
index ead5e3d..6514aa8 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitem.cpp
@@ -85,7 +85,7 @@ QString DbTreeItem::getTable() const
{
const DbTreeItem* item = getParentItem(Type::TABLE);
if (!item)
- return QString::null;
+ return QString();
return item->text();
}
@@ -93,7 +93,7 @@ QString DbTreeItem::getTable() const
QString DbTreeItem::getColumn() const
{
if (getType() != Type::COLUMN)
- return QString::null;
+ return QString();
return text();
}
@@ -102,7 +102,7 @@ QString DbTreeItem::getIndex() const
{
const DbTreeItem* item = getParentItem(Type::INDEX);
if (!item)
- return QString::null;
+ return QString();
return item->text();
}
@@ -111,7 +111,7 @@ QString DbTreeItem::getTrigger() const
{
const DbTreeItem* item = getParentItem(Type::TRIGGER);
if (!item)
- return QString::null;
+ return QString();
return item->text();
}
@@ -120,7 +120,7 @@ QString DbTreeItem::getView() const
{
const DbTreeItem* item = getParentItem(Type::VIEW);
if (!item)
- return QString::null;
+ return QString();
return item->text();
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitemdelegate.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitemdelegate.cpp
index ef691d2..552bd91 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitemdelegate.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeitemdelegate.cpp
@@ -133,7 +133,7 @@ void DbTreeItemDelegate::paintSystemIndexLabel(QPainter* painter, const QStyleOp
if (!db || !db->isValid())
return;
- if (!isSystemIndex(item->text(), db->getDialect()))
+ if (!isSystemIndex(item->text()))
return;
paintLabel(painter, option, index, item, tr("(system index)", "database tree label"));
@@ -147,7 +147,7 @@ void DbTreeItemDelegate::paintLabel(QPainter *painter, const QStyleOptionViewIte
painter->save();
// Colors
- painter->setPen(CFG_UI.Colors.DbTreeLabelsFg.get());
+ painter->setPen(QApplication::style()->standardPalette().link().color());
// Font
opt.font = CFG_UI.Fonts.DbTreeLabel.get();
@@ -155,7 +155,7 @@ void DbTreeItemDelegate::paintLabel(QPainter *painter, const QStyleOptionViewIte
painter->setFont(opt.font);
// Coords
- int x = option.rect.x() + option.fontMetrics.width(item->text()) + 15 + option.decorationSize.width();
+ int x = option.rect.x() + option.fontMetrics.horizontalAdvance(item->text()) + 15 + option.decorationSize.width();
int y = opt.rect.y() + (opt.rect.height() - opt.fontMetrics.descent() - opt.fontMetrics.ascent()) / 2 + opt.fontMetrics.ascent();
// Paint
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
index 123c4df..436ab50 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
@@ -14,6 +14,7 @@
#include "dialogs/versionconvertsummarydialog.h"
#include "db/invaliddb.h"
#include "services/notifymanager.h"
+#include "common/compatibility.h"
#include <QMimeData>
#include <QDebug>
#include <QFile>
@@ -202,6 +203,7 @@ QList<Config::DbGroupPtr> DbTreeModel::childsToConfig(QStandardItem *item)
group->referencedDbName = dbTreeItem->text();
group->order = i;
group->open = dbTreeItem->getDb()->isOpen();
+ group->dbExpanded = treeView->isExpanded(dbTreeItem->index());
groups += group;
break;
}
@@ -260,10 +262,7 @@ void DbTreeModel::restoreGroup(const Config::DbGroupPtr& group, QList<Db*>* dbLi
// Instead of that, we just check if the database is already open (by DbManager)
// and call proper handler to refresh database's schema and create tree nodes.
if (db->isOpen())
- {
- dbConnected(db);
- treeView->expand(item->index());
- }
+ dbConnected(db, group->dbExpanded);
}
else
{
@@ -394,7 +393,7 @@ QVariant DbTreeModel::data(const QModelIndex &index, int role) const
QString DbTreeModel::getToolTip(DbTreeItem* item) const
{
if (!item)
- return QString::null;
+ return QString();
switch (item->getType())
{
@@ -405,7 +404,7 @@ QString DbTreeModel::getToolTip(DbTreeItem* item) const
default:
break;
}
- return QString::null;
+ return QString();
}
QString DbTreeModel::getDbToolTip(DbTreeItem* item) const
@@ -552,13 +551,13 @@ QList<QStandardItem *> DbTreeModel::refreshSchemaTables(const QStringList &table
StrHash<QList<QStandardItem*>> DbTreeModel::refreshSchemaTableColumns(const StrHash<QStringList> &columns)
{
QStringList sortedColumns;
- bool sort = CFG_UI.General.SortColumns.get();
+ bool doSort = CFG_UI.General.SortColumns.get();
StrHash<QList<QStandardItem*>> items;
for (const QString& key : columns.keys())
{
sortedColumns = columns[key];
- if (sort)
- qSort(sortedColumns);
+ if (doSort)
+ ::sSort(sortedColumns);
for (const QString& column : sortedColumns)
items[key] += DbTreeItemFactory::createColumn(column, this);
@@ -681,7 +680,23 @@ void DbTreeModel::restoreExpandedState(const QHash<QString, bool>& expandedState
restoreExpandedState(expandedState, child);
}
-void DbTreeModel::dbConnected(Db* db)
+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);
if (!item)
@@ -690,12 +705,15 @@ void DbTreeModel::dbConnected(Db* db)
return;
}
refreshSchema(db, item);
- treeView->expand(item->index());
- if (CFG_UI.General.ExpandTables.get())
- treeView->expand(item->index().child(0, 0)); // also expand tables
+ if (expandItem)
+ {
+ treeView->expand(item->index());
+ if (CFG_UI.General.ExpandTables.get())
+ treeView->expand(item->model()->index(0, 0, item->index())); // also expand tables
- if (CFG_UI.General.ExpandViews.get())
- treeView->expand(item->index().child(1, 0)); // also expand views
+ if (CFG_UI.General.ExpandViews.get())
+ treeView->expand(item->model()->index(1, 0, item->index())); // also expand views
+ }
}
void DbTreeModel::dbDisconnected(Db* db)
@@ -798,6 +816,11 @@ DbTreeItem *DbTreeModel::findItem(DbTreeItem::Type type, Db* db)
return findItem(root(), type, db);
}
+DbTreeItem* DbTreeModel::findFirstItemOfType(DbTreeItem::Type type)
+{
+ return findFirstItemOfType(type, root());
+}
+
DbTreeItem *DbTreeModel::findItemBySignature(const QString &signature)
{
QStringList parts = signature.split("_");
@@ -953,7 +976,7 @@ bool DbTreeModel::pasteData(const QMimeData* data, int row, int column, const QM
DbTreeItem* dstItem = nullptr;
if (parent.isValid())
{
- QModelIndex idx = parent.child(row, column);
+ QModelIndex idx = index(row, column, parent);
if (idx.isValid())
dstItem = dynamic_cast<DbTreeItem*>(itemFromIndex(idx));
else // drop on top of the parent
@@ -1268,6 +1291,7 @@ void DbTreeModel::dbObjectsMoveFinished(bool success, Db* srcDb, Db* dstDb)
if (!success)
{
interruptableFinished(dbOrganizer);
+ DBTREE->refreshSchema(srcDb);
return;
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
index 9ba0d82..86dc8a6 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
@@ -27,6 +27,7 @@ class GUI_API_EXPORT DbTreeModel : public QStandardItemModel
void connectDbManagerSignals();
DbTreeItem* findItem(DbTreeItem::Type type, const QString &name);
DbTreeItem* findItem(DbTreeItem::Type type, Db* db);
+ DbTreeItem* findFirstItemOfType(DbTreeItem::Type type);
DbTreeItem* findItemBySignature(const QString& signature);
QList<DbTreeItem*> findItems(DbTreeItem::Type type);
void move(QStandardItem* itemToMove, QStandardItem* newParentItem, int newRow = -1);
@@ -69,14 +70,15 @@ class GUI_API_EXPORT DbTreeModel : public QStandardItemModel
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);
+ 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*> 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 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;
@@ -111,7 +113,7 @@ class GUI_API_EXPORT DbTreeModel : public QStandardItemModel
void dbAdded(Db* db);
void dbUpdated(const QString &oldName, Db* db);
void dbRemoved(Db* db);
- void dbConnected(Db* db);
+ void dbConnected(Db* db, bool expandItem = true);
void dbDisconnected(Db* db);
void dbUnloaded(Db* db);
void dbLoaded(Db* db);
diff --git a/SQLiteStudio3/guiSQLiteStudio/debugconsole.cpp b/SQLiteStudio3/guiSQLiteStudio/debugconsole.cpp
index 033eb1c..47387e6 100644
--- a/SQLiteStudio3/guiSQLiteStudio/debugconsole.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/debugconsole.cpp
@@ -51,7 +51,7 @@ void DebugConsole::initFormats()
fatFormat.setFontUnderline(true);
QFontMetrics fm(ui->textEdit->font());
- int indent = fm.width(QString("X").repeated(25));
+ int indent = fm.horizontalAdvance(QString("X").repeated(25));
ui->textEdit->document()->setIndentWidth(indent);
blockFormat.setIndent(1);
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.cpp
index 82d5e14..7e084fb 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/aboutdialog.cpp
@@ -120,7 +120,7 @@ QString AboutDialog::readFile(const QString& path)
if (!file.open(QIODevice::ReadOnly))
{
qCritical() << "Error opening" << file.fileName();
- return QString::null;
+ return QString();
}
QString contents = QString::fromLatin1(file.readAll()).toHtmlEscaped();
file.close();
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp
index 8bf1698..ebf9253 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.cpp
@@ -62,6 +62,7 @@ void ColumnDialog::init()
connect(ui->fkButton, SIGNAL(clicked()), this, SLOT(configureFk()));
connect(ui->checkButton, SIGNAL(clicked()), this, SLOT(configureCheck()));
connect(ui->defaultButton, SIGNAL(clicked()), this, SLOT(configureDefault()));
+ connect(ui->generatedButton, SIGNAL(clicked()), this, SLOT(configureGenerated()));
connect(ui->notNullButton, SIGNAL(clicked()), this, SLOT(configureNotNull()));
connect(ui->collateButton, SIGNAL(clicked()), this, SLOT(configureCollate()));
connect(ui->uniqueButton, SIGNAL(clicked()), this, SLOT(configureUnique()));
@@ -95,6 +96,7 @@ void ColumnDialog::createActions()
createAction(ADD_CHECK, ICONS.CONSTRAINT_CHECK_ADD, tr("Add a check constraint", "column dialog"), this, SLOT(addCheck()), ui->constraintsToolbar);
createAction(ADD_NOT_NULL, ICONS.CONSTRAINT_NOT_NULL_ADD, tr("Add a not null constraint", "column dialog"), this, SLOT(addNotNull()), ui->constraintsToolbar);
createAction(ADD_COLLATE, ICONS.CONSTRAINT_COLLATION_ADD, tr("Add a collate constraint", "column dialog"), this, SLOT(addCollate()), ui->constraintsToolbar);
+ createAction(ADD_GENERATED, ICONS.CONSTRAINT_GENERATED_ADD, tr("Add a generated value constraint", "column dialog"), this, SLOT(addGenerated()), ui->constraintsToolbar);
createAction(ADD_DEFAULT, ICONS.CONSTRAINT_DEFAULT_ADD, tr("Add a default constraint", "column dialog"), this, SLOT(addDefault()), ui->constraintsToolbar);
}
@@ -128,6 +130,7 @@ void ColumnDialog::updateState()
ui->notNullButton->setEnabled(ui->notNullCheck->isChecked());
ui->checkButton->setEnabled(ui->checkCheck->isChecked());
ui->collateButton->setEnabled(ui->collateCheck->isChecked());
+ ui->generatedButton->setEnabled(ui->generatedCheck->isChecked());
ui->defaultButton->setEnabled(ui->defaultCheck->isChecked());
updateConstraintsToolbarState();
}
@@ -135,6 +138,9 @@ void ColumnDialog::updateState()
void ColumnDialog::addConstraint(ConstraintDialog::Constraint mode)
{
NewConstraintDialog dialog(mode, column.data(), db, this);
+ for (ConstraintDialog::Constraint constraint : disabledConstraints)
+ dialog.disableMode(constraint);
+
if (dialog.exec() != QDialog::Accepted)
return;
@@ -160,6 +166,7 @@ void ColumnDialog::setupConstraintCheckBoxes()
ui->notNullCheck->setIcon(ICONS.CONSTRAINT_NOT_NULL);
ui->checkCheck->setIcon(ICONS.CONSTRAINT_CHECK);
ui->collateCheck->setIcon(ICONS.CONSTRAINT_COLLATION);
+ ui->generatedCheck->setIcon(ICONS.CONSTRAINT_GENERATED);
ui->defaultCheck->setIcon(ICONS.CONSTRAINT_DEFAULT);
connect(ui->pkCheck, SIGNAL(clicked(bool)), this, SLOT(pkToggled(bool)));
@@ -168,6 +175,7 @@ void ColumnDialog::setupConstraintCheckBoxes()
connect(ui->notNullCheck, SIGNAL(clicked(bool)), this, SLOT(notNullToggled(bool)));
connect(ui->checkCheck, SIGNAL(clicked(bool)), this, SLOT(checkToggled(bool)));
connect(ui->collateCheck, SIGNAL(clicked(bool)), this, SLOT(collateToggled(bool)));
+ connect(ui->generatedCheck, SIGNAL(clicked(bool)), this, SLOT(generatedToggled(bool)));
connect(ui->defaultCheck, SIGNAL(clicked(bool)), this, SLOT(defaultToggled(bool)));
for (QCheckBox* cb : {
@@ -177,6 +185,7 @@ void ColumnDialog::setupConstraintCheckBoxes()
ui->notNullCheck,
ui->checkCheck,
ui->collateCheck,
+ ui->generatedCheck,
ui->defaultCheck
})
{
@@ -293,15 +302,7 @@ void ColumnDialog::updateConstraintState(SqliteCreateTable::Column::Constraint*
}
QString errMsg = tr("Correct the constraint's configuration.");
- if (db->getDialect() == Dialect::Sqlite2 && isUnofficialSqlite2Constraint(constraint))
- {
- QString tooltip = tr("This constraint is not officially supported by SQLite 2,\nbut it's okay to use it.");
- setValidStateWihtTooltip(toolButton, tooltip, result, errMsg);
- }
- else
- {
- setValidState(toolButton, result, errMsg);
- }
+ setValidState(toolButton, result, errMsg);
if (!result)
{
@@ -326,6 +327,8 @@ QCheckBox* ColumnDialog::getCheckBoxForConstraint(SqliteCreateTable::Column::Con
return ui->defaultCheck;
case SqliteCreateTable::Column::Constraint::COLLATE:
return ui->collateCheck;
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return ui->generatedCheck;
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return ui->fkCheck;
case SqliteCreateTable::Column::Constraint::NULL_:
@@ -352,6 +355,8 @@ QToolButton* ColumnDialog::getToolButtonForConstraint(SqliteCreateTable::Column:
return ui->defaultButton;
case SqliteCreateTable::Column::Constraint::COLLATE:
return ui->collateButton;
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return ui->generatedButton;
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return ui->fkButton;
case SqliteCreateTable::Column::Constraint::NULL_:
@@ -362,26 +367,6 @@ QToolButton* ColumnDialog::getToolButtonForConstraint(SqliteCreateTable::Column:
return nullptr;
}
-bool ColumnDialog::isUnofficialSqlite2Constraint(SqliteCreateTable::Column::Constraint* constraint)
-{
- switch (constraint->type)
- {
- case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
- case SqliteCreateTable::Column::Constraint::COLLATE:
- return true;
- case SqliteCreateTable::Column::Constraint::PRIMARY_KEY:
- case SqliteCreateTable::Column::Constraint::NOT_NULL:
- case SqliteCreateTable::Column::Constraint::UNIQUE:
- case SqliteCreateTable::Column::Constraint::CHECK:
- case SqliteCreateTable::Column::Constraint::DEFAULT:
- case SqliteCreateTable::Column::Constraint::NULL_:
- case SqliteCreateTable::Column::Constraint::NAME_ONLY:
- case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY:
- break;
- }
- return false;
-}
-
void ColumnDialog::updateTypeValidations()
{
QString scaleErrorMsg = tr("Scale is not allowed for INTEGER PRIMARY KEY columns.");
@@ -503,6 +488,11 @@ void ColumnDialog::addNotNull()
addConstraint(ConstraintDialog::NOTNULL);
}
+void ColumnDialog::addGenerated()
+{
+ addConstraint(ConstraintDialog::GENERATED);
+}
+
void ColumnDialog::addDefault()
{
addConstraint(ConstraintDialog::DEFAULT);
@@ -538,6 +528,11 @@ void ColumnDialog::configureNotNull()
configureConstraint(SqliteCreateTable::Column::Constraint::NOT_NULL);
}
+void ColumnDialog::configureGenerated()
+{
+ configureConstraint(SqliteCreateTable::Column::Constraint::GENERATED);
+}
+
void ColumnDialog::configureDefault()
{
configureConstraint(SqliteCreateTable::Column::Constraint::DEFAULT);
@@ -569,6 +564,11 @@ void ColumnDialog::collateToggled(bool enabled)
constraintToggled(SqliteCreateTable::Column::Constraint::COLLATE, enabled);
}
+void ColumnDialog::generatedToggled(bool enabled)
+{
+ constraintToggled(SqliteCreateTable::Column::Constraint::GENERATED, enabled);
+}
+
void ColumnDialog::notNullToggled(bool enabled)
{
constraintToggled(SqliteCreateTable::Column::Constraint::NOT_NULL, enabled);
@@ -596,6 +596,7 @@ void ColumnDialog::updateValidations()
ui->notNullCheck,
ui->checkCheck,
ui->collateCheck,
+ ui->generatedCheck,
ui->defaultCheck
})
{
@@ -609,6 +610,7 @@ void ColumnDialog::updateValidations()
ui->notNullButton,
ui->checkButton,
ui->collateButton,
+ ui->generatedButton,
ui->defaultButton
})
{
@@ -663,6 +665,47 @@ QToolBar* ColumnDialog::getToolBar(int toolbar) const
return nullptr;
}
+void ColumnDialog::disableConstraint(ConstraintDialog::Constraint constraint)
+{
+ disabledConstraints << constraint;
+ switch (constraint) {
+ case ConstraintDialog::PK:
+ ui->pkCheck->setEnabled(false);
+ actionMap[ADD_PK]->setEnabled(false);
+ break;
+ case ConstraintDialog::FK:
+ ui->fkCheck->setEnabled(false);
+ actionMap[ADD_FK]->setEnabled(false);
+ break;
+ case ConstraintDialog::UNIQUE:
+ ui->uniqueCheck->setEnabled(false);
+ actionMap[ADD_UNIQUE]->setEnabled(false);
+ break;
+ case ConstraintDialog::NOTNULL:
+ ui->notNullCheck->setEnabled(false);
+ actionMap[ADD_NOT_NULL]->setEnabled(false);
+ break;
+ case ConstraintDialog::CHECK:
+ ui->checkCheck->setEnabled(false);
+ actionMap[ADD_CHECK]->setEnabled(false);
+ break;
+ case ConstraintDialog::COLLATE:
+ ui->collateCheck->setEnabled(false);
+ actionMap[ADD_COLLATE]->setEnabled(false);
+ break;
+ case ConstraintDialog::GENERATED:
+ ui->generatedCheck->setEnabled(false);
+ actionMap[ADD_GENERATED]->setEnabled(false);
+ break;
+ case ConstraintDialog::DEFAULT:
+ ui->defaultCheck->setEnabled(false);
+ actionMap[ADD_DEFAULT]->setEnabled(false);
+ break;
+ case ConstraintDialog::UNKNOWN:
+ break;
+ }
+}
+
void ColumnDialog::updateDataType()
{
if (!column)
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h
index 47615e8..c9faf23 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.h
@@ -34,6 +34,7 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer
ADD_CHECK,
ADD_DEFAULT,
ADD_NOT_NULL,
+ ADD_GENERATED,
ADD_COLLATE
};
@@ -48,6 +49,7 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer
void setColumn(SqliteCreateTable::Column* value);
SqliteCreateTable::Column* getModifiedColumn();
QToolBar* getToolBar(int toolbar) const;
+ void disableConstraint(ConstraintDialog::Constraint constraint);
protected:
void changeEvent(QEvent *e);
@@ -66,7 +68,6 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer
void updateConstraintState(SqliteCreateTable::Column::Constraint* constraint);
QCheckBox* getCheckBoxForConstraint(SqliteCreateTable::Column::Constraint* constraint);
QToolButton* getToolButtonForConstraint(SqliteCreateTable::Column::Constraint* constraint);
- bool isUnofficialSqlite2Constraint(SqliteCreateTable::Column::Constraint* constraint);
void updateTypeValidations();
void updateTypeForAutoIncr();
bool hasAutoIncr() const;
@@ -77,6 +78,7 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer
QCheckBox* modeCheckBox = nullptr;
Db* db = nullptr;
bool integerTypeEnforced = false;
+ QSet<ConstraintDialog::Constraint> disabledConstraints;
private slots:
void updateConstraintsToolbarState();
@@ -93,12 +95,14 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer
void addCheck();
void addCollate();
void addNotNull();
+ void addGenerated();
void addDefault();
void configurePk();
void configureFk();
void configureUnique();
void configureCheck();
void configureCollate();
+ void configureGenerated();
void configureNotNull();
void configureDefault();
void pkToggled(bool enabled);
@@ -106,6 +110,7 @@ class GUI_API_EXPORT ColumnDialog : public QDialog, public ExtActionContainer
void uniqueToggled(bool enabled);
void checkToggled(bool enabled);
void collateToggled(bool enabled);
+ void generatedToggled(bool enabled);
void notNullToggled(bool enabled);
void defaultToggled(bool enabled);
void switchMode(bool advanced);
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.ui
index 1ac6cbb..6094ab1 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>424</width>
- <height>360</height>
+ <width>467</width>
+ <height>393</height>
</rect>
</property>
<property name="windowTitle">
@@ -109,31 +109,31 @@
</property>
<widget class="QWidget" name="simplePage">
<layout class="QGridLayout" name="gridLayout_2">
- <item row="3" column="0">
- <widget class="QCheckBox" name="uniqueCheck">
+ <item row="2" column="1">
+ <widget class="QToolButton" name="fkButton">
<property name="text">
- <string>Unique</string>
+ <string>Configure</string>
</property>
</widget>
</item>
- <item row="1" column="1">
- <widget class="QToolButton" name="pkButton">
+ <item row="7" column="0">
+ <widget class="QCheckBox" name="generatedCheck">
<property name="text">
- <string>Configure</string>
+ <string>Generated value</string>
</property>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QCheckBox" name="fkCheck">
+ <item row="5" column="0">
+ <widget class="QCheckBox" name="notNullCheck">
<property name="text">
- <string>Foreign Key</string>
+ <string>Not NULL</string>
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QToolButton" name="fkButton">
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="fkCheck">
<property name="text">
- <string>Configure</string>
+ <string>Foreign Key</string>
</property>
</widget>
</item>
@@ -144,17 +144,24 @@
</property>
</widget>
</item>
- <item row="5" column="0">
- <widget class="QCheckBox" name="notNullCheck">
+ <item row="4" column="0">
+ <widget class="QCheckBox" name="checkCheck">
<property name="text">
- <string>Not NULL</string>
+ <string>Check condition</string>
</property>
</widget>
</item>
- <item row="4" column="0">
- <widget class="QCheckBox" name="checkCheck">
+ <item row="3" column="0">
+ <widget class="QCheckBox" name="uniqueCheck">
<property name="text">
- <string>Check condition</string>
+ <string>Unique</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QToolButton" name="uniqueButton">
+ <property name="text">
+ <string>Configure</string>
</property>
</widget>
</item>
@@ -165,43 +172,50 @@
</property>
</widget>
</item>
- <item row="7" column="0">
- <widget class="QCheckBox" name="defaultCheck">
+ <item row="5" column="1">
+ <widget class="QToolButton" name="notNullButton">
<property name="text">
- <string>Default</string>
+ <string>Configure</string>
</property>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QToolButton" name="uniqueButton">
+ <item row="6" column="1">
+ <widget class="QToolButton" name="collateButton">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
- <item row="4" column="1">
- <widget class="QToolButton" name="checkButton">
+ <item row="8" column="1">
+ <widget class="QToolButton" name="defaultButton">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
- <item row="5" column="1">
- <widget class="QToolButton" name="notNullButton">
+ <item row="1" column="1">
+ <widget class="QToolButton" name="pkButton">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
- <item row="6" column="1">
- <widget class="QToolButton" name="collateButton">
+ <item row="8" column="0">
+ <widget class="QCheckBox" name="defaultCheck">
+ <property name="text">
+ <string>Default</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QToolButton" name="checkButton">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="7" column="1">
- <widget class="QToolButton" name="defaultButton">
+ <widget class="QToolButton" name="generatedButton">
<property name="text">
<string>Configure</string>
</property>
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.cpp
index 853b680..1107ef5 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.cpp
@@ -147,6 +147,9 @@ QIcon ColumnDialogConstraintsModel::getIcon(int rowIdx) const
return ICONS.CONSTRAINT_DEFAULT;
case SqliteCreateTable::Column::Constraint::COLLATE:
return ICONS.CONSTRAINT_COLLATION;
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return (constr->generatedType == SqliteCreateTable::Column::Constraint::GeneratedType::STORED) ?
+ ICONS.CONSTRAINT_GENERATED_STORED : ICONS.CONSTRAINT_GENERATED_VIRTUAL;
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return ICONS.CONSTRAINT_FOREIGN_KEY;
case SqliteCreateTable::Column::Constraint::NULL_:
@@ -180,6 +183,8 @@ QString ColumnDialogConstraintsModel::getType(int rowIdx) const
return "DEFAULT";
case SqliteCreateTable::Column::Constraint::COLLATE:
return "COLLATE";
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return "GENERATED";
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return "FOREIGN KEY";
case SqliteCreateTable::Column::Constraint::NULL_:
@@ -187,7 +192,7 @@ QString ColumnDialogConstraintsModel::getType(int rowIdx) const
case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY:
break;
}
- return QString::null;
+ return QString();
}
QString ColumnDialogConstraintsModel::getDetails(int rowIdx) const
@@ -207,6 +212,8 @@ QString ColumnDialogConstraintsModel::getDetails(int rowIdx) const
return getDefaultDetails(constr);
case SqliteCreateTable::Column::Constraint::COLLATE:
return getCollateDetails(constr);
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return getGeneratedDetails(constr);
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return getFkDetails(constr);
case SqliteCreateTable::Column::Constraint::NULL_:
@@ -214,7 +221,7 @@ QString ColumnDialogConstraintsModel::getDetails(int rowIdx) const
case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY:
break;
}
- return QString::null;
+ return QString();
}
QString ColumnDialogConstraintsModel::getPkDetails(SqliteCreateTable::Column::Constraint* constr) const
@@ -241,6 +248,12 @@ QString ColumnDialogConstraintsModel::getCheckDetails(SqliteCreateTable::Column:
return getConstrDetails(constr, idx);
}
+QString ColumnDialogConstraintsModel::getGeneratedDetails(SqliteCreateTable::Column::Constraint* constr) const
+{
+ int idx = constr->tokens.indexOf(Token::KEYWORD, "AS", Qt::CaseInsensitive);
+ return getConstrDetails(constr, idx);
+}
+
QString ColumnDialogConstraintsModel::getDefaultDetails(SqliteCreateTable::Column::Constraint* constr) const
{
int idx = constr->tokens.indexOf(Token::KEYWORD, "DEFAULT", Qt::CaseInsensitive);
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.h
index f37933a..aed7a28 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/columndialogconstraintsmodel.h
@@ -44,6 +44,7 @@ class GUI_API_EXPORT ColumnDialogConstraintsModel : public QAbstractTableModel
QString getNotNullDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getUniqueDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getCheckDetails(SqliteCreateTable::Column::Constraint* constr) const;
+ QString getGeneratedDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getDefaultDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getCollateDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getFkDetails(SqliteCreateTable::Column::Constraint* constr) const;
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp
index 63af58a..be45873 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.cpp
@@ -22,6 +22,9 @@
#include "datatype.h"
#include "uiutils.h"
#include "translations.h"
+#include "plugins/uiconfiguredplugin.h"
+#include "dbtree/dbtree.h"
+#include "common/compatibility.h"
#include <QSignalMapper>
#include <QLineEdit>
#include <QSpinBox>
@@ -37,8 +40,6 @@
#include <QDesktopServices>
#include <QtUiTools/QUiLoader>
#include <QKeySequenceEdit>
-#include <plugins/uiconfiguredplugin.h>
-#include <dbtree/dbtree.h>
#define GET_FILTER_STRING(Widget, WidgetType, Method) \
if (qobject_cast<WidgetType*>(Widget))\
@@ -117,7 +118,7 @@ QString ConfigDialog::getFilterString(QWidget *widget)
GET_FILTER_STRING2(widget, QListWidget);
GET_FILTER_STRING2(widget, QTableWidget);
- return QString::null;
+ return QString();
}
QString ConfigDialog::getFilterString(QComboBox *widget)
@@ -201,7 +202,9 @@ void ConfigDialog::init()
for (CfgEntry* cfg : entries)
connect(cfg, SIGNAL(changed(QVariant)), this, SLOT(markRequiresSchemasRefresh()));
- ui->activeStyleCombo->addItems(QStyleFactory::keys());
+ QStringList styles = QStyleFactory::keys();
+ styles.sort(Qt::CaseInsensitive);
+ ui->activeStyleCombo->addItems(styles);
connect(ui->stackedWidget, SIGNAL(currentChanged(int)), this, SLOT(pageSwitched()));
@@ -384,7 +387,7 @@ QList<MultiEditorWidgetPlugin*> ConfigDialog::getDefaultEditorsForType(DataType:
sortedPlugins << editorWithPrio;
}
- qSort(sortedPlugins.begin(), sortedPlugins.end(), [=](const PluginWithPriority& p1, const PluginWithPriority& p2) -> bool
+ sSort(sortedPlugins, [=](const PluginWithPriority& p1, const PluginWithPriority& p2) -> bool
{
return p1.first < p2.first;
});
@@ -446,7 +449,7 @@ QList<MultiEditorWidgetPlugin*> ConfigDialog::updateCustomDataTypeEditors(const
ui->dataEditorsAvailableList->addItem(item);
}
- qSort(enabledPlugins.begin(), enabledPlugins.end(), [=](MultiEditorWidgetPlugin* p1, MultiEditorWidgetPlugin* p2) -> bool
+ sSort(enabledPlugins, [=](MultiEditorWidgetPlugin* p1, MultiEditorWidgetPlugin* p2) -> bool
{
return editorsOrder.indexOf(p1->getName()) < editorsOrder.indexOf(p2->getName());
});
@@ -920,9 +923,9 @@ void ConfigDialog::updateBuiltInPluginsVisibility()
{
it.next();
if (PLUGINS->isBuiltIn(it.value()))
- ui->pluginsList->setItemHidden(it.key(), hideBuiltIn);
+ it.key()->setHidden(hideBuiltIn);
else
- ui->pluginsList->setItemHidden(it.key(), false);
+ it.key()->setHidden(false);
}
}
@@ -1053,7 +1056,7 @@ void ConfigDialog::refreshFormattersPage()
pluginTitles << plugin->getTitle();
}
sortedPluginNames = pluginNames;
- qSort(sortedPluginNames);
+ sSort(sortedPluginNames);
combo = new QComboBox(ui->formatterPluginsTree);
for (int i = 0, total = pluginNames.size(); i < total; ++i)
@@ -1092,6 +1095,7 @@ void ConfigDialog::refreshFormattersPage()
void ConfigDialog::applyStyle(QWidget *widget, QStyle *style)
{
widget->setStyle(style);
+ widget->setPalette(style->standardPalette());
for (QObject* child : widget->children())
{
if (!qobject_cast<QWidget*>(child))
@@ -1250,7 +1254,7 @@ void ConfigDialog::initPluginsPage()
categoryRow = 0;
QList<PluginType*> pluginTypes = PLUGINS->getPluginTypes();
- qSort(pluginTypes.begin(), pluginTypes.end(), PluginType::nameLessThan);
+ sSort(pluginTypes, PluginType::nameLessThan);
for (PluginType* pluginType : pluginTypes)
{
category = new QTreeWidgetItem({pluginType->getTitle()});
@@ -1270,7 +1274,7 @@ void ConfigDialog::initPluginsPage()
itemRow = 0;
pluginNames = pluginType->getAllPluginNames();
- qSort(pluginNames);
+ sSort(pluginNames);
for (const QString& pluginName : pluginNames)
{
builtIn = PLUGINS->isBuiltIn(pluginName);
@@ -1388,10 +1392,10 @@ void ConfigDialog::initDataEditors()
ui->dataEditorsAvailableList->setSpacing(1);
QHash<QString,QVariant> editorsOrder = CFG_UI.General.DataEditorsOrder.get();
- QSet<QString> dataTypeSet = editorsOrder.keys().toSet();
- dataTypeSet += DataType::getAllNames().toSet();
- QStringList dataTypeList = dataTypeSet.toList();
- qSort(dataTypeList);
+ QSet<QString> dataTypeSet = toSet(editorsOrder.keys());
+ dataTypeSet += toSet(DataType::getAllNames());
+ QStringList dataTypeList = dataTypeSet.values();
+ sSort(dataTypeList);
QListWidgetItem* item = nullptr;
for (const QString& type : dataTypeList)
@@ -1452,7 +1456,7 @@ void ConfigDialog::initShortcuts()
categories << cat;
}
- qSort(categories.begin(), categories.end(), [](CfgCategory* cat1, CfgCategory* cat2) -> bool
+ sSort(categories, [](CfgCategory* cat1, CfgCategory* cat2) -> bool
{
return cat1->getTitle().compare(cat2->getTitle()) < 0;
});
@@ -1503,7 +1507,7 @@ void ConfigDialog::initShortcuts(CfgCategory *cfgCategory)
int itemRow = 0;
QStringList entryNames = cfgCategory->getEntries().keys();
- qSort(entryNames);
+ sSort(entryNames);
for (const QString& entryName : entryNames)
{
// Title
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui
index fe0b772..4452f63 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/configdialog.ui
@@ -148,18 +148,6 @@
<normaloff>:/icons/img/config_font.png</normaloff>:/icons/img/config_font.png</iconset>
</property>
</item>
- <item>
- <property name="text">
- <string>Colors</string>
- </property>
- <property name="statusTip">
- <string notr="true">colorsPage</string>
- </property>
- <property name="icon">
- <iconset resource="../icons.qrc">
- <normaloff>:/icons/img/config_colors.png</normaloff>:/icons/img/config_colors.png</iconset>
- </property>
- </item>
</item>
<item>
<property name="text">
@@ -229,7 +217,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
- <number>3</number>
+ <number>1</number>
</property>
<widget class="QWidget" name="databaseListPage">
<layout class="QVBoxLayout" name="verticalLayout_36">
@@ -407,8 +395,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>577</width>
- <height>472</height>
+ <width>564</width>
+ <height>540</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_34">
@@ -418,29 +406,6 @@
<string>Data browsing and editing</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
- <item row="2" column="0" colspan="2">
- <widget class="QLabel" name="label_2">
- <property name="toolTip">
- <string>&lt;p&gt;Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.&lt;/p&gt;</string>
- </property>
- <property name="text">
- <string>Number of memorized table populating configurations</string>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QSpinBox" name="spinBox">
- <property name="toolTip">
- <string>&lt;p&gt;Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.&lt;/p&gt;</string>
- </property>
- <property name="maximum">
- <number>999999</number>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">General.PopulateHistorySize</string>
- </property>
- </widget>
- </item>
<item row="0" column="2">
<widget class="QSpinBox" name="rowsPerPageSpin">
<property name="maximumSize">
@@ -460,7 +425,7 @@
</property>
</widget>
</item>
- <item row="1" column="2">
+ <item row="2" column="2">
<widget class="QSpinBox" name="initColWidthLimitSpin">
<property name="toolTip">
<string>&lt;p&gt;When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.&lt;/p&gt;</string>
@@ -479,7 +444,14 @@
</property>
</widget>
</item>
- <item row="1" column="0" colspan="2">
+ <item row="0" column="0" colspan="2">
+ <widget class="QLabel" name="rowsPerPageLabel">
+ <property name="text">
+ <string>Number of data rows per page:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
<widget class="QLabel" name="initColWidthLimitLabel">
<property name="toolTip">
<string>&lt;p&gt;When the data is read into grid view columns width is automatically adjusted. This value limits the initial width for the adjustment, but user can still resize the column manually over this limit.&lt;/p&gt;</string>
@@ -489,14 +461,43 @@
</property>
</widget>
</item>
- <item row="0" column="0" colspan="2">
- <widget class="QLabel" name="rowsPerPageLabel">
+ <item row="6" column="0" colspan="3">
+ <widget class="QCheckBox" name="useDefaultForNullCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.&lt;/p&gt;&lt;p&gt;Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
<property name="text">
- <string>Number of data rows per page:</string>
+ <string>Use DEFAULT value (if defined), when committing NULL value</string>
+ </property>
+ <property name="cfg" stdset="0">
+ <string notr="true">General.UseDefaultValueForNull</string>
</property>
</widget>
</item>
- <item row="3" column="0" colspan="3">
+ <item row="3" column="2">
+ <widget class="QSpinBox" name="spinBox">
+ <property name="toolTip">
+ <string>&lt;p&gt;Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.&lt;/p&gt;</string>
+ </property>
+ <property name="maximum">
+ <number>999999</number>
+ </property>
+ <property name="cfg" stdset="0">
+ <string notr="true">General.PopulateHistorySize</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QLabel" name="label_2">
+ <property name="toolTip">
+ <string>&lt;p&gt;Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.&lt;/p&gt;</string>
+ </property>
+ <property name="text">
+ <string>Number of memorized table populating configurations</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="3">
<widget class="QCheckBox" name="tolltipInDataViewCheck">
<property name="toolTip">
<string>&lt;p&gt;When this is enabled and user holds mouse pointer over a cell in any data view (query results, a table data, a view data) a tooltip will appear with details about the cell - it includes details like column data type, constraints, ROWID and others.&lt;/p&gt;</string>
@@ -509,7 +510,7 @@
</property>
</widget>
</item>
- <item row="4" column="0" colspan="3">
+ <item row="5" column="0" colspan="3">
<widget class="QCheckBox" name="keepNullWhenEmptyCheck">
<property name="toolTip">
<string>&lt;p&gt;When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).&lt;/p&gt;</string>
@@ -522,16 +523,16 @@
</property>
</widget>
</item>
- <item row="5" column="0" colspan="3">
- <widget class="QCheckBox" name="useDefaultForNullCheck">
+ <item row="1" column="0" colspan="3">
+ <widget class="QCheckBox" name="checkBox">
<property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable this to always enforce DEFAULT value when committing a NULL value for a column that has DEFAULT value defined, even though the column is allowed to contain NULL values.&lt;/p&gt;&lt;p&gt;Disable this option to use DEFAULT value exclusively when NULL value is committed for column with NOT NULL constraint.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If query results contain dozens (or hundreds) of columns, it is more likely that it will exhaust free memory of your computer by loading several gigabytes of data at once. SQLiteStudio may try to limit number of results displayed on one page in such cases to protect your computer. If you know that you don't work with big values in database, you can disable this limit and you will always see as many rows as defined per page.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
- <string>Use DEFAULT value (if defined), when committing NULL value</string>
+ <string>Limit number of rows for in case of dozens of columns</string>
</property>
<property name="cfg" stdset="0">
- <string notr="true">General.UseDefaultValueForNull</string>
+ <string>General.LimitRowsForManyColumns</string>
</property>
</widget>
</item>
@@ -934,6 +935,16 @@
</property>
</widget>
</item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="multipleSessionsCheck">
+ <property name="text">
+ <string>Allow multiple instances of the application at the same time</string>
+ </property>
+ <property name="cfg" stdset="0">
+ <string>General.AllowMultipleSessions</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -1021,12 +1032,12 @@
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
- <attribute name="headerDefaultSectionSize">
- <number>150</number>
- </attribute>
<attribute name="headerMinimumSectionSize">
<number>16</number>
</attribute>
+ <attribute name="headerDefaultSectionSize">
+ <number>150</number>
+ </attribute>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
@@ -1073,8 +1084,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>335</width>
- <height>237</height>
+ <width>339</width>
+ <height>264</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_31">
@@ -1585,8 +1596,8 @@ p, li { white-space: pre-wrap; }
<rect>
<x>0</x>
<y>0</y>
- <width>196</width>
- <height>263</height>
+ <width>206</width>
+ <height>298</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
@@ -1689,542 +1700,6 @@ p, li { white-space: pre-wrap; }
</item>
</layout>
</widget>
- <widget class="QWidget" name="colorsPage">
- <layout class="QVBoxLayout" name="verticalLayout_11">
- <item>
- <widget class="QScrollArea" name="scrollArea">
- <property name="frameShape">
- <enum>QFrame::NoFrame</enum>
- </property>
- <property name="lineWidth">
- <number>0</number>
- </property>
- <property name="widgetResizable">
- <bool>true</bool>
- </property>
- <widget class="QWidget" name="colorsWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>247</width>
- <height>701</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_12">
- <item>
- <widget class="QGroupBox" name="sqlEditorColorsGroup">
- <property name="title">
- <string>SQL editor colors</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="14" column="0">
- <widget class="QLabel" name="sqlEditorCurrLineBgLabel">
- <property name="text">
- <string>Current line background</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="sqlEditorStringFgLabel">
- <property name="toolTip">
- <string>&lt;p&gt;SQL strings are enclosed with single quote characters.&lt;/p&gt;</string>
- </property>
- <property name="text">
- <string>String foreground</string>
- </property>
- </widget>
- </item>
- <item row="6" column="1">
- <widget class="ColorButton" name="sqlEditorKeywordFgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorKeywordFg</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="ColorButton" name="sqlEditorStringFgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorStringFg</string>
- </property>
- </widget>
- </item>
- <item row="9" column="1">
- <widget class="ColorButton" name="sqlEditorCommentFgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorCommentFg</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="ColorButton" name="sqlEditorRegularFgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorForeground</string>
- </property>
- </widget>
- </item>
- <item row="14" column="1">
- <widget class="ColorButton" name="sqlEditorCurrLineBgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorCurrentLineBg</string>
- </property>
- </widget>
- </item>
- <item row="16" column="1">
- <widget class="ColorButton" name="sqlEditorLineNumAreaBgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorLineNumAreaBg</string>
- </property>
- </widget>
- </item>
- <item row="12" column="0">
- <widget class="QLabel" name="sqlEditorBindParamFgLabel">
- <property name="toolTip">
- <string>&lt;p&gt;Bind parameters are placeholders for values yet to be provided by the user. They have one of the forms:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;:param_name&lt;/li&gt;&lt;li&gt;$param_name&lt;/li&gt;&lt;li&gt;@param_name&lt;/li&gt;&lt;li&gt;?&lt;/li&gt;&lt;/ul&gt;</string>
- </property>
- <property name="text">
- <string>Bind parameter foreground</string>
- </property>
- </widget>
- </item>
- <item row="15" column="1">
- <widget class="ColorButton" name="sqlEditorParBgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorParenthesisBg</string>
- </property>
- </widget>
- </item>
- <item row="15" column="0">
- <widget class="QLabel" name="sqlEditorParBgLabel">
- <property name="text">
- <string>Highlighted parenthesis background</string>
- </property>
- </widget>
- </item>
- <item row="11" column="0">
- <widget class="QLabel" name="sqlEditorBlobFgLabel">
- <property name="toolTip">
- <string>&lt;p&gt;BLOB values are binary values represented as hexadecimal numbers, like:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;X'12B4'&lt;/li&gt;&lt;li&gt;x'46A2F4'&lt;/li&gt;&lt;/ul&gt;</string>
- </property>
- <property name="text">
- <string>BLOB value foreground</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="sqlEditorRegularFgLabel">
- <property name="text">
- <string>Regular foreground</string>
- </property>
- </widget>
- </item>
- <item row="16" column="0">
- <widget class="QLabel" name="sqlEditorLineNumAreaBgLabel">
- <property name="text">
- <string>Line numbers area background</string>
- </property>
- </widget>
- </item>
- <item row="11" column="1">
- <widget class="ColorButton" name="sqlEditorBlobFgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorBlobFg</string>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QLabel" name="sqlEditorKeywordFgLabel">
- <property name="text">
- <string>Keyword foreground</string>
- </property>
- </widget>
- </item>
- <item row="10" column="0">
- <widget class="QLabel" name="sqlEditorNumberFgLabel">
- <property name="text">
- <string>Number foreground</string>
- </property>
- </widget>
- </item>
- <item row="9" column="0">
- <widget class="QLabel" name="sqlEditorCommentFgLabel">
- <property name="text">
- <string>Comment foreground</string>
- </property>
- </widget>
- </item>
- <item row="10" column="1">
- <widget class="ColorButton" name="sqlEditorNumberFgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorNumberFg</string>
- </property>
- </widget>
- </item>
- <item row="12" column="1">
- <widget class="ColorButton" name="sqlEditorBindParamFgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorBindParamFg</string>
- </property>
- </widget>
- </item>
- <item row="13" column="0">
- <widget class="QLabel" name="sqlEditorValidObjectsLabel">
- <property name="toolTip">
- <string>&lt;p&gt;Valid objects are name of tables, indexes, triggers, or views that exist in the SQLite database.&lt;/p&gt;</string>
- </property>
- <property name="text">
- <string>Valid objects foreground</string>
- </property>
- </widget>
- </item>
- <item row="13" column="1">
- <widget class="ColorButton" name="sqlEditorValidObjectsButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.SqlEditorValidObject</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="dataViewGroup">
- <property name="title">
- <string>Data view colors</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_6">
- <item row="0" column="0">
- <widget class="QLabel" name="dataViewUncommittedLabel">
- <property name="toolTip">
- <string>&lt;p&gt;Any data changes will be outlined with this color, until they're committed to the database.&lt;/p&gt;</string>
- </property>
- <property name="text">
- <string>Uncommitted data outline color</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="ColorButton" name="dataViewUncommittedButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.DataUncommitted</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="dataViewErrorLabel">
- <property name="toolTip">
- <string>&lt;p&gt;In case of error while committing data changes, the problematic cell will be outlined with this color.&lt;/p&gt;</string>
- </property>
- <property name="text">
- <string>Commit error outline color</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="ColorButton" name="dataViewErrorButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.DataUncommittedError</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="dataViewNullFgLabel">
- <property name="text">
- <string>NULL value foreground</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="ColorButton" name="dataViewNullFgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.DataNullFg</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="dataViewDeletedRowBgLabel">
- <property name="text">
- <string>Deleted row background</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="ColorButton" name="dataViewDeletedRowBgButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.DataDeletedBg</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="dbTreeGroup">
- <property name="title">
- <string>Database list colors</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_9">
- <item row="0" column="0">
- <widget class="QLabel" name="dbTreeLabelsLabel">
- <property name="toolTip">
- <string>&lt;p&gt;Additional labels are those which tell you SQLite version, number of objects deeper in the tree, etc.&lt;/p&gt;</string>
- </property>
- <property name="text">
- <string>Additional labels foreground</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="ColorButton" name="dbTreeLabelsButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.DbTreeLabelsFg</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="statusFieldGroup">
- <property name="title">
- <string>Status field colors</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_10">
- <item row="0" column="0">
- <widget class="QLabel" name="statusFieldInfoLabel">
- <property name="text">
- <string>Information message foreground</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="ColorButton" name="statusFieldInfoButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.StatusFieldInfoFg</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="statusFieldWarnLabel">
- <property name="text">
- <string>Warning message foreground</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="ColorButton" name="statusFieldWarnButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.StatusFieldWarnFg</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="statusFieldErrorLabel">
- <property name="text">
- <string>Error message foreground</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="ColorButton" name="statusFieldErrorButton">
- <property name="maximumSize">
- <size>
- <width>50</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="cfg" stdset="0">
- <string notr="true">Colors.StatusFieldErrorFg</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_3">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
</widget>
</widget>
</item>
@@ -2256,11 +1731,6 @@ p, li { white-space: pre-wrap; }
</widget>
<customwidgets>
<customwidget>
- <class>ColorButton</class>
- <extends>QPushButton</extends>
- <header>common/colorbutton.h</header>
- </customwidget>
- <customwidget>
<class>FontEdit</class>
<extends>QWidget</extends>
<header>common/fontedit.h</header>
@@ -2298,26 +1768,6 @@ p, li { white-space: pre-wrap; }
<tabstop>previewComboBox</tabstop>
<tabstop>previewTextEdit</tabstop>
<tabstop>fontsScrollArea</tabstop>
- <tabstop>scrollArea</tabstop>
- <tabstop>sqlEditorKeywordFgButton</tabstop>
- <tabstop>sqlEditorStringFgButton</tabstop>
- <tabstop>sqlEditorCommentFgButton</tabstop>
- <tabstop>sqlEditorRegularFgButton</tabstop>
- <tabstop>sqlEditorCurrLineBgButton</tabstop>
- <tabstop>sqlEditorLineNumAreaBgButton</tabstop>
- <tabstop>sqlEditorParBgButton</tabstop>
- <tabstop>sqlEditorBlobFgButton</tabstop>
- <tabstop>sqlEditorNumberFgButton</tabstop>
- <tabstop>sqlEditorBindParamFgButton</tabstop>
- <tabstop>sqlEditorValidObjectsButton</tabstop>
- <tabstop>dataViewUncommittedButton</tabstop>
- <tabstop>dataViewErrorButton</tabstop>
- <tabstop>dataViewNullFgButton</tabstop>
- <tabstop>dataViewDeletedRowBgButton</tabstop>
- <tabstop>dbTreeLabelsButton</tabstop>
- <tabstop>statusFieldInfoButton</tabstop>
- <tabstop>statusFieldWarnButton</tabstop>
- <tabstop>statusFieldErrorButton</tabstop>
</tabstops>
<resources>
<include location="../icons.qrc"/>
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp
index 0094ad0..0333cbc 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.cpp
@@ -136,6 +136,8 @@ ConstraintDialog::Constraint ConstraintDialog::getSelectedConstraint(SqliteCreat
return CHECK;
case SqliteCreateTable::Column::Constraint::DEFAULT:
return DEFAULT;
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return GENERATED;
case SqliteCreateTable::Column::Constraint::COLLATE:
return COLLATE;
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
@@ -185,6 +187,10 @@ void ConstraintDialog::updateDefinitionHeader()
ui->titleIcon->setPixmap(ICONS.CONSTRAINT_CHECK);
ui->titleLabel->setText(tr("Check", "table constraints"));
break;
+ case ConstraintDialog::GENERATED:
+ ui->titleIcon->setPixmap(ICONS.CONSTRAINT_GENERATED);
+ ui->titleLabel->setText(tr("Generated", "table constraints"));
+ break;
case ConstraintDialog::COLLATE:
ui->titleIcon->setPixmap(ICONS.CONSTRAINT_COLLATION);
ui->titleLabel->setText(tr("Collate", "table constraints"));
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.h
index fe24c0f..ef3e9f5 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/constraintdialog.h
@@ -32,6 +32,7 @@ class GUI_API_EXPORT ConstraintDialog : public QDialog
NOTNULL,
CHECK,
COLLATE,
+ GENERATED,
DEFAULT,
UNKNOWN
};
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/cssdebugdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/cssdebugdialog.cpp
index 99439e8..6e45138 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/cssdebugdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/cssdebugdialog.cpp
@@ -2,6 +2,7 @@
#include "ui_cssdebugdialog.h"
#include "mainwindow.h"
#include "themetuner.h"
+#include "uiconfig.h"
#include <QApplication>
#include <QPushButton>
@@ -12,7 +13,10 @@ CssDebugDialog::CssDebugDialog(QWidget *parent) :
ui->setupUi(this);
connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
- appliedCss = MAINWINDOW->styleSheet();
+ appliedCss = CFG_UI.General.CustomCss.get();
+ if (appliedCss.isEmpty())
+ appliedCss = MAINWINDOW->styleSheet();
+
ui->cssEdit->setPlainText(appliedCss);
updateState();
@@ -33,6 +37,7 @@ void CssDebugDialog::buttonClicked(QAbstractButton* button)
else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ApplyRole)
{
appliedCss = ui->cssEdit->toPlainText();
+ CFG_UI.General.CustomCss.set(appliedCss);
MAINWINDOW->setStyleSheet(appliedCss);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.cpp
deleted file mode 100644
index 8af131e..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-#include "dbconverterdialog.h"
-#include "ui_dbconverterdialog.h"
-#include "common/global.h"
-#include "dblistmodel.h"
-#include "db/db.h"
-#include "common/utils_sql.h"
-#include "dbversionconverter.h"
-#include "services/dbmanager.h"
-#include "iconmanager.h"
-#include "uiutils.h"
-#include "versionconvertsummarydialog.h"
-#include "mainwindow.h"
-#include "errorsconfirmdialog.h"
-#include "parser/ast/sqlitecreatetable.h"
-#include "services/pluginmanager.h"
-#include "plugins/dbplugin.h"
-#include "db/sqlquery.h"
-#include "services/notifymanager.h"
-#include "common/widgetcover.h"
-#include <QDebug>
-#include <QFileInfo>
-#include <QPushButton>
-
-DbConverterDialog::DbConverterDialog(QWidget *parent) :
- QDialog(parent),
- ui(new Ui::DbConverterDialog)
-{
- init();
-}
-
-DbConverterDialog::~DbConverterDialog()
-{
- delete ui;
- safe_delete(converter);
-}
-
-void DbConverterDialog::setDb(Db* db)
-{
- ui->srcDbCombo->setCurrentText(db->getName());
- srcDb = db;
- srcDbChanged();
-}
-
-void DbConverterDialog::init()
-{
- ui->setupUi(this);
- limitDialogWidth(this);
-
- widgetCover = new WidgetCover(this);
- widgetCover->setVisible(false);
- widgetCover->initWithInterruptContainer();
-
- ui->trgFileButton->setIcon(ICONS.OPEN_FILE);
-
- converter = new DbVersionConverter();
-
- dbListModel = new DbListModel(this);
- ui->srcDbCombo->setModel(dbListModel);
-
- connect(ui->srcDbCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(srcDbChanged(int)));
- connect(ui->trgVersionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateState()));
- connect(ui->trgFileEdit, SIGNAL(textChanged(QString)), this, SLOT(updateState()));
- connect(ui->trgNameEdit, SIGNAL(textChanged(QString)), this, SLOT(updateState()));
- connect(converter, SIGNAL(conversionFailed(QString)), this, SLOT(processingFailed(QString)));
- connect(converter, SIGNAL(conversionSuccessful()), this, SLOT(processingSuccessful()));
- connect(converter, SIGNAL(conversionAborted()), this, SLOT(processingAborted()));
- connect(widgetCover, SIGNAL(cancelClicked()), converter, SLOT(interrupt()));
-}
-
-void DbConverterDialog::srcDbChanged()
-{
- dontUpdateState = true;
- ui->srcDbVersionCombo->clear();
- ui->trgVersionCombo->clear();
- if (srcDb)
- {
- // Source version
- QList<Dialect> dialects = converter->getSupportedVersions();
- QStringList versionNames = converter->getSupportedVersionNames();
- Dialect dialect = srcDb->getDialect();
- int idx = dialects.indexOf(dialect);
- QString type = versionNames[idx];
- ui->srcDbVersionCombo->addItem(type);
- ui->srcDbVersionCombo->setCurrentText(type);
-
- // Target version
- QString oldTrgVersion = ui->trgVersionCombo->currentText();
- versionNames.removeAt(idx);
- ui->trgVersionCombo->addItems(versionNames);
- if (versionNames.contains(oldTrgVersion))
- ui->trgVersionCombo->setCurrentText(oldTrgVersion);
- else if (versionNames.size() > 0)
- ui->trgVersionCombo->setCurrentIndex(0);
-
- // File
- QString trgFile = srcDb->getPath() + "_new";
- int i = 0;
- while (QFileInfo(trgFile).exists())
- {
- trgFile = srcDb->getPath() + "_new" + QString::number(i++);
- }
-
- ui->trgFileEdit->setText(trgFile);
-
- // Name
- QString generatedName = generateUniqueName(srcDb->getName() + "_new", DBLIST->getDbNames());
- ui->trgNameEdit->setText(generatedName);
- }
- else
- {
- ui->srcDbVersionCombo->setCurrentText("");
- ui->trgFileEdit->setText("");
- ui->trgVersionCombo->setCurrentText("");
- ui->trgNameEdit->setText("");
- }
- dontUpdateState = false;
- updateState();
-}
-
-bool DbConverterDialog::validate()
-{
- bool srcDbOk = (srcDb != nullptr);
- setValidState(ui->srcDbCombo, srcDbOk, tr("Select source database"));
-
- QString dstDbPath = ui->trgFileEdit->text();
- QFileInfo dstDbFi(dstDbPath);
- bool dstDbOk = (!dstDbFi.exists() || dstDbFi.isWritable()) && dstDbFi != QFileInfo(srcDb->getPath());
- bool dstExists = dstDbFi.exists();
- setValidState(ui->trgFileEdit, dstDbOk, tr("Enter valid and writable file path."));
- if (dstExists && dstDbOk)
- setValidStateInfo(ui->trgFileEdit, tr("Entered file exists and will be overwritten."));
-
- QString name = ui->trgNameEdit->text();
- bool nameOk = !name.isEmpty() && !DBLIST->getDbNames().contains(name);
- setValidState(ui->trgNameEdit, nameOk, tr("Enter a not empty, unique name (as in the list of databases on the left)."));
-
- bool dstDialectOk = ui->trgVersionCombo->currentIndex() > -1;
- QString msg;
- if (!dstDialectOk && ui->trgVersionCombo->count() == 0)
- msg = tr("No valid target dialect available. Conversion not possible.");
- else
- msg = tr("Select valid target dialect.");
-
- setValidState(ui->trgVersionCombo, dstDialectOk, msg);
-
- return (srcDbOk && nameOk && dstDbOk && dstDialectOk);
-}
-
-void DbConverterDialog::accept()
-{
- if (!validate())
- return;
-
- QStringList versionNames = converter->getSupportedVersionNames();
- QList<Dialect> dialects = converter->getSupportedVersions();
- QString trgDialectName = ui->trgVersionCombo->currentText();
- int idx = versionNames.indexOf(trgDialectName);
- if (idx == -1)
- {
- qCritical() << "Could not find target dialect on list of supported dialects in DbConverterDialog::accept()";
- return;
- }
-
- Dialect srcDialect = srcDb->getDialect();
- Dialect trgDialect = dialects[idx];
- QString trgFile = ui->trgFileEdit->text();
- QString trgName = ui->trgNameEdit->text();
- widgetCover->show();
- converter->convert(srcDialect, trgDialect, srcDb, trgFile, trgName, &DbConverterDialog::confirmConversion, &DbConverterDialog::confirmConversionErrors);
-}
-
-void DbConverterDialog::srcDbChanged(int index)
-{
- srcDb = dbListModel->getDb(index);
- srcDbChanged();
-}
-
-void DbConverterDialog::updateState()
-{
- if (dontUpdateState)
- return;
-
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(validate());
-}
-
-void DbConverterDialog::processingFailed(const QString& errorMessage)
-{
- widgetCover->hide();
- notifyError(errorMessage);
-}
-
-void DbConverterDialog::processingSuccessful()
-{
- notifyInfo(tr("Database %1 has been successfully converted and now is available under new name: %2").arg(srcDb->getName(), ui->trgNameEdit->text()));
- QDialog::accept();
-}
-
-void DbConverterDialog::processingAborted()
-{
- widgetCover->hide();
-}
-
-bool DbConverterDialog::confirmConversion(const QList<QPair<QString, QString> >& diffs)
-{
- VersionConvertSummaryDialog dialog(MAINWINDOW);
- dialog.setWindowTitle(tr("SQL statements conversion"));
- dialog.setSides(diffs);
- return dialog.exec() == QDialog::Accepted;
-}
-
-bool DbConverterDialog::confirmConversionErrors(const QSet<QString>& errors)
-{
- ErrorsConfirmDialog dialog(MAINWINDOW);
- dialog.setTopLabel(tr("Following error occurred while converting SQL statements to the target SQLite version:"));
- dialog.setBottomLabel(tr("Would you like to ignore those errors and proceed?"));
- dialog.setErrors(errors);
- return dialog.exec() == QDialog::Accepted;
-}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.h
deleted file mode 100644
index 4267a1b..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef DBCONVERTERDIALOG_H
-#define DBCONVERTERDIALOG_H
-
-#include "guiSQLiteStudio_global.h"
-#include <QDialog>
-
-class DbListModel;
-class Db;
-class DbVersionConverter;
-class WidgetCover;
-
-namespace Ui {
- class DbConverterDialog;
-}
-
-class GUI_API_EXPORT DbConverterDialog : public QDialog
-{
- Q_OBJECT
-
- public:
- explicit DbConverterDialog(QWidget *parent = 0);
- ~DbConverterDialog();
-
- void setDb(Db* db);
-
- private:
- void init();
- void srcDbChanged();
- bool validate();
-
- static bool confirmConversion(const QList<QPair<QString, QString> >& diffs);
- static bool confirmConversionErrors(const QSet<QString>& errors);
-
- Ui::DbConverterDialog *ui = nullptr;
- DbListModel* dbListModel = nullptr;
- Db* srcDb = nullptr;
- DbVersionConverter* converter = nullptr;
- bool dontUpdateState = false;
- WidgetCover* widgetCover = nullptr;
-
- public slots:
- void accept();
-
- private slots:
- void srcDbChanged(int index);
- void updateState();
- void processingFailed(const QString& errorMessage);
- void processingSuccessful();
- void processingAborted();
-};
-
-#endif // DBCONVERTERDIALOG_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.ui
deleted file mode 100644
index f6bf009..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbconverterdialog.ui
+++ /dev/null
@@ -1,144 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DbConverterDialog</class>
- <widget class="QDialog" name="DbConverterDialog">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>251</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Convert database</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="srcGroup">
- <property name="title">
- <string>Source database</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0" colspan="2">
- <widget class="QComboBox" name="srcDbCombo"/>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="srcDbVersionLabel">
- <property name="text">
- <string>Source database version:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QComboBox" name="srcDbVersionCombo">
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="trgGroup">
- <property name="title">
- <string>Target database</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="trgVersionLabel">
- <property name="text">
- <string>Target version:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="trgFileEdit">
- <property name="toolTip">
- <string>This is the file that will be created as a result of the conversion.</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="trgFileLabel">
- <property name="text">
- <string>Target file:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="trgNameLabel">
- <property name="text">
- <string>Name of the new database:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QToolButton" name="trgFileButton">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="1" colspan="2">
- <widget class="QComboBox" name="trgVersionCombo"/>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QLineEdit" name="trgNameEdit">
- <property name="toolTip">
- <string>This is the name that the converted database will be added to SQLiteStudio with.</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>DbConverterDialog</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>DbConverterDialog</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp
index 183f8dd..1e56258 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/dbdialog.cpp
@@ -8,6 +8,7 @@
#include "services/dbmanager.h"
#include "common/global.h"
#include "iconmanager.h"
+#include "sqleditor.h"
#include "common/unused.h"
#include "db/sqlquery.h"
#include <QDateTimeEdit>
@@ -199,16 +200,13 @@ void DbDialog::addOption(const DbPluginOption& option, int& row)
}
QLabel* label = new QLabel(option.label, this);
- label->setAlignment(Qt::AlignVCenter|Qt::AlignRight);
+ label->setAlignment(Qt::AlignTop|Qt::AlignRight);
QWidget* editor = nullptr;
QWidget* editorHelper = nullptr; // TODO, based on plugins for Url handlers
editor = getEditor(option, editorHelper);
Q_ASSERT(editor != nullptr);
- if (!option.toolTip.isNull())
- editor->setToolTip(option.toolTip);
-
optionWidgets << label << editor;
optionKeyToWidget[option.key] = editor;
@@ -240,6 +238,16 @@ QWidget *DbDialog::getEditor(const DbPluginOption& opt, QWidget*& editorHelper)
editorHelper = nullptr;
switch (opt.type)
{
+ case DbPluginOption::SQL:
+ {
+ SqlEditor* sqlEdit = new SqlEditor(this);
+ editor = sqlEdit;
+ sqlEdit->setShowLineNumbers(false);
+ sqlEdit->setPlainText(opt.defaultValue.toString());
+ sqlEdit->setMaximumHeight(sqlEdit->fontMetrics().height() * 5);
+ connect(sqlEdit, SIGNAL(textChanged()), this, SLOT(propertyChanged()));
+ break;
+ }
case DbPluginOption::STRING:
{
editor = new QLineEdit(this);
@@ -260,8 +268,20 @@ QWidget *DbDialog::getEditor(const DbPluginOption& opt, QWidget*& editorHelper)
QComboBox* cb = new QComboBox(this);
editor = cb;
cb->setEditable(!opt.choiceReadOnly);
- cb->addItems(opt.choiceValues);
- cb->setCurrentText(opt.defaultValue.toString());
+ if (opt.choiceDataValues.isEmpty())
+ {
+ cb->addItems(opt.choiceValues);
+ cb->setCurrentText(opt.defaultValue.toString());
+ }
+ else
+ {
+ for (auto it = opt.choiceDataValues.begin(); it != opt.choiceDataValues.end(); ++it)
+ {
+ cb->addItem(it.key(), it.value());
+ if (it.value() == opt.defaultValue)
+ cb->setCurrentText(it.key());
+ }
+ }
connect(cb, SIGNAL(currentIndexChanged(QString)), this, SLOT(propertyChanged()));
break;
}
@@ -330,6 +350,9 @@ QWidget *DbDialog::getEditor(const DbPluginOption& opt, QWidget*& editorHelper)
le->setText(opt.defaultValue.toString());
}
+ if (!opt.toolTip.isNull())
+ editor->setToolTip(opt.toolTip);
+
return editor;
}
@@ -338,6 +361,9 @@ QVariant DbDialog::getValueFrom(DbPluginOption::Type type, QWidget *editor)
QVariant value;
switch (type)
{
+ case DbPluginOption::SQL:
+ value = dynamic_cast<SqlEditor*>(editor)->toPlainText();
+ break;
case DbPluginOption::STRING:
case DbPluginOption::PASSWORD:
case DbPluginOption::FILE:
@@ -353,8 +379,17 @@ QVariant DbDialog::getValueFrom(DbPluginOption::Type type, QWidget *editor)
value = dynamic_cast<QDoubleSpinBox*>(editor)->value();
break;
case DbPluginOption::CHOICE:
- value = dynamic_cast<QComboBox*>(editor)->currentText();
+ {
+ QComboBox* cb = dynamic_cast<QComboBox*>(editor);
+ QVariant data = cb->currentData();
+ if (data.isValid())
+ {
+ value = data;
+ break;
+ }
+ value = cb->currentText();
break;
+ }
case DbPluginOption::CUSTOM_PATH_BROWSE:
break; // should not happen ever
default:
@@ -369,6 +404,9 @@ void DbDialog::setValueFor(DbPluginOption::Type type, QWidget *editor, const QVa
{
switch (type)
{
+ case DbPluginOption::SQL:
+ dynamic_cast<SqlEditor*>(editor)->setPlainText(value.toString());
+ break;
case DbPluginOption::STRING:
case DbPluginOption::FILE:
case DbPluginOption::PASSWORD:
@@ -384,8 +422,20 @@ void DbDialog::setValueFor(DbPluginOption::Type type, QWidget *editor, const QVa
dynamic_cast<QDoubleSpinBox*>(editor)->setValue(value.toDouble());
break;
case DbPluginOption::CHOICE:
- dynamic_cast<QComboBox*>(editor)->setCurrentText(value.toString());
+ {
+ QComboBox* cb = dynamic_cast<QComboBox*>(editor);
+ if (value.isValid())
+ {
+ int idx = cb->findData(value);
+ if (idx > -1)
+ {
+ cb->setCurrentIndex(idx);
+ break;
+ }
+ }
+ cb->setCurrentText(value.toString());
break;
+ }
case DbPluginOption::CUSTOM_PATH_BROWSE:
break; // should not happen ever
default:
@@ -413,7 +463,7 @@ QHash<QString, QVariant> DbDialog::collectOptions()
if (ui->typeCombo->currentIndex() < 0)
return options;
- for (const QString key : optionKeyToWidget.keys())
+ for (const QString& key : optionKeyToWidget.keys())
options[key] = getValueFrom(optionKeyToType[key], optionKeyToWidget[key]);
DbPlugin* plugin = nullptr;
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/errorsconfirmdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/errorsconfirmdialog.cpp
index c0a73f3..9f53ef1 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/errorsconfirmdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/errorsconfirmdialog.cpp
@@ -1,6 +1,7 @@
#include "errorsconfirmdialog.h"
#include "ui_errorsconfirmdialog.h"
#include "iconmanager.h"
+#include "common/compatibility.h"
ErrorsConfirmDialog::ErrorsConfirmDialog(QWidget *parent) :
QDialog(parent),
@@ -31,7 +32,7 @@ void ErrorsConfirmDialog::setErrors(const QHash<QString,QSet<QString>>& errors)
void ErrorsConfirmDialog::setErrors(const QSet<QString>& errors)
{
ui->list->clear();
- ui->list->addItems(errors.toList());
+ ui->list->addItems(errors.values());
for (int i = 0, total = ui->list->count(); i < total; ++i)
ui->list->item(i)->setIcon(ICONS.STATUS_ERROR);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp
index 7b6a4d0..7dda03e 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/exportdialog.cpp
@@ -14,6 +14,7 @@
#include "schemaresolver.h"
#include "common/widgetcover.h"
#include "services/notifymanager.h"
+#include "themetuner.h"
#include "uiconfig.h"
#include <QClipboard>
#include <QDebug>
@@ -49,6 +50,7 @@ ExportDialog::~ExportDialog()
void ExportDialog::init()
{
ui->setupUi(this);
+ THEME_TUNER->darkThemeFix(this);
limitDialogWidth(this);
#ifdef Q_OS_MACX
@@ -531,7 +533,7 @@ void ExportDialog::updateDbObjTree()
ui->dbObjectsTree->expand(root);
QModelIndex child;
- for (int i = 0; (child = root.child(i, 0)).isValid(); i++)
+ for (int i = 0; (child = selectableDbListModel->index(i, 0, root)).isValid(); i++)
ui->dbObjectsTree->expand(child);
}
dbObjectsSelectAll();
@@ -718,7 +720,7 @@ void ExportDialog::exportTable(const ExportManager::StandardExportConfig& stdCon
EXPORT_MANAGER->configure(format, stdConfig);
// TODO when dbnames are fully supported, pass the dbname below
- EXPORT_MANAGER->exportTable(db, QString::null, ui->exportTableNameCombo->currentText());
+ EXPORT_MANAGER->exportTable(db, QString(), ui->exportTableNameCombo->currentText());
}
void ExportDialog::exportQuery(const ExportManager::StandardExportConfig& stdConfig, const QString& format)
@@ -741,7 +743,7 @@ ExportManager::StandardExportConfig ExportDialog::getExportConfig() const
stdConfig.intoClipboard = clipboard;
if (clipboard)
- stdConfig.outputFileName = QString::null;
+ stdConfig.outputFileName = QString();
else if (outputFileSupported)
stdConfig.outputFileName = ui->exportFileEdit->text();
@@ -790,7 +792,7 @@ QModelIndex ExportDialog::setupNewDbObjTreeRoot(const QModelIndex& root)
if (item->getType() == DbTreeItem::Type::DB)
return newRoot;
- newRoot = newRoot.child(0, 0);
+ newRoot = selectableDbListModel->index(0, 0, newRoot);
}
return newRoot;
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp
index ddb443d..565feb4 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/importdialog.cpp
@@ -13,6 +13,7 @@
#include "formmanager.h"
#include "common/utils.h"
#include "uiconfig.h"
+#include "themetuner.h"
#include <QDir>
#include <QDebug>
#include <QFileDialog>
@@ -100,6 +101,7 @@ void ImportDialog::readStdConfig()
void ImportDialog::init()
{
ui->setupUi(this);
+ THEME_TUNER->darkThemeFix(this);
limitDialogWidth(this);
#ifdef Q_OS_MACX
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp
index e3e7701..ebf9beb 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.cpp
@@ -9,10 +9,11 @@
#include "uiconfig.h"
#include "services/config.h"
#include "uiutils.h"
-#include "sqlite3.h"
+#include "db/sqlite3.h"
#include "indexexprcolumndialog.h"
#include "windows/editorwindow.h"
#include "services/codeformatter.h"
+#include "common/compatibility.h"
#include <QDebug>
#include <QGridLayout>
#include <QSignalMapper>
@@ -64,7 +65,7 @@ void IndexDialog::init()
{
qCritical() << "Created IndexDialog for null or closed database.";
notifyError(tr("Tried to open index dialog for closed or inexisting database."));
- reject();
+ preReject();
return;
}
@@ -91,7 +92,7 @@ void IndexDialog::init()
connect(columnStateSignalMapping, SIGNAL(mapped(QString)), this, SLOT(updateColumnState(QString)));
SchemaResolver resolver(db);
- ui->tableCombo->addItem(QString::null);
+ ui->tableCombo->addItem(QString());
ui->tableCombo->addItems(resolver.getTables());
connect(ui->tableCombo, SIGNAL(currentTextChanged(QString)), this, SLOT(updateTable(QString)));
connect(ui->tableCombo, SIGNAL(currentTextChanged(QString)), this, SLOT(updateValidation()));
@@ -99,29 +100,15 @@ void IndexDialog::init()
if (existingIndex)
ui->tableCombo->setEnabled(false);
- if (db->getDialect() == Dialect::Sqlite3)
- {
- connect(ui->partialIndexCheck, SIGNAL(toggled(bool)), this, SLOT(updatePartialConditionState()));
- connect(ui->partialIndexEdit, SIGNAL(errorsChecked(bool)), this, SLOT(updateValidation()));
- connect(ui->partialIndexEdit, SIGNAL(textChanged()), this, SLOT(updateValidation()));
- ui->partialIndexEdit->setVirtualSqlExpression("SELECT %1");
- updatePartialConditionState();
- ui->columnsTable->setColumnHidden(2, false);
- }
- else
- {
- ui->partialIndexCheck->setVisible(false);
- ui->partialIndexEdit->setVisible(false);
- ui->columnsTable->setColumnHidden(2, true);
- ui->addExprColumnButton->setVisible(false);
- ui->editExprColumnButton->setVisible(false);
- ui->delExprColumnButton->setVisible(false);
- }
+ connect(ui->partialIndexCheck, SIGNAL(toggled(bool)), this, SLOT(updatePartialConditionState()));
+ connect(ui->partialIndexEdit, SIGNAL(errorsChecked(bool)), this, SLOT(updateValidation()));
+ connect(ui->partialIndexEdit, SIGNAL(textChanged()), this, SLOT(updateValidation()));
+ ui->partialIndexEdit->setVirtualSqlExpression("SELECT %1");
+ updatePartialConditionState();
+ ui->columnsTable->setColumnHidden(2, false);
readCollations();
- ui->ddlEdit->setSqliteVersion(db->getVersion());
-
if (index.isNull())
createIndex = SqliteCreateIndexPtr::create();
else
@@ -146,8 +133,9 @@ void IndexDialog::readIndex()
SqliteQueryPtr parsedObject = resolver.getParsedObject(index, SchemaResolver::INDEX);
if (!parsedObject.dynamicCast<SqliteCreateIndex>())
{
+ createIndex = SqliteCreateIndexPtr::create();
notifyError(tr("Could not process index %1 correctly. Unable to open an index dialog.").arg(index));
- reject();
+ preReject();
return;
}
@@ -160,9 +148,6 @@ void IndexDialog::buildColumns()
clearColumns();
ui->columnsTable->setRowCount(0);
- totalColumns = tableColumns.size();
- ui->columnsTable->setRowCount(totalColumns);
-
int row = 0;
for (const QString& column : tableColumns)
buildColumn(column, row++);
@@ -235,8 +220,12 @@ void IndexDialog::buildColumn(const QString& name, int row)
IndexDialog::Column* IndexDialog::buildColumn(SqliteOrderBy* orderBy, int row)
{
- SqliteExpr* expr = dynamic_cast<SqliteExpr*>(orderBy->expr->clone());
- return buildColumn(expr, row);
+ Column* column = orderBy->isSimpleColumn() ?
+ new Column(orderBy->getColumnName(), ui->columnsTable) :
+ new Column(dynamic_cast<SqliteExpr*>(orderBy->expr->clone()), ui->columnsTable);
+
+ buildColumn(column, row);
+ return column;
}
IndexDialog::Column* IndexDialog::buildColumn(SqliteExpr* expr, int row)
@@ -248,6 +237,9 @@ IndexDialog::Column* IndexDialog::buildColumn(SqliteExpr* expr, int row)
void IndexDialog::buildColumn(Column* column, int row)
{
+ totalColumns++;
+ ui->columnsTable->setRowCount(totalColumns);
+
QString key = column->getKey();
columns[key] = column;
columnsByRow << column;
@@ -262,20 +254,17 @@ void IndexDialog::buildColumn(Column* column, int row)
layout->setContentsMargins(margins);
column->getCheckParent()->setLayout(layout);
- column->setCheck(new QCheckBox(key));
+ column->setCheck(new QCheckBox(column->getKey()));
column->getCheckParent()->layout()->addWidget(column->getCheck());
columnStateSignalMapping->setMapping(column->getCheck(), key);
connect(column->getCheck(), SIGNAL(toggled(bool)), columnStateSignalMapping, SLOT(map()));
connect(column->getCheck(), SIGNAL(toggled(bool)), this, SLOT(updateValidation()));
- if (db->getDialect() == Dialect::Sqlite3)
- {
- column->setCollation(new QComboBox());
- column->getCollation()->setEditable(true);
- column->getCollation()->lineEdit()->setPlaceholderText(tr("default", "index dialog"));
- column->getCollation()->setModel(&collations);
- }
+ column->setCollation(new QComboBox());
+ column->getCollation()->setEditable(true);
+ column->getCollation()->lineEdit()->setPlaceholderText(tr("default", "index dialog"));
+ column->getCollation()->setModel(&collations);
column->setSort(new QComboBox());
column->getSort()->setToolTip(tr("Sort order", "table constraints"));
@@ -286,8 +275,6 @@ void IndexDialog::buildColumn(Column* column, int row)
column->prepareForNewRow();
column->assignToNewRow(row);
- totalColumns++;
-
updateColumnState(key);
}
@@ -297,8 +284,7 @@ void IndexDialog::updateColumnState(const QString& columnKey)
bool enabled = col->getCheck()->isChecked();
col->getSort()->setEnabled(enabled);
- if (col->hasCollation())
- col->getCollation()->setEnabled(enabled);
+ col->getCollation()->setEnabled(enabled);
}
void IndexDialog::updatePartialConditionState()
@@ -482,9 +468,11 @@ void IndexDialog::applyColumnValues()
int row = 0;
int totalRows = tableColumns.size();
bool orderChanged = false;
+ QStringList orderedIndexKeys;
for (SqliteOrderBy* idxCol : createIndex->indexedColumns)
{
key = getKey(idxCol);
+ orderedIndexKeys << key;
if (idxCol->isSimpleColumn())
{
@@ -502,14 +490,13 @@ void IndexDialog::applyColumnValues()
column->getCheck()->setChecked(true);
updateColumnState(key);
column->getSort()->setCurrentText(sqliteSortOrder(idxCol->order));
- if (column->hasCollation())
- column->getCollation()->setCurrentText(idxCol->getCollation());
+ column->getCollation()->setCurrentText(idxCol->getCollation());
// Setting proper order
- int currentRow = columnsByRow.indexOf(column);
- if (currentRow != row)
+ int intendedRow = columnsByRow.indexOf(column);
+ if (intendedRow != row)
{
- columnsByRow.move(currentRow, row);
+ columnsByRow.move(intendedRow, row);
orderChanged = true;
}
@@ -587,7 +574,7 @@ void IndexDialog::rebuildCreateIndex()
else
idxCol = addIndexedColumn(column->getName());
- if (column->hasCollation() && !column->getCollation()->currentText().isEmpty())
+ if (!column->getCollation()->currentText().isEmpty())
addCollation(idxCol, column->getCollation()->currentText());
if (column->getSort()->currentIndex() > 0)
@@ -599,7 +586,7 @@ void IndexDialog::rebuildCreateIndex()
if (createIndex->where)
delete createIndex->where;
- Parser parser(db->getDialect());
+ Parser parser;
SqliteExpr* expr = parser.parseExpr(ui->partialIndexEdit->toPlainText());
if (expr)
@@ -624,8 +611,6 @@ void IndexDialog::queryDuplicates()
static QString countColNameTpl = QStringLiteral("count(%1)");
static QString countConditionTpl = QStringLiteral("count(%1) > 1");
- Dialect dialect = db->getDialect();
-
QStringList cols;
QStringList grpCols;
QStringList countCols;
@@ -636,10 +621,10 @@ void IndexDialog::queryDuplicates()
if (!columns[column]->getCheck()->isChecked())
continue;
- wrappedCol = wrapObjIfNeeded(column, dialect);
+ wrappedCol = wrapObjIfNeeded(column);
cols << wrappedCol;
grpCols << wrappedCol;
- countColName = wrapObjIfNeeded(countColNameTpl.arg(column), dialect);
+ countColName = wrapObjIfNeeded(countColNameTpl.arg(column));
cols << countTpl.arg(wrappedCol, countColName);
countCols << countConditionTpl.arg(wrappedCol);
}
@@ -650,7 +635,7 @@ void IndexDialog::queryDuplicates()
QString sqlCols = cols.join(", ");
QString sqlGrpCols = grpCols.join(", ");
QString sqlCntCols = countCols.join(" AND ");
- QString sqlTable = wrapObjIfNeeded(ui->tableCombo->currentText(), dialect);
+ QString sqlTable = wrapObjIfNeeded(ui->tableCombo->currentText());
editor->setContents(queryTpl.arg(sqlCols, sqlTable, sqlGrpCols, sqlCntCols));
editor->execute();
}
@@ -679,7 +664,15 @@ QString IndexDialog::getKey(SqliteOrderBy* col) const
if (col->isSimpleColumn())
return col->getColumnName();
- return col->expr->tokens.filterWhiteSpaces(false).detokenize();
+ return buildKey(col->expr);
+}
+
+QString IndexDialog::buildKey(SqliteExpr* expr)
+{
+ if (expr->mode == SqliteExpr::Mode::COLLATE && expr->expr1)
+ return expr->expr1->tokens.filterWhiteSpaces(false).detokenize().trimmed();
+
+ return expr->tokens.filterWhiteSpaces(false).detokenize().trimmed();
}
QStringList IndexDialog::getExistingColumnExprs(const QString& exceptThis) const
@@ -711,15 +704,18 @@ QStringList IndexDialog::getTableColumns() const
return cols;
}
+void IndexDialog::preReject()
+{
+ preRejected = true;
+}
+
void IndexDialog::accept()
{
rebuildCreateIndex();
- Dialect dialect = db->getDialect();
-
QStringList sqls;
if (existingIndex)
- sqls << QString("DROP INDEX %1").arg(wrapObjIfNeeded(originalCreateIndex->index, dialect));
+ sqls << QString("DROP INDEX %1").arg(wrapObjIfNeeded(originalCreateIndex->index));
sqls << createIndex->detokenize();
@@ -767,6 +763,14 @@ void IndexDialog::accept()
}
}
+int IndexDialog::exec()
+{
+ if (preRejected)
+ return Rejected;
+
+ return QDialog::exec();
+}
+
IndexDialog::Column::Column(const QString& name, QTableWidget* table)
{
this->name = name;
@@ -795,8 +799,7 @@ void IndexDialog::Column::prepareForNewRow()
{
column1Contrainer = defineContainer(checkParent);
column2Contrainer = defineContainer(sort);
- if (collation)
- column3Contrainer = defineContainer(collation);
+ column3Contrainer = defineContainer(collation);
}
QCheckBox* IndexDialog::Column::getCheck() const
@@ -839,11 +842,6 @@ void IndexDialog::Column::setCollation(QComboBox* cb)
collation = cb;
}
-bool IndexDialog::Column::hasCollation() const
-{
- return collation != nullptr;
-}
-
QString IndexDialog::Column::getName() const
{
return name;
@@ -851,6 +849,11 @@ QString IndexDialog::Column::getName() const
SqliteExpr* IndexDialog::Column::getExpr() const
{
+ // If column's expression contains collation at top level,
+ // the EXPR for processing is inner expr of collation.
+ if (expr->mode == SqliteExpr::Mode::COLLATE)
+ return expr->expr1;
+
return expr;
}
@@ -868,7 +871,7 @@ bool IndexDialog::Column::isExpr() const
QString IndexDialog::Column::getKey() const
{
if (expr)
- return expr->tokens.filterWhiteSpaces(false).detokenize();
+ return IndexDialog::buildKey(expr);
else
return name;
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.h
index f29b651..2e586d4 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexdialog.h
@@ -36,7 +36,14 @@ class GUI_API_EXPORT IndexDialog : public QDialog
class Column
{
public:
+ /**
+ * @brief Constructor for a real column in the table
+ */
Column(const QString& name, QTableWidget* table);
+
+ /**
+ * @brief Constructor for an expression column
+ */
Column(SqliteExpr* expr, QTableWidget* table);
~Column();
@@ -50,11 +57,32 @@ class GUI_API_EXPORT IndexDialog : public QDialog
void setSort(QComboBox* cb);
QComboBox* getCollation() const;
void setCollation(QComboBox* cb);
- bool hasCollation() const;
+ /**
+ * @brief Gets name of a real column in the table
+ * @return Name of table's column, or null string if it's expression column.
+ */
QString getName() const;
+
+ /**
+ * @brief Gets expression of an expression column.
+ * @return Either the expression, or null if this is a real table column.
+ *
+ * If an expression assigned to the column is a collate expression,
+ * this method will extract inner expression and return that.
+ *
+ * This is done this way, because after parsing SqliteOrderBy,
+ * the whole expression (including outer COLLATE expression) is passed
+ * to the column, whereas COLLATE is used for dropdowns, not for actual expression.
+ */
SqliteExpr* getExpr() const;
+
void setExpr(SqliteExpr* expr);
+
+ /**
+ * @brief Tells whether this is an expression column or real table column.
+ * @return true if it's expression column, or false if it's real table.
+ */
bool isExpr() const;
QString getKey() const;
@@ -73,6 +101,8 @@ class GUI_API_EXPORT IndexDialog : public QDialog
SqliteExpr* expr = nullptr;
};
+ static QString buildKey(SqliteExpr* expr);
+
void init();
void readIndex();
void readCollations();
@@ -92,6 +122,7 @@ class GUI_API_EXPORT IndexDialog : public QDialog
QString getKey(SqliteOrderBy* col) const;
QStringList getExistingColumnExprs(const QString& exceptThis = QString()) const;
QStringList getTableColumns() const;
+ void preReject();
bool existingIndex = false;
Db* db = nullptr;
@@ -105,6 +136,7 @@ class GUI_API_EXPORT IndexDialog : public QDialog
StrHash<Column*> columns;
QList<Column*> columnsByRow;
int totalColumns = 0;
+ bool preRejected = false;
Ui::IndexDialog *ui = nullptr;
private slots:
@@ -124,6 +156,7 @@ class GUI_API_EXPORT IndexDialog : public QDialog
public slots:
void accept();
+ int exec();
};
#endif // INDEXDIALOG_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexexprcolumndialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexexprcolumndialog.cpp
index f041294..3fcbdb9 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/indexexprcolumndialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/indexexprcolumndialog.cpp
@@ -44,7 +44,7 @@ void IndexExprColumnDialog::setOkEnabled(bool enabled)
SqliteExpr* IndexExprColumnDialog::parseExpr()
{
- Parser parser(db->getDialect());
+ Parser parser;
return parser.parseExpr(ui->sqlEditor->toPlainText());
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.cpp
index 36b400b..f34ff2e 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.cpp
@@ -50,6 +50,24 @@ SqliteStatement* NewConstraintDialog::getConstraint()
return constrStatement;
}
+void NewConstraintDialog::disableMode(ConstraintDialog::Constraint constraintType)
+{
+ switch (constraintType) {
+ case ConstraintDialog::PK:
+ case ConstraintDialog::FK:
+ case ConstraintDialog::UNIQUE:
+ case ConstraintDialog::CHECK:
+ case ConstraintDialog::NOTNULL:
+ case ConstraintDialog::COLLATE:
+ case ConstraintDialog::DEFAULT:
+ case ConstraintDialog::GENERATED:
+ modeToButton[constraintType]->setEnabled(false);
+ break;
+ case ConstraintDialog::UNKNOWN:
+ break;
+ }
+}
+
void NewConstraintDialog::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
@@ -84,36 +102,32 @@ void NewConstraintDialog::init()
void NewConstraintDialog::initTable()
{
- addButton(ICONS.CONSTRAINT_PRIMARY_KEY, tr("Primary Key", "new constraint dialog"), SLOT(createTablePk()));
- if (createTable->dialect == Dialect::Sqlite3)
- addButton(ICONS.CONSTRAINT_FOREIGN_KEY, tr("Foreign Key", "new constraint dialog"), SLOT(createTableFk()));
-
- addButton(ICONS.CONSTRAINT_UNIQUE, tr("Unique", "new constraint dialog"), SLOT(createTableUnique()));
- addButton(ICONS.CONSTRAINT_CHECK, tr("Check", "new constraint dialog"), SLOT(createTableCheck()));
+ modeToButton[ConstraintDialog::Constraint::PK] = addButton(ICONS.CONSTRAINT_PRIMARY_KEY, tr("Primary Key", "new constraint dialog"), SLOT(createTablePk()));
+ modeToButton[ConstraintDialog::Constraint::FK] = addButton(ICONS.CONSTRAINT_FOREIGN_KEY, tr("Foreign Key", "new constraint dialog"), SLOT(createTableFk()));
+ modeToButton[ConstraintDialog::Constraint::UNIQUE] = addButton(ICONS.CONSTRAINT_UNIQUE, tr("Unique", "new constraint dialog"), SLOT(createTableUnique()));
+ modeToButton[ConstraintDialog::Constraint::CHECK] = addButton(ICONS.CONSTRAINT_CHECK, tr("Check", "new constraint dialog"), SLOT(createTableCheck()));
}
void NewConstraintDialog::initColumn()
{
- addButton(ICONS.CONSTRAINT_PRIMARY_KEY, tr("Primary Key", "new constraint dialog"), SLOT(createColumnPk()));
- if (createTable->dialect == Dialect::Sqlite3)
- addButton(ICONS.CONSTRAINT_FOREIGN_KEY, tr("Foreign Key", "new constraint dialog"), SLOT(createColumnFk()));
-
- addButton(ICONS.CONSTRAINT_UNIQUE, tr("Unique", "new constraint dialog"), SLOT(createColumnUnique()));
- addButton(ICONS.CONSTRAINT_CHECK, tr("Check", "new constraint dialog"), SLOT(createColumnCheck()));
- addButton(ICONS.CONSTRAINT_NOT_NULL, tr("Not NULL", "new constraint dialog"), SLOT(createColumnNotNull()));
- if (createTable->dialect == Dialect::Sqlite3)
- addButton(ICONS.CONSTRAINT_COLLATION, tr("Collate", "new constraint dialog"), SLOT(createColumnCollate()));
-
- addButton(ICONS.CONSTRAINT_DEFAULT, tr("Default", "new constraint dialog"), SLOT(createColumnDefault()));
+ modeToButton[ConstraintDialog::Constraint::PK] = addButton(ICONS.CONSTRAINT_PRIMARY_KEY, tr("Primary Key", "new constraint dialog"), SLOT(createColumnPk()));
+ modeToButton[ConstraintDialog::Constraint::FK] = addButton(ICONS.CONSTRAINT_FOREIGN_KEY, tr("Foreign Key", "new constraint dialog"), SLOT(createColumnFk()));
+ modeToButton[ConstraintDialog::Constraint::UNIQUE] = addButton(ICONS.CONSTRAINT_UNIQUE, tr("Unique", "new constraint dialog"), SLOT(createColumnUnique()));
+ modeToButton[ConstraintDialog::Constraint::CHECK] = addButton(ICONS.CONSTRAINT_CHECK, tr("Check", "new constraint dialog"), SLOT(createColumnCheck()));
+ modeToButton[ConstraintDialog::Constraint::NOTNULL] = addButton(ICONS.CONSTRAINT_NOT_NULL, tr("Not NULL", "new constraint dialog"), SLOT(createColumnNotNull()));
+ modeToButton[ConstraintDialog::Constraint::COLLATE] = addButton(ICONS.CONSTRAINT_COLLATION, tr("Collate", "new constraint dialog"), SLOT(createColumnCollate()));
+ modeToButton[ConstraintDialog::Constraint::GENERATED] = addButton(ICONS.CONSTRAINT_GENERATED, tr("Generated", "new constraint dialog"), SLOT(createColumnGenerated()));
+ modeToButton[ConstraintDialog::Constraint::DEFAULT] = addButton(ICONS.CONSTRAINT_DEFAULT, tr("Default", "new constraint dialog"), SLOT(createColumnDefault()));
}
-void NewConstraintDialog::addButton(const Icon& icon, const QString text, const char* slot)
+QCommandLinkButton* NewConstraintDialog::addButton(const Icon& icon, const QString text, const char* slot)
{
QCommandLinkButton* btn = new QCommandLinkButton();
btn->setIcon(icon);
btn->setText(text);
connect(btn, SIGNAL(clicked()), this, slot);
ui->container->layout()->addWidget(btn);
+ return btn;
}
int NewConstraintDialog::createColumnConstraint(ConstraintDialog::Constraint constraintType)
@@ -142,6 +156,9 @@ int NewConstraintDialog::createColumnConstraint(ConstraintDialog::Constraint con
case ConstraintDialog::DEFAULT:
constraint->type = SqliteCreateTable::Column::Constraint::DEFAULT;
break;
+ case ConstraintDialog::GENERATED:
+ constraint->type = SqliteCreateTable::Column::Constraint::GENERATED;
+ break;
case ConstraintDialog::UNKNOWN:
break;
}
@@ -172,6 +189,7 @@ int NewConstraintDialog::createTableConstraint(ConstraintDialog::Constraint cons
case ConstraintDialog::NOTNULL:
case ConstraintDialog::COLLATE:
case ConstraintDialog::DEFAULT:
+ case ConstraintDialog::GENERATED:
case ConstraintDialog::UNKNOWN:
break;
}
@@ -258,6 +276,11 @@ void NewConstraintDialog::createColumnCollate()
createColumnConstraint(ConstraintDialog::COLLATE);
}
+void NewConstraintDialog::createColumnGenerated()
+{
+ createColumnConstraint(ConstraintDialog::GENERATED);
+}
+
int NewConstraintDialog::exec()
{
if (predefinedConstraintType == ConstraintDialog::UNKNOWN)
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.h
index e374312..daa226c 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/newconstraintdialog.h
@@ -12,6 +12,7 @@
namespace Ui {
class NewConstraintDialog;
}
+class QCommandLinkButton;
class GUI_API_EXPORT NewConstraintDialog : public QDialog
{
@@ -25,6 +26,7 @@ class GUI_API_EXPORT NewConstraintDialog : public QDialog
~NewConstraintDialog();
SqliteStatement* getConstraint();
+ void disableMode(ConstraintDialog::Constraint constraintType);
int exec();
protected:
@@ -34,7 +36,7 @@ class GUI_API_EXPORT NewConstraintDialog : public QDialog
void init();
void initTable();
void initColumn();
- void addButton(const Icon& icon, const QString text, const char* slot);
+ QCommandLinkButton* addButton(const Icon& icon, const QString text, const char* slot);
int createColumnConstraint(ConstraintDialog::Constraint constraintType);
int createTableConstraint(ConstraintDialog::Constraint constraintType);
int editConstraint();
@@ -47,6 +49,7 @@ class GUI_API_EXPORT NewConstraintDialog : public QDialog
QPointer<SqliteCreateTable> createTable;
QPointer<SqliteCreateTable::Column> columnStmt;
ConstraintDialog* constraintDialog = nullptr;
+ QHash<ConstraintDialog::Constraint, QCommandLinkButton*> modeToButton;
private slots:
void createTablePk();
@@ -60,6 +63,7 @@ class GUI_API_EXPORT NewConstraintDialog : public QDialog
void createColumnNotNull();
void createColumnDefault();
void createColumnCollate();
+ void createColumnGenerated();
};
#endif // NEWCONSTRAINTDIALOG_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp
index 020cfef..7ba2c0b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.cpp
@@ -5,7 +5,9 @@
#include "sqlitestudio.h"
#include "ui_newversiondialog.h"
#include "services/config.h"
+#include <QDesktopServices>
#include <QInputDialog>
+#include <QUrl>
NewVersionDialog::NewVersionDialog(QWidget *parent) :
QDialog(parent),
@@ -19,22 +21,10 @@ NewVersionDialog::~NewVersionDialog()
delete ui;
}
-void NewVersionDialog::setUpdates(const QList<UpdateManager::UpdateEntry>& updates)
+void NewVersionDialog::setUpdate(const QString& version, const QString& url)
{
- QTableWidgetItem* item = nullptr;
- int row = 0;
- ui->updateList->setRowCount(updates.size());
- for (const UpdateManager::UpdateEntry& entry : updates)
- {
- item = new QTableWidgetItem(entry.compontent);
- ui->updateList->setItem(row, 0, item);
-
- item = new QTableWidgetItem(entry.version);
- ui->updateList->setItem(row, 1, item);
-
- row++;
- }
- ui->updateList->resizeColumnsToContents();
+ downloadUrl = url;
+ ui->versionLabel->setText(version);
}
void NewVersionDialog::init()
@@ -42,16 +32,23 @@ void NewVersionDialog::init()
ui->setupUi(this);
connect(ui->abortButton, SIGNAL(clicked()), this, SLOT(reject()));
- connect(ui->updateButton, SIGNAL(clicked()), this, SLOT(installUpdates()));
+ connect(ui->updateButton, SIGNAL(clicked()), this, SLOT(downloadUpdates()));
+ connect(ui->homepageButton, SIGNAL(clicked()), this, SLOT(openHomePage()));
connect(ui->checkOnStartupCheck, &QCheckBox::clicked, [=](bool checked)
{
CFG_CORE.General.CheckUpdatesOnStartup.set(checked);
});
}
-void NewVersionDialog::installUpdates()
+void NewVersionDialog::downloadUpdates()
+{
+ QDesktopServices::openUrl(QUrl(downloadUrl));
+ close();
+}
+
+void NewVersionDialog::openHomePage()
{
- UPDATES->update();
+ QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getHomePage()));
close();
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.h b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.h
index fc62d6d..a1b1569 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.h
@@ -19,7 +19,7 @@ class GUI_API_EXPORT NewVersionDialog : public QDialog
explicit NewVersionDialog(QWidget *parent = 0);
~NewVersionDialog();
- void setUpdates(const QList<UpdateManager::UpdateEntry>& updates);
+ void setUpdate(const QString& version, const QString& url);
protected:
void showEvent(QShowEvent*);
@@ -27,10 +27,13 @@ class GUI_API_EXPORT NewVersionDialog : public QDialog
private:
void init();
+ QString downloadUrl;
+
Ui::NewVersionDialog *ui = nullptr;
private slots:
- void installUpdates();
+ void downloadUpdates();
+ void openHomePage();
};
#endif // PORTABLE_CONFIG
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui
index d5468b3..12794ce 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/newversiondialog.ui
@@ -23,7 +23,7 @@
</font>
</property>
<property name="text">
- <string>New updates are available!</string>
+ <string>New version is available!</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -31,73 +31,50 @@
</widget>
</item>
<item>
- <widget class="QTableWidget" name="updateList">
- <property name="focusPolicy">
- <enum>Qt::NoFocus</enum>
- </property>
- <property name="editTriggers">
- <set>QAbstractItemView::NoEditTriggers</set>
- </property>
- <property name="showDropIndicator" stdset="0">
- <bool>false</bool>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::NoSelection</enum>
- </property>
- <property name="selectionBehavior">
- <enum>QAbstractItemView::SelectRows</enum>
- </property>
- <property name="verticalScrollMode">
- <enum>QAbstractItemView::ScrollPerPixel</enum>
- </property>
- <property name="showGrid">
- <bool>false</bool>
- </property>
- <attribute name="horizontalHeaderStretchLastSection">
- <bool>true</bool>
- </attribute>
- <attribute name="verticalHeaderVisible">
- <bool>false</bool>
- </attribute>
- <attribute name="verticalHeaderDefaultSectionSize">
- <number>20</number>
- </attribute>
- <attribute name="verticalHeaderMinimumSectionSize">
- <number>20</number>
- </attribute>
- <column>
- <property name="text">
- <string>Component</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Update version</string>
- </property>
- </column>
+ <widget class="QLabel" name="versionLabel">
+ <property name="font">
+ <font>
+ <pointsize>16</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>0.0.0</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
</widget>
</item>
<item>
- <widget class="QWidget" name="checkOnStartupWidget" native="true">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QCheckBox" name="checkOnStartupCheck">
- <property name="text">
- <string>Check for updates on startup</string>
- </property>
- </widget>
- </item>
- </layout>
+ <widget class="QCommandLinkButton" name="updateButton">
+ <property name="text">
+ <string>Download new version!</string>
+ </property>
+ <property name="icon">
+ <iconset resource="../icons.qrc">
+ <normaloff>:/icons/img/get_update.png</normaloff>:/icons/img/get_update.png</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>24</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="description">
+ <string>New version package will be downloaded. It will be up to you to install it whenever you're ready.</string>
+ </property>
</widget>
</item>
<item>
- <widget class="QCommandLinkButton" name="updateButton">
+ <widget class="QCommandLinkButton" name="homepageButton">
<property name="text">
- <string>Update to new version!</string>
+ <string>Open SQLiteStudio home page.</string>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
- <normaloff>:/icons/img/get_update.png</normaloff>:/icons/img/get_update.png</iconset>
+ <normaloff>:/icons/img/sqlitestudio.svg</normaloff>:/icons/img/sqlitestudio.svg</iconset>
</property>
<property name="iconSize">
<size>
@@ -106,7 +83,7 @@
</size>
</property>
<property name="description">
- <string>This application will be closed and the update installer will start to download and install all the updates.</string>
+ <string>Read release notes &amp;&amp; download package yourself.</string>
</property>
</widget>
</item>
@@ -126,10 +103,23 @@
</size>
</property>
<property name="description">
- <string>Don't install the update and close this window.</string>
+ <string>Just close this window.</string>
</property>
</widget>
</item>
+ <item>
+ <widget class="QWidget" name="checkOnStartupWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QCheckBox" name="checkOnStartupCheck">
+ <property name="text">
+ <string>Check for updates on startup</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
</layout>
</widget>
<resources>
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp
index 7f4ec20..aae0d58 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/populatedialog.cpp
@@ -10,6 +10,7 @@
#include "uiutils.h"
#include "services/populatemanager.h"
#include "common/widgetcover.h"
+#include "common/compatibility.h"
#include <QPushButton>
#include <QGridLayout>
#include <QCheckBox>
@@ -42,7 +43,7 @@ void PopulateDialog::init()
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Populate", "populate dialog button"));
plugins = PLUGINS->getLoadedPlugins<PopulatePlugin>();
- qSort(plugins.begin(), plugins.end(), [](PopulatePlugin* p1, PopulatePlugin* p2) -> bool
+ sSort(plugins, [](PopulatePlugin* p1, PopulatePlugin* p2) -> bool
{
return p1->getTitle().compare(p2->getTitle()) < 0;
});
diff --git a/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp b/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp
index 255694c..86862e2 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dialogs/triggerdialog.cpp
@@ -107,12 +107,6 @@ void TriggerDialog::init()
SqliteCreateTrigger::scopeToString(SqliteCreateTrigger::Scope::null),
SqliteCreateTrigger::scopeToString(SqliteCreateTrigger::Scope::FOR_EACH_ROW)
});
- if (db->getDialect() == Dialect::Sqlite2)
- {
- ui->scopeCombo->addItems({
- SqliteCreateTrigger::scopeToString(SqliteCreateTrigger::Scope::FOR_EACH_STATEMENT)
- });
- }
// Event combo - default values
ui->whenCombo->addItems(tableEventNames + viewEventNames);
@@ -223,7 +217,6 @@ void TriggerDialog::readTrigger()
void TriggerDialog::setupVirtualSqls()
{
- Dialect dialect = db->getDialect();
static QString preconditionVirtSql = QStringLiteral("CREATE TRIGGER %1 BEFORE INSERT ON %2 WHEN %3 BEGIN SELECT 1; END;");
static QString codeVirtSql = QStringLiteral("CREATE TRIGGER %1 BEFORE INSERT ON %2 BEGIN %3 END;");
ui->codeEdit->setVirtualSqlCompleteSemicolon(true);
@@ -232,14 +225,14 @@ void TriggerDialog::setupVirtualSqls()
if (createTrigger) // if false, then there was a parsing error in parseDdl().
{
ui->preconditionEdit->setVirtualSqlExpression(
- preconditionVirtSql.arg(wrapObjIfNeeded(trigger, dialect),
- wrapObjIfNeeded(createTrigger->table, dialect),
+ preconditionVirtSql.arg(wrapObjIfNeeded(trigger),
+ wrapObjIfNeeded(createTrigger->table),
"%1"));
ui->codeEdit->setVirtualSqlExpression(
codeVirtSql.arg(
- wrapObjIfNeeded(trigger, dialect),
- wrapObjIfNeeded(createTrigger->table, dialect),
+ wrapObjIfNeeded(trigger),
+ wrapObjIfNeeded(createTrigger->table),
"%1"));
}
}
@@ -247,12 +240,12 @@ void TriggerDialog::setupVirtualSqls()
{
ui->preconditionEdit->setVirtualSqlExpression(
preconditionVirtSql.arg("trig",
- wrapObjIfNeeded(getTargetObjectName(), dialect),
+ wrapObjIfNeeded(getTargetObjectName()),
"%1"));
ui->codeEdit->setVirtualSqlExpression(
codeVirtSql.arg("trig",
- wrapObjIfNeeded(getTargetObjectName(), dialect),
+ wrapObjIfNeeded(getTargetObjectName()),
"%1"));
}
else
@@ -292,12 +285,11 @@ void TriggerDialog::rebuildTrigger()
*/
static const QString tempDdl = QStringLiteral("CREATE TRIGGER %1%2 %3%4 ON %5%6%7 BEGIN %8 END;");
- Dialect dialect = db->getDialect();
- QString trigName = wrapObjIfNeeded(ui->nameEdit->text(), dialect);
+ QString trigName = wrapObjIfNeeded(ui->nameEdit->text());
QString when = ui->whenCombo->currentText();
QString action = ui->actionCombo->currentText();
QString columns = "";
- QString target = wrapObjIfNeeded(getTargetObjectName(), dialect);
+ QString target = wrapObjIfNeeded(getTargetObjectName());
QString scope = ui->scopeCombo->currentText();
QString precondition = "";
QString queries = ui->codeEdit->toPlainText();
@@ -308,7 +300,7 @@ void TriggerDialog::rebuildTrigger()
{
QStringList colNames;
for (const QString& colName : selectedColumns)
- colNames << wrapObjIfNeeded(colName, dialect);
+ colNames << wrapObjIfNeeded(colName);
columns = " "+colNames.join(", ");
}
@@ -394,11 +386,9 @@ void TriggerDialog::accept()
{
rebuildTrigger();
- Dialect dialect = db->getDialect();
-
QStringList sqls;
if (existingTrigger)
- sqls << QString("DROP TRIGGER %1").arg(wrapObjIfNeeded(originalTriggerName, dialect));
+ sqls << QString("DROP TRIGGER %1").arg(wrapObjIfNeeded(originalTriggerName));
sqls << ddl;
diff --git a/SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp b/SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp
new file mode 100644
index 0000000..8357810
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/extendedpalette.cpp
@@ -0,0 +1,60 @@
+#include "extendedpalette.h"
+#include <QStyle>
+#include <QDebug>
+
+ExtendedPalette::ExtendedPalette()
+{
+
+}
+
+QBrush ExtendedPalette::editorString() const
+{
+ return editorStringBrush;
+}
+
+void ExtendedPalette::setEditorString(const QBrush &value)
+{
+ editorStringBrush = value;
+}
+
+QBrush ExtendedPalette::editorLineBase() const
+{
+ return editorLineBaseBrush;
+}
+
+void ExtendedPalette::setEditorLineBase(const QBrush &value)
+{
+ editorLineBaseBrush = value;
+}
+
+void ExtendedPalette::styleChanged(QStyle *style, const QString &themeName)
+{
+ QPalette stdPalette = style->standardPalette();
+ bool isDark = stdPalette.base().color().lightness() < 128;
+
+ static const QColor stdAltColor = QColor(Qt::green);
+ if (stdPalette.text().color().lightness() >= 128)
+ editorStringBrush = QBrush(stdAltColor.lighter());
+ else
+ editorStringBrush = QBrush(stdAltColor.darker());
+
+ if (themeName.toLower() == "macintosh" && isDark)
+ editorLineBaseBrush = QBrush(stdPalette.alternateBase().color().darker(300));
+ else
+ editorLineBaseBrush = stdPalette.alternateBase();
+
+ if (isDark)
+ mdiAreaBaseBrush = stdPalette.alternateBase();
+ else
+ mdiAreaBaseBrush = QBrush("#8a8a8a");
+}
+
+QBrush ExtendedPalette::mdiAreaBase() const
+{
+ return mdiAreaBaseBrush;
+}
+
+void ExtendedPalette::setMdiAreaBase(const QBrush& value)
+{
+ mdiAreaBaseBrush = value;
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/extendedpalette.h b/SQLiteStudio3/guiSQLiteStudio/extendedpalette.h
new file mode 100644
index 0000000..e6e5aef
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/extendedpalette.h
@@ -0,0 +1,30 @@
+#ifndef EXTENDEDPALETTE_H
+#define EXTENDEDPALETTE_H
+
+#include <QBrush>
+
+class QStyle;
+
+class ExtendedPalette
+{
+ public:
+ ExtendedPalette();
+
+ QBrush editorString() const;
+ void setEditorString(const QBrush &value);
+
+ QBrush editorLineBase() const;
+ void setEditorLineBase(const QBrush &value);
+
+ void styleChanged(QStyle* style, const QString& themeName);
+
+ QBrush mdiAreaBase() const;
+ void setMdiAreaBase(const QBrush& value);
+
+ private:
+ QBrush editorStringBrush;
+ QBrush editorLineBaseBrush;
+ QBrush mdiAreaBaseBrush;
+};
+
+#endif // EXTENDEDPALETTE_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/formmanager.cpp b/SQLiteStudio3/guiSQLiteStudio/formmanager.cpp
index 735fb5d..bd5f6c0 100644
--- a/SQLiteStudio3/guiSQLiteStudio/formmanager.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/formmanager.cpp
@@ -170,7 +170,7 @@ QString FormManager::getWidgetName(const QString& path)
if (!file.open(QIODevice::ReadOnly))
{
qWarning() << "Could not open" << path << "for reading. Form file ignored.";
- return QString::null;
+ return QString();
}
QString contents = file.readAll();
@@ -180,7 +180,7 @@ QString FormManager::getWidgetName(const QString& path)
if (!match.hasMatch())
{
qWarning() << "Could not match widget in" << path << " document. File ignored.";
- return QString::null;
+ return QString();
}
QString widgetName = match.captured(1);
diff --git a/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro b/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro
index d603f87..59a56d0 100644
--- a/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro
+++ b/SQLiteStudio3/guiSQLiteStudio/guiSQLiteStudio.pro
@@ -26,7 +26,7 @@ portable: {
TARGET = guiSQLiteStudio
TEMPLATE = lib
-CONFIG += c++11
+CONFIG += c++17
QMAKE_CXXFLAGS += -pedantic
DEFINES += GUISQLITESTUDIO_LIBRARY
@@ -43,6 +43,9 @@ TRANSLATIONS += translations/guiSQLiteStudio_ro_RO.ts \
translations/guiSQLiteStudio_pl.ts
SOURCES +=\
+ common/dbcombobox.cpp \
+ constraints/columngeneratedpanel.cpp \
+ extendedpalette.cpp \
mainwindow.cpp \
iconmanager.cpp \
dbtree/dbtreemodel.cpp \
@@ -50,6 +53,7 @@ SOURCES +=\
dbtree/dbtree.cpp \
dbtree/dbtreeview.cpp \
actionentry.cpp \
+ style.cpp \
uiutils.cpp \
dbtree/dbtreeitemdelegate.cpp \
dbtree/dbtreeitemfactory.cpp \
@@ -168,7 +172,6 @@ SOURCES +=\
uicustomicon.cpp \
uiurlbutton.cpp \
common/configcombobox.cpp \
- dialogs/dbconverterdialog.cpp \
dialogs/dbdialog.cpp \
uidebug.cpp \
debugconsole.cpp \
@@ -193,12 +196,16 @@ SOURCES +=\
dialogs/fileexecerrorsdialog.cpp
HEADERS += mainwindow.h \
+ common/dbcombobox.h \
+ constraints/columngeneratedpanel.h \
+ extendedpalette.h \
iconmanager.h \
dbtree/dbtreemodel.h \
dbtree/dbtreeitem.h \
dbtree/dbtree.h \
dbtree/dbtreeview.h \
actionentry.h \
+ style.h \
uiutils.h \
dbtree/dbtreeitemdelegate.h \
dbtree/dbtreeitemfactory.h \
@@ -320,7 +327,6 @@ HEADERS += mainwindow.h \
uicustomicon.h \
uiurlbutton.h \
common/configcombobox.h \
- dialogs/dbconverterdialog.h \
dialogs/configdialog.h \
dialogs/dbdialog.h \
uidebug.h \
@@ -348,6 +354,7 @@ HEADERS += mainwindow.h \
dialogs/fileexecerrorsdialog.h
FORMS += mainwindow.ui \
+ constraints/columngeneratedpanel.ui \
dbtree/dbtree.ui \
statusfield.ui \
completer/completerwindow.ui \
@@ -384,7 +391,6 @@ FORMS += mainwindow.ui \
dialogs/importdialog.ui \
dialogs/populatedialog.ui \
dialogs/populateconfigdialog.ui \
- dialogs/dbconverterdialog.ui \
dialogs/dbdialog.ui \
debugconsole.ui \
dialogs/aboutdialog.ui \
diff --git a/SQLiteStudio3/guiSQLiteStudio/icon.cpp b/SQLiteStudio3/guiSQLiteStudio/icon.cpp
index bdc21ce..e1fc552 100644
--- a/SQLiteStudio3/guiSQLiteStudio/icon.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/icon.cpp
@@ -318,10 +318,14 @@ QString Icon::getIconNameForAttribute(Icon::Attributes attr)
return "sort_ind_asc";
case SORT_DESC:
return "sort_ind_desc";
+ case DISK:
+ return "disk_small";
+ case LIGHTENING:
+ return "lightning_small";
default:
qWarning() << "Unhandled icon attribute:" << attr;
}
- return QString::null;
+ return QString();
}
QIcon Icon::mergeAttribute(const QIcon* icon, Icon::Attributes attr)
diff --git a/SQLiteStudio3/guiSQLiteStudio/icon.h b/SQLiteStudio3/guiSQLiteStudio/icon.h
index d6512c9..b54e730 100644
--- a/SQLiteStudio3/guiSQLiteStudio/icon.h
+++ b/SQLiteStudio3/guiSQLiteStudio/icon.h
@@ -35,7 +35,9 @@ class GUI_API_EXPORT Icon
QUESTION,
ERROR,
SORT_ASC,
- SORT_DESC
+ SORT_DESC,
+ DISK,
+ LIGHTENING
};
Icon(const QString& name, const QString& fileName);
diff --git a/SQLiteStudio3/guiSQLiteStudio/iconmanager.h b/SQLiteStudio3/guiSQLiteStudio/iconmanager.h
index 6034de1..6bff0e0 100644
--- a/SQLiteStudio3/guiSQLiteStudio/iconmanager.h
+++ b/SQLiteStudio3/guiSQLiteStudio/iconmanager.h
@@ -18,7 +18,6 @@ class GUI_API_EXPORT IconManager : public QObject
public:
DEF_ICONS(Icons, iconEnums,
- DEF_ICON(ABORT24, "abort24")
DEF_ICON(ACT_ABORT, "act_abort")
DEF_ICON(ACT_CLEAR, "act_clear")
DEF_ICON(ACT_COPY, "act_copy")
@@ -27,7 +26,6 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICON(ACT_DELETE, "act_delete")
DEF_ICON(ACT_PASTE, "act_paste")
DEF_ICON(ACT_REDO, "act_redo")
- DEF_ICON(ACT_SEARCH, "act_search")
DEF_ICON(ACT_SELECT_ALL, "act_select_all")
DEF_ICON(ACT_UNDO, "act_undo")
DEF_ICON(APPLY_FILTER, "apply_filter")
@@ -55,7 +53,6 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICON(COMPLETER_PRAGMA, "completer_pragma")
DEF_ICON(COMPLETER_STRING, "completer_string")
DEF_ICON(CONFIGURE, "configure")
- DEF_ICON(CONFIGURE_CONSTRAINT, "configure_constraint")
DEF_ICON(CONSTRAINT_CHECK, "check")
DEF_ICO2(CONSTRAINT_CHECK_ADD, CONSTRAINT_CHECK, PLUS)
DEF_ICON(CONSTRAINT_COLLATION, "collation")
@@ -64,27 +61,27 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICO2(CONSTRAINT_DEFAULT_ADD, CONSTRAINT_DEFAULT, PLUS)
DEF_ICON(CONSTRAINT_FOREIGN_KEY, "fk")
DEF_ICO2(CONSTRAINT_FOREIGN_KEY_ADD, CONSTRAINT_FOREIGN_KEY, PLUS)
+ DEF_ICON(CONSTRAINT_GENERATED, "generated")
+ DEF_ICO2(CONSTRAINT_GENERATED_STORED, CONSTRAINT_GENERATED, DISK)
+ DEF_ICO2(CONSTRAINT_GENERATED_VIRTUAL, CONSTRAINT_GENERATED, LIGHTENING)
+ DEF_ICO2(CONSTRAINT_GENERATED_ADD, CONSTRAINT_GENERATED, PLUS)
DEF_ICON(CONSTRAINT_NOT_NULL, "not_null")
DEF_ICO2(CONSTRAINT_NOT_NULL_ADD, CONSTRAINT_NOT_NULL, PLUS)
DEF_ICON(CONSTRAINT_PRIMARY_KEY, "pk")
DEF_ICO2(CONSTRAINT_PRIMARY_KEY_ADD, CONSTRAINT_PRIMARY_KEY, PLUS)
DEF_ICON(CONSTRAINT_UNIQUE, "unique")
DEF_ICO2(CONSTRAINT_UNIQUE_ADD, CONSTRAINT_UNIQUE, PLUS)
- DEF_ICON(CONVERT_DB, "convert_db")
DEF_ICON(VACUUM_DB, "vacuum_db")
DEF_ICON(INTEGRITY_CHECK, "integrity_check")
DEF_ICON(DATABASE, "database")
DEF_ICO2(DATABASE_ADD, DATABASE, PLUS)
DEF_ICON(DATABASE_CONNECT, "database_connect")
- DEF_ICON(DATABASE_CONNECTED, "database_connected")
DEF_ICO2(DATABASE_DEL, DATABASE, MINUS)
DEF_ICON(DATABASE_DISCONNECT, "database_disconnect")
DEF_ICO2(DATABASE_EDIT, DATABASE, EDIT)
DEF_ICON(DATABASE_EXPORT, "database_export")
DEF_ICON(DATABASE_EXPORT_WIZARD, "database_export_wizard")
- DEF_ICON(DATABASE_FILE, "database_file")
DEF_ICON(DATABASE_IMPORT_WIZARD, "database_import_wizard")
- DEF_ICON(DATABASE_NETWORK, "database_network")
DEF_ICON(DATABASE_OFFLINE, "database_offline")
DEF_ICO2(DATABASE_INVALID, DATABASE_OFFLINE, WARNING)
DEF_ICON(DATABASE_ONLINE, "database_online")
@@ -103,9 +100,7 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICO2(DIRECTORY_EDIT, DIRECTORY, EDIT)
DEF_ICON(DIRECTORY_OPEN, "directory_open")
DEF_ICON(DIRECTORY_OPEN_WITH_DB, "directory_open_with_db")
- DEF_ICON(DIRECTORY_WITH_DB, "directory_with_db")
- DEF_ICON(DOCK_LAYOUT_HORIZONTAL, "dock_layout_horizontal")
- DEF_ICON(DOCK_LAYOUT_VERTICAL, "dock_layout_vertical")
+ DEF_ICO3(DONATE, TEST_CONN_OK)
DEF_ICON(ERASE, "erase")
DEF_ICON(ERASE_TABLE_DATA, "erase_table_data")
DEF_ICON(EXEC_QUERY, "exec_query")
@@ -116,7 +111,6 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICON(EXTENSION, "brick")
DEF_ICON(EXTENSION_ADD, "brick_add")
DEF_ICON(EXTENSION_DELETE, "brick_delete")
- DEF_ICON(EXTENSION_EDITOR, "brick_folder")
DEF_ICON(EXTENSION_ERROR, "brick_error")
DEF_ICON(FEATURE_REQUEST, "feature_request")
DEF_ICON(FONT_BROWSE, "font_browse")
@@ -138,7 +132,6 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICON(INDICATOR_HINT, "indicator_hint")
DEF_ICON(INDICATOR_INFO, "indicator_info")
DEF_ICON(INDICATOR_WARN, "indicator_warn")
- DEF_ICON(INFO_BALLOON, "info_balloon")
DEF_ICON(INDEX_EXPR_ADD, "tag_hash_add")
DEF_ICON(INDEX_EXPR_EDIT, "tag_hash_edit")
DEF_ICON(INDEX_EXPR_DEL, "tag_hash_del")
@@ -147,15 +140,15 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICO3(INSERT_FN_ARG, INSERT_ROW)
DEF_ICO3(INSERT_DATATYPE, INSERT_ROW)
DEF_ICON(KEYWORD, "keyword")
- DEF_ICON(KEYBOARD, "keyboard")
- DEF_ICON(LOADING, "loading")
DEF_ICON(LICENSES, "licenses")
+ DEF_ICON(LOADING, "loading")
+ DEF_ICON(LOAD_FULL_VALUE, "load_full_value")
+ DEF_ICON(LOAD_FULL_VALUES, "load_full_values")
DEF_ICON(MOVE_DOWN, "move_down")
DEF_ICON(MOVE_UP, "move_up")
DEF_ICO3(NEW_COLLATION, INSERT_ROW)
DEF_ICO3(NEW_FUNCTION, INSERT_ROW)
DEF_ICON(OPEN_FILE, "open_sql_file")
- DEF_ICON(OPEN_FORUM, "open_forum")
DEF_ICON(OPEN_SQL_EDITOR, "open_sql_editor")
DEF_ICO3(OPEN_SQL_FILE, OPEN_FILE)
DEF_ICON(OPEN_VALUE_EDITOR, "open_value_editor")
@@ -166,6 +159,7 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICO3(MOVE_LEFT, PAGE_PREV)
DEF_ICO3(MOVE_RIGHT, PAGE_NEXT)
DEF_ICON(PLUS, "plus")
+ DEF_ICON(QUIT, "quit")
DEF_ICON(RELOAD, "reload")
DEF_ICON(RENAME_FN_ARG, "rename_fn_arg")
DEF_ICO3(RENAME_DATATYPE, RENAME_FN_ARG)
@@ -200,8 +194,6 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICON(SORT_COUNT_19, "sort_cnt_19")
DEF_ICON(SORT_COUNT_20, "sort_cnt_20")
DEF_ICON(SORT_COUNT_20_PLUS, "sort_cnt_20p")
- DEF_ICON(SORT_INDICATOR_ASC, "sort_ind_asc")
- DEF_ICON(SORT_INDICATOR_DESC, "sort_ind_desc")
DEF_ICON(SORT_RESET, "sort_reset")
DEF_ICON(SQLITE_DOCS, "sqlite_docs")
DEF_ICON(SQLITESTUDIO_APP, "sqlitestudio")
@@ -229,7 +221,6 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICON(TABS_ON_TOP, "tabs_on_top")
DEF_ICON(TEST_CONN_ERROR, "test_conn_error")
DEF_ICON(TEST_CONN_OK, "test_conn_ok")
- DEF_ICON(TIP, "tip")
DEF_ICON(TRIGGER, "trigger")
DEF_ICO2(TRIGGER_ADD, TRIGGER, PLUS)
DEF_ICON(TRIGGER_COLUMNS, "trigger_columns")
@@ -237,8 +228,6 @@ class GUI_API_EXPORT IconManager : public QObject
DEF_ICO2(TRIGGER_DEL, TRIGGER, MINUS)
DEF_ICO2(TRIGGER_EDIT, TRIGGER, EDIT)
DEF_ICON(TRIGGERS, "triggers")
- DEF_ICON(USER, "user")
- DEF_ICON(USER_UNKNOWN, "user_unknown")
DEF_ICON(USER_MANUAL, "user_manual")
DEF_ICON(VIEW, "view")
DEF_ICO2(VIEW_ADD, VIEW, PLUS)
diff --git a/SQLiteStudio3/guiSQLiteStudio/icons.qrc b/SQLiteStudio3/guiSQLiteStudio/icons.qrc
index b656f25..67c9351 100644
--- a/SQLiteStudio3/guiSQLiteStudio/icons.qrc
+++ b/SQLiteStudio3/guiSQLiteStudio/icons.qrc
@@ -8,7 +8,6 @@
<file>img/act_delete.png</file>
<file>img/act_paste.png</file>
<file>img/act_redo.png</file>
- <file>img/act_search.png</file>
<file>img/act_select_all.png</file>
<file>img/act_undo.png</file>
<file>img/apply_filter_re.png</file>
@@ -31,14 +30,10 @@
<file>img/completer_other.png</file>
<file>img/completer_pragma.png</file>
<file>img/completer_string.png</file>
- <file>img/configure_constraint.png</file>
<file>img/configure.png</file>
<file>img/database_connect.png</file>
- <file>img/database_connected.png</file>
<file>img/database_disconnect.png</file>
<file>img/database_export.png</file>
- <file>img/database_file.png</file>
- <file>img/database_network.png</file>
<file>img/database_reload.png</file>
<file>img/database.png</file>
<file>img/ddl_history.png</file>
@@ -49,7 +44,6 @@
<file>img/denied_small.png</file>
<file>img/directory_open_with_db.png</file>
<file>img/directory_open.png</file>
- <file>img/directory_with_db.png</file>
<file>img/directory.png</file>
<file>img/edit_small.png</file>
<file>img/erase.png</file>
@@ -70,7 +64,6 @@
<file>img/indicator_hint.png</file>
<file>img/indicator_info.png</file>
<file>img/indicator_warn.png</file>
- <file>img/info_balloon.png</file>
<file>img/info_small.png</file>
<file>img/insert_row.png</file>
<file>img/insert_rows.png</file>
@@ -162,19 +155,14 @@
<file>img/vacuum_db.png</file>
<file>img/bug.png</file>
<file>img/feature_request.png</file>
- <file>img/user_unknown.png</file>
- <file>img/user.png</file>
- <file>img/open_forum.png</file>
<file>img/user_manual.png</file>
<file>img/sqlite_docs.png</file>
- <file>img/tip.png</file>
<file>img/licenses.png</file>
<file>img/homepage.png</file>
<file>img/bug_list.png</file>
<file>img/get_update.png</file>
<file>img/sqlitestudio.svg</file>
<file>img/sqlitestudio_16.png</file>
- <file>img/keyboard.png</file>
<file>img/config_general.png</file>
<file>img/config_colors.png</file>
<file>img/config_font.png</file>
@@ -193,8 +181,6 @@
<file>img/plus.png</file>
<file>img/erase_table_data.png</file>
<file>img/delete.png</file>
- <file>img/dock_layout_horizontal.png</file>
- <file>img/dock_layout_vertical.png</file>
<file>img/tag_hash_add.png</file>
<file>img/tag_hash_del.png</file>
<file>img/tag_hash_edit.png</file>
@@ -209,7 +195,15 @@
<file>img/brick_add.png</file>
<file>img/brick_delete.png</file>
<file>img/brick_error.png</file>
- <file>img/brick_folder.png</file>
<file>img/execute_sql_from_file.png</file>
+ <file>img/dock_layout_horizontal.png</file>
+ <file>img/dock_layout_vertical.png</file>
+ <file>img/keyboard.png</file>
+ <file>img/disk_small.png</file>
+ <file>img/generated.png</file>
+ <file>img/lightning_small.png</file>
+ <file>img/load_full_value.png</file>
+ <file>img/load_full_values.png</file>
+ <file>img/quit.png</file>
</qresource>
</RCC>
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/act_search.png b/SQLiteStudio3/guiSQLiteStudio/img/act_search.png
deleted file mode 100644
index 7d57954..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/act_search.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/brick_folder.png b/SQLiteStudio3/guiSQLiteStudio/img/brick_folder.png
deleted file mode 100644
index 5dea976..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/brick_folder.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/configure_constraint.png b/SQLiteStudio3/guiSQLiteStudio/img/configure_constraint.png
deleted file mode 100644
index 40a7bf9..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/configure_constraint.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/database_connected.png b/SQLiteStudio3/guiSQLiteStudio/img/database_connected.png
deleted file mode 100644
index 71bc905..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/database_connected.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/database_file.png b/SQLiteStudio3/guiSQLiteStudio/img/database_file.png
deleted file mode 100644
index a36f74b..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/database_file.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/database_network.png b/SQLiteStudio3/guiSQLiteStudio/img/database_network.png
deleted file mode 100644
index 03f6f90..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/database_network.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/directory_with_db.png b/SQLiteStudio3/guiSQLiteStudio/img/directory_with_db.png
deleted file mode 100644
index 33c6d88..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/directory_with_db.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/disk_small.png b/SQLiteStudio3/guiSQLiteStudio/img/disk_small.png
new file mode 100644
index 0000000..df83a60
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/img/disk_small.png
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/function.png b/SQLiteStudio3/guiSQLiteStudio/img/function.png
index 18fa585..f2a57a6 100644
--- a/SQLiteStudio3/guiSQLiteStudio/img/function.png
+++ b/SQLiteStudio3/guiSQLiteStudio/img/function.png
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/generated.png b/SQLiteStudio3/guiSQLiteStudio/img/generated.png
new file mode 100644
index 0000000..efc599d
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/img/generated.png
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/info_balloon.png b/SQLiteStudio3/guiSQLiteStudio/img/info_balloon.png
deleted file mode 100644
index f14f2a3..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/info_balloon.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/lightning_small.png b/SQLiteStudio3/guiSQLiteStudio/img/lightning_small.png
new file mode 100644
index 0000000..e1b6e78
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/img/lightning_small.png
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/load_full_value.png b/SQLiteStudio3/guiSQLiteStudio/img/load_full_value.png
new file mode 100644
index 0000000..a7bd87b
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/img/load_full_value.png
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/load_full_values.png b/SQLiteStudio3/guiSQLiteStudio/img/load_full_values.png
new file mode 100644
index 0000000..7ae440a
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/img/load_full_values.png
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/open_forum.png b/SQLiteStudio3/guiSQLiteStudio/img/open_forum.png
deleted file mode 100644
index 6aa2603..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/open_forum.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/quit.png b/SQLiteStudio3/guiSQLiteStudio/img/quit.png
new file mode 100644
index 0000000..2bc51ac
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/img/quit.png
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/tip.png b/SQLiteStudio3/guiSQLiteStudio/img/tip.png
deleted file mode 100644
index 845e110..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/tip.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/user.png b/SQLiteStudio3/guiSQLiteStudio/img/user.png
deleted file mode 100644
index 2d44726..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/user.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/img/user_unknown.png b/SQLiteStudio3/guiSQLiteStudio/img/user_unknown.png
deleted file mode 100644
index 09f73c2..0000000
--- a/SQLiteStudio3/guiSQLiteStudio/img/user_unknown.png
+++ /dev/null
Binary files differ
diff --git a/SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp
index 2b6463a..57c7d35 100644
--- a/SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/mainwindow.cpp
@@ -38,7 +38,9 @@
#include "common/widgetcover.h"
#include "dialogs/cssdebugdialog.h"
#include "themetuner.h"
+#include "style.h"
#include "services/codeformatter.h"
+#include "common/compatibility.h"
#include <QMdiSubWindow>
#include <QDebug>
#include <QStyleFactory>
@@ -48,6 +50,7 @@
#include <QLabel>
#include <QStyle>
#include <QApplication>
+#include <QToolTip>
CFG_KEYS_DEFINE(MainWindow)
MainWindow* MainWindow::instance = nullptr;
@@ -126,13 +129,15 @@ void MainWindow::init()
}
#ifdef PORTABLE_CONFIG
- connect(UPDATES, SIGNAL(updatesAvailable(QList<UpdateManager::UpdateEntry>)), this, SLOT(updatesAvailable(QList<UpdateManager::UpdateEntry>)));
+ connect(UPDATES, SIGNAL(updateAvailable(QString, QString)), this, SLOT(updateAvailable(QString, QString)));
connect(UPDATES, SIGNAL(noUpdatesAvailable()), this, SLOT(noUpdatesAvailable()));
#endif
connect(statusField, SIGNAL(linkActivated(QString)), this, SLOT(statusFieldLinkClicked(QString)));
connect(CFG_CORE.General.Language, SIGNAL(changed(QVariant)), this, SLOT(notifyAboutLanguageChange()));
+ connect(CFG_UI.General.AllowMultipleSessions, SIGNAL(changed(QVariant)), this, SLOT(updateMultipleSessionsSetting(QVariant)));
+ updateMultipleSessionsSetting();
fixFonts();
}
@@ -257,14 +262,15 @@ void MainWindow::createActions()
createAction(OPEN_DEBUG_CONSOLE, tr("Open Debug Console"), this, SLOT(openDebugConsole()), this);
createAction(OPEN_CSS_CONSOLE, tr("Open CSS Console"), this, SLOT(openCssConsole()), this);
createAction(REPORT_BUG, ICONS.BUG, tr("Report a &bug"), this, SLOT(reportBug()), this);
+ createAction(DONATE, ICONS.DONATE, tr("D&onate"), this, SLOT(donate()), this);
createAction(FEATURE_REQUEST, ICONS.FEATURE_REQUEST, tr("Propose a new &feature"), this, SLOT(requestFeature()), this);
createAction(ABOUT, ICONS.SQLITESTUDIO_APP16, tr("&About"), this, SLOT(aboutSqlitestudio()), this);
createAction(LICENSES, ICONS.LICENSES, tr("&Licenses"), this, SLOT(licenses()), this);
createAction(HOMEPAGE, ICONS.HOMEPAGE, tr("Open home &page"), this, SLOT(homepage()), this);
- createAction(FORUM, ICONS.OPEN_FORUM, tr("Open fo&rum page"), this, SLOT(forum()), this);
createAction(USER_MANUAL, ICONS.USER_MANUAL, tr("User &Manual"), this, SLOT(userManual()), this);
createAction(SQLITE_DOCS, ICONS.SQLITE_DOCS, tr("SQLite &documentation"), this, SLOT(sqliteDocs()), this);
createAction(BUG_REPORT_HISTORY, ICONS.BUG_LIST, tr("Bugs and feature &requests"), this, SLOT(reportHistory()), this);
+ createAction(QUIT, ICONS.QUIT, tr("Quit"), this, SLOT(quit()), this);
#ifdef PORTABLE_CONFIG
createAction(CHECK_FOR_UPDATES, ICONS.GET_UPDATE, tr("Check for &updates"), this, SLOT(checkForUpdates()), this);
#endif
@@ -276,26 +282,10 @@ void MainWindow::createActions()
ui->dbToolbar->addAction(dbTree->getAction(DbTree::DISCONNECT_FROM_DB));
ui->dbToolbar->addSeparator();
ui->dbToolbar->addAction(dbTree->getAction(DbTree::ADD_DB));
- ui->dbToolbar->addAction(dbTree->getAction(DbTree::EDIT_DB));
- ui->dbToolbar->addAction(dbTree->getAction(DbTree::DELETE_DB));
- ui->dbToolbar->addSeparator();
ui->dbToolbar->addAction(dbTree->getAction(DbTree::REFRESH_SCHEMA));
ui->structureToolbar->addAction(dbTree->getAction(DbTree::ADD_TABLE));
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::EDIT_TABLE));
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::DEL_TABLE));
- ui->structureToolbar->addSeparator();
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::ADD_INDEX));
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::EDIT_INDEX));
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::DEL_INDEX));
- ui->structureToolbar->addSeparator();
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::ADD_TRIGGER));
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::EDIT_TRIGGER));
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::DEL_TRIGGER));
- ui->structureToolbar->addSeparator();
ui->structureToolbar->addAction(dbTree->getAction(DbTree::ADD_VIEW));
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::EDIT_VIEW));
- ui->structureToolbar->addAction(dbTree->getAction(DbTree::DEL_VIEW));
ui->taskBar->initContextMenu(this);
}
@@ -315,12 +305,15 @@ void MainWindow::initMenuBar()
dbMenu->addAction(dbTree->getAction(DbTree::DELETE_DB));
dbMenu->addSeparator();
dbMenu->addAction(dbTree->getAction(DbTree::EXPORT_DB));
- dbMenu->addAction(dbTree->getAction(DbTree::CONVERT_DB));
dbMenu->addAction(dbTree->getAction(DbTree::VACUUM_DB));
dbMenu->addAction(dbTree->getAction(DbTree::INTEGRITY_CHECK));
dbMenu->addSeparator();
dbMenu->addAction(dbTree->getAction(DbTree::REFRESH_SCHEMA));
dbMenu->addAction(dbTree->getAction(DbTree::REFRESH_SCHEMAS));
+#ifndef Q_OS_MACX
+ dbMenu->addSeparator();
+ dbMenu->addAction(actionMap[QUIT]);
+#endif
// Structure menu
structMenu = new QMenu(this);
@@ -395,7 +388,6 @@ void MainWindow::initMenuBar()
sqlitestudioMenu->addAction(actionMap[USER_MANUAL]);
sqlitestudioMenu->addAction(actionMap[SQLITE_DOCS]);
sqlitestudioMenu->addAction(actionMap[HOMEPAGE]);
- sqlitestudioMenu->addAction(actionMap[FORUM]);
sqlitestudioMenu->addSeparator();
#ifdef PORTABLE_CONFIG
if (UPDATES->isPlatformEligibleForUpdate())
@@ -409,6 +401,7 @@ void MainWindow::initMenuBar()
sqlitestudioMenu->addAction(actionMap[BUG_REPORT_HISTORY]);
sqlitestudioMenu->addSeparator();
sqlitestudioMenu->addAction(actionMap[LICENSES]);
+ sqlitestudioMenu->addAction(actionMap[DONATE]);
sqlitestudioMenu->addAction(actionMap[ABOUT]);
}
@@ -450,6 +443,7 @@ void MainWindow::restoreSession()
if (sessionValue.size() == 0)
{
THEME_TUNER->tuneCurrentTheme();
+ restoreState(saveState()); // workaround for probable Qt bug (?), reported in #3421
return;
}
@@ -463,6 +457,8 @@ void MainWindow::restoreSession()
if (sessionValue.contains("state"))
restoreState(sessionValue["state"].toByteArray());
+ else
+ restoreState(saveState()); // workaround for probable Qt bug (?), reported in #3421
if (sessionValue.contains("dbTree"))
dbTree->restoreSession(sessionValue["dbTree"]);
@@ -550,13 +546,14 @@ void MainWindow::setStyle(const QString& styleName)
notifyWarn(tr("Could not set style: %1", "main window").arg(styleName));
return;
}
- QApplication::setStyle(style);
- THEME_TUNER->tuneTheme(styleName);
+
+ STYLE->setStyle(style, styleName);
+ statusField->refreshColors();
}
QString MainWindow::currentStyle() const
{
- return QApplication::style()->objectName();
+ return STYLE->name();
}
EditorWindow* MainWindow::openSqlEditor(Db* dbToSet, const QString& sql)
@@ -606,7 +603,7 @@ void MainWindow::refreshMdiWindows()
nameToAction[action->text()] = action;
}
- qSort(actionNames);
+ sSort(actionNames);
for (const QString& name : actionNames)
mdiMenu->addAction(nameToAction[name]);
@@ -744,9 +741,9 @@ void MainWindow::homepage()
QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getHomePage()));
}
-void MainWindow::forum()
+void MainWindow::githubReleases()
{
- QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getForumPage()));
+ QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getGitHubReleases()));
}
void MainWindow::userManual()
@@ -764,6 +761,11 @@ void MainWindow::reportHistory()
QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getIssuesPage()));
}
+void MainWindow::donate()
+{
+ QDesktopServices::openUrl(QUrl(SQLITESTUDIO->getDonatePage()));
+}
+
void MainWindow::statusFieldLinkClicked(const QString& link)
{
#ifdef PORTABLE_CONFIG
@@ -775,12 +777,29 @@ void MainWindow::statusFieldLinkClicked(const QString& link)
#endif
}
+void MainWindow::quit()
+{
+ close();
+}
+
+void MainWindow::updateMultipleSessionsSetting(const QVariant& newValue)
+{
+ QSettings sett;
+ sett.setValue(ALLOW_MULTIPLE_SESSIONS_SETTING, newValue);
+}
+
+void MainWindow::updateMultipleSessionsSetting()
+{
+ QSettings sett;
+ sett.setValue(ALLOW_MULTIPLE_SESSIONS_SETTING, CFG_UI.General.AllowMultipleSessions.get());
+}
+
#ifdef PORTABLE_CONFIG
-void MainWindow::updatesAvailable(const QList<UpdateManager::UpdateEntry>& updates)
+void MainWindow::updateAvailable(const QString& version, const QString& url)
{
manualUpdatesChecking = false;
newVersionDialog = new NewVersionDialog(this);
- newVersionDialog->setUpdates(updates);
+ newVersionDialog->setUpdate(version, url);
notifyInfo(tr("New updates are available. <a href=\"%1\">Click here for details</a>.").arg(openUpdatesUrl));
}
@@ -820,7 +839,11 @@ void MainWindow::messageFromSecondaryInstance(quint32 instanceId, QByteArray mes
{
UNUSED(instanceId);
QApplication::setActiveWindow(this);
+ if (isMinimized())
+ showMaximized();
+
raise();
+ activateWindow();
QString dbToOpen = deserializeFromBytes(message).toString();
if (!dbToOpen.isNull())
openDb(dbToOpen);
diff --git a/SQLiteStudio3/guiSQLiteStudio/mainwindow.h b/SQLiteStudio3/guiSQLiteStudio/mainwindow.h
index fbc3317..cedbc20 100644
--- a/SQLiteStudio3/guiSQLiteStudio/mainwindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/mainwindow.h
@@ -49,6 +49,7 @@ CFG_KEY_LIST(MainWindow, QObject::tr("Main window"),
CFG_KEY_ENTRY(OPEN_CONFIG, Qt::Key_F2, QObject::tr("Open configuration dialog"))
CFG_KEY_ENTRY(OPEN_DEBUG_CONSOLE, Qt::Key_F12, QObject::tr("Open Debug Console"))
CFG_KEY_ENTRY(OPEN_CSS_CONSOLE, Qt::Key_F11, QObject::tr("Open CSS Console"))
+ CFG_KEY_ENTRY(QUIT, Qt::CTRL + Qt::Key_Q, QObject::tr("Quit the application"))
)
class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer
@@ -83,14 +84,15 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer
OPEN_CSS_CONSOLE,
LICENSES,
HOMEPAGE,
- FORUM,
USER_MANUAL,
SQLITE_DOCS,
REPORT_BUG,
FEATURE_REQUEST,
ABOUT,
+ DONATE,
BUG_REPORT_HISTORY,
- CHECK_FOR_UPDATES
+ CHECK_FOR_UPDATES,
+ QUIT
};
enum ToolBar
@@ -124,6 +126,8 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer
ThemeTuner* getThemeTuner() const;
EditorWindow* openSqlEditor(Db* dbToSet, const QString& sql);
+ static_char* ALLOW_MULTIPLE_SESSIONS_SETTING = "AllowMultipleSessions";
+
protected:
void closeEvent(QCloseEvent *event);
@@ -177,6 +181,13 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer
void updateWindowActions();
void updateCornerDocking();
void messageFromSecondaryInstance(quint32 instanceId, QByteArray message);
+ void licenses();
+ void homepage();
+ void githubReleases();
+ void userManual();
+ void sqliteDocs();
+ void reportHistory();
+ void donate();
private slots:
void notifyAboutLanguageChange();
@@ -201,18 +212,15 @@ class GUI_API_EXPORT MainWindow : public QMainWindow, public ExtActionContainer
void reportBug();
void requestFeature();
void aboutSqlitestudio();
- void licenses();
- void homepage();
- void forum();
- void userManual();
- void sqliteDocs();
- void reportHistory();
#ifdef PORTABLE_CONFIG
- void updatesAvailable(const QList<UpdateManager::UpdateEntry>& updates);
+ void updateAvailable(const QString& version, const QString& url);
void noUpdatesAvailable();
void checkForUpdates();
#endif
void statusFieldLinkClicked(const QString& link);
+ void quit();
+ void updateMultipleSessionsSetting();
+ void updateMultipleSessionsSetting(const QVariant& newValue);
};
template <class T>
diff --git a/SQLiteStudio3/guiSQLiteStudio/mdiwindow.h b/SQLiteStudio3/guiSQLiteStudio/mdiwindow.h
index 7003425..9a7be2b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/mdiwindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/mdiwindow.h
@@ -14,7 +14,7 @@ class GUI_API_EXPORT MdiWindow : public QMdiSubWindow
Q_OBJECT
public:
- MdiWindow(MdiChild* mdiChild, MdiArea *mdiArea, Qt::WindowFlags flags = 0);
+ MdiWindow(MdiChild* mdiChild, MdiArea *mdiArea, Qt::WindowFlags flags = Qt::WindowFlags());
virtual ~MdiWindow();
virtual QVariant saveSession();
diff --git a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp
index d766738..0f965cd 100644
--- a/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/multieditor/multieditor.cpp
@@ -14,6 +14,8 @@
#include "uiconfig.h"
#include "dialogs/configdialog.h"
#include "formview.h"
+#include "themetuner.h"
+#include "common/compatibility.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTabWidget>
@@ -26,7 +28,6 @@
#include <QToolButton>
#include <QDebug>
#include <QKeyEvent>
-#include <themetuner.h>
static QHash<QString,bool> missingEditorPluginsAlreadyWarned;
@@ -55,7 +56,7 @@ void MultiEditor::init(TabsMode tabsMode)
QFont font = cornerLabel->font();
font.setBold(true);
cornerLabel->setFont(font);
- cornerLabel->setFrameStyle(QFrame::StyledPanel|QFrame::Plain);
+ cornerLabel->setFrameStyle(QFrame::NoFrame);
hbox->addWidget(cornerLabel);
cornerLabel->setVisible(false);
@@ -365,7 +366,7 @@ QList<MultiEditorWidget*> MultiEditor::getEditorTypes(const DataType& dataType)
sortedEditors << editorWithPrio;
}
- qSort(sortedEditors.begin(), sortedEditors.end(), [=](const EditorWithPriority& ed1, const EditorWithPriority& ed2) -> bool
+ sSort(sortedEditors, [=](const EditorWithPriority& ed1, const EditorWithPriority& ed2) -> bool
{
return ed1.first < ed2.first;
});
diff --git a/SQLiteStudio3/guiSQLiteStudio/qhexedit2/qhexedit_p.cpp b/SQLiteStudio3/guiSQLiteStudio/qhexedit2/qhexedit_p.cpp
index 3919c19..18b85cf 100644
--- a/SQLiteStudio3/guiSQLiteStudio/qhexedit2/qhexedit_p.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/qhexedit2/qhexedit_p.cpp
@@ -855,7 +855,7 @@ void QHexEditPrivate::updateCursor()
void QHexEditPrivate::adjust()
{
- _charWidth = fontMetrics().width(QLatin1Char('9'));
+ _charWidth = fontMetrics().horizontalAdvance(QLatin1Char('9'));
_charHeight = fontMetrics().height();
_xPosAdr = 0;
diff --git a/SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.cpp b/SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.cpp
index 6ca5c59..58e4315 100644
--- a/SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.cpp
@@ -1,6 +1,7 @@
#include "qtscriptsyntaxhighlighter.h"
-#include "uiconfig.h"
-
+#include "style.h"
+#include <QApplication>
+#include <QStyle>
#include <QPlainTextEdit>
JavaScriptSyntaxHighlighter::JavaScriptSyntaxHighlighter(QTextDocument *parent)
@@ -183,6 +184,7 @@ JavaScriptSyntaxHighlighter::JavaScriptSyntaxHighlighter(QTextDocument *parent)
m_knownIds << "userAgent";
keywordsFormat.setFontWeight(QFont::Bold);
+ commentFormat.setFontItalic(true);
}
void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
@@ -197,6 +199,12 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
Regex = 5
};
+ commentFormat.setForeground(QApplication::style()->standardPalette().dark());
+ keywordsFormat.setForeground(QApplication::style()->standardPalette().windowText());
+ keywordsFormat.setFontWeight(QFont::Bold);
+ normalFormat.setForeground(QApplication::style()->standardPalette().text());
+ stringFormat.setForeground(STYLE->extendedPalette().editorString());
+
int state = previousBlockState();
int start = 0;
int i = 0;
@@ -225,13 +233,13 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
state = Comment;
} else if (ch == '/' && next == '/') {
i = text.length();
- setFormat(start, text.length(), CFG_UI.Colors.JavaScriptComment.get());
+ setFormat(start, text.length(), commentFormat);
} else if (ch == '/' && next != '*') {
++i;
state = Regex;
} else {
if (!QString("(){}[]").contains(ch))
- setFormat(start, 1, CFG_UI.Colors.JavaScriptOperator.get());
+ setFormat(start, 1, normalFormat);
++i;
state = Start;
}
@@ -239,7 +247,7 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
case Number:
if (ch.isSpace() || !ch.isDigit()) {
- setFormat(start, i - start, CFG_UI.Colors.JavaScriptNumber.get());
+ setFormat(start, i - start, normalFormat);
state = Start;
} else {
++i;
@@ -250,12 +258,10 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
if (ch.isSpace() || !(ch.isDigit() || ch.isLetter() || ch == '_')) {
QString token = text.mid(start, i - start).trimmed();
if (m_keywords.contains(token))
- {
- keywordsFormat.setForeground(CFG_UI.Colors.JavaScriptKeyword.get());
setFormat(start, i - start, keywordsFormat);
- }
else if (m_knownIds.contains(token))
- setFormat(start, i - start, CFG_UI.Colors.JavaScriptBuiltIn.get());
+ setFormat(start, i - start, normalFormat);
+
state = Start;
} else {
++i;
@@ -267,7 +273,7 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
QChar prev = (i > 0) ? text.at(i - 1) : QChar();
if (prev != '\\') {
++i;
- setFormat(start, i - start, CFG_UI.Colors.JavaScriptString.get());
+ setFormat(start, i - start, stringFormat);
state = Start;
} else {
++i;
@@ -281,7 +287,7 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
if (ch == '*' && next == '/') {
++i;
++i;
- setFormat(start, i - start, CFG_UI.Colors.JavaScriptComment.get());
+ setFormat(start, i - start, commentFormat);
state = Start;
} else {
++i;
@@ -293,7 +299,7 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
QChar prev = (i > 0) ? text.at(i - 1) : QChar();
if (prev != '\\') {
++i;
- setFormat(start, i - start, CFG_UI.Colors.JavaScriptString.get());
+ setFormat(start, i - start, normalFormat);
state = Start;
} else {
++i;
@@ -310,7 +316,7 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
}
if (state == Comment)
- setFormat(start, text.length(), CFG_UI.Colors.JavaScriptComment.get());
+ setFormat(start, text.length(), commentFormat);
else
state = Start;
@@ -318,8 +324,8 @@ void JavaScriptSyntaxHighlighter::highlightBlock(const QString &text)
int pos = 0;
int len = m_markString.length();
QTextCharFormat markerFormat;
- markerFormat.setBackground(CFG_UI.Colors.JavaScriptMarker.get());
- markerFormat.setForeground(CFG_UI.Colors.JavaScriptFg.get());
+ markerFormat.setBackground(QApplication::style()->standardPalette().alternateBase());
+ markerFormat.setForeground(QApplication::style()->standardPalette().text());
for (;;) {
pos = text.indexOf(m_markString, pos, m_markCaseSensitivity);
if (pos < 0)
diff --git a/SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.h b/SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.h
index bf978d2..3d701de 100644
--- a/SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.h
+++ b/SQLiteStudio3/guiSQLiteStudio/qtscriptsyntaxhighlighter.h
@@ -56,7 +56,10 @@ class GUI_API_EXPORT JavaScriptSyntaxHighlighter : public QSyntaxHighlighter
QSet<QString> m_knownIds;
QString m_markString;
Qt::CaseSensitivity m_markCaseSensitivity;
+ QTextCharFormat normalFormat;
QTextCharFormat keywordsFormat;
+ QTextCharFormat commentFormat;
+ QTextCharFormat stringFormat;
};
class GUI_API_EXPORT JavaScriptHighlighterPlugin : public BuiltInPlugin, public SyntaxHighlighterPlugin
diff --git a/SQLiteStudio3/guiSQLiteStudio/searchtextlocator.h b/SQLiteStudio3/guiSQLiteStudio/searchtextlocator.h
index 02ab9fa..534da51 100644
--- a/SQLiteStudio3/guiSQLiteStudio/searchtextlocator.h
+++ b/SQLiteStudio3/guiSQLiteStudio/searchtextlocator.h
@@ -60,7 +60,7 @@ class GUI_API_EXPORT SearchTextLocator : public QObject
int startPosition = 0;
public slots:
- bool find(QTextDocument::FindFlags flags = 0);
+ bool find(QTextDocument::FindFlags flags = QTextDocument::FindFlags());
void findNext();
void findPrev();
bool replaceAndFind();
diff --git a/SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp
index 75579d5..d9d99ba 100644
--- a/SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp
@@ -1,6 +1,7 @@
#include "selectabledbobjmodel.h"
#include "dbtree/dbtreeitem.h"
#include "dbtree/dbtreemodel.h"
+#include "common/compatibility.h"
#include <QDebug>
#include <QTreeView>
@@ -29,10 +30,10 @@ bool SelectableDbObjModel::setData(const QModelIndex& index, const QVariant& val
return true;
}
-Qt::ItemFlags SelectableDbObjModel::flags(const QModelIndex& index) const
+Qt::ItemFlags SelectableDbObjModel::flags(const QModelIndex& idx) const
{
- Qt::ItemFlags flags = QSortFilterProxyModel::flags(index);
- DbTreeItem* item = getItemForProxyIndex(index);
+ Qt::ItemFlags flags = QSortFilterProxyModel::flags(idx);
+ DbTreeItem* item = getItemForProxyIndex(idx);
switch (item->getType())
{
case DbTreeItem::Type::TABLE:
@@ -47,7 +48,7 @@ Qt::ItemFlags SelectableDbObjModel::flags(const QModelIndex& index) const
case DbTreeItem::Type::VIEWS:
{
flags |= Qt::ItemIsUserCheckable;
- if (index.child(0, 0).isValid())
+ if (index(0, 0, idx).isValid())
flags |= Qt::ItemIsTristate;
break;
@@ -76,12 +77,12 @@ void SelectableDbObjModel::setDbName(const QString& value)
}
QStringList SelectableDbObjModel::getCheckedObjects() const
{
- return checkedObjects.toList();
+ return checkedObjects.values();
}
void SelectableDbObjModel::setCheckedObjects(const QStringList& value)
{
- checkedObjects = value.toSet();
+ checkedObjects = toSet(value);
}
void SelectableDbObjModel::setRootChecked(bool checked)
@@ -147,13 +148,13 @@ DbTreeItem* SelectableDbObjModel::getItemForProxyIndex(const QModelIndex& index)
return item;
}
-Qt::CheckState SelectableDbObjModel::getStateFromChilds(const QModelIndex& index) const
+Qt::CheckState SelectableDbObjModel::getStateFromChilds(const QModelIndex& idx) const
{
- DbTreeItem* item = getItemForProxyIndex(index);
+ DbTreeItem* item = getItemForProxyIndex(idx);
if (!item)
return Qt::Unchecked;
- if (!index.child(0, 0).isValid())
+ if (!index(0, 0, idx).isValid())
{
if (isObject(item) && checkedObjects.contains(item->text()))
return Qt::Checked;
@@ -166,7 +167,7 @@ Qt::CheckState SelectableDbObjModel::getStateFromChilds(const QModelIndex& index
int partial = 0;
Qt::CheckState state;
QModelIndex child;
- for (int i = 0; (child = index.child(i, 0)).isValid(); i++)
+ for (int i = 0; (child = index(i, 0, idx)).isValid(); i++)
{
if (!child.flags().testFlag(Qt::ItemIsUserCheckable))
continue;
@@ -200,9 +201,9 @@ Qt::CheckState SelectableDbObjModel::getStateFromChilds(const QModelIndex& index
return Qt::PartiallyChecked;
}
-void SelectableDbObjModel::setRecurrently(const QModelIndex& index, Qt::CheckState checked)
+void SelectableDbObjModel::setRecurrently(const QModelIndex& idx, Qt::CheckState checked)
{
- DbTreeItem* item = getItemForProxyIndex(index);
+ DbTreeItem* item = getItemForProxyIndex(idx);
if (!item)
return;
@@ -211,14 +212,14 @@ void SelectableDbObjModel::setRecurrently(const QModelIndex& index, Qt::CheckSta
else
checkedObjects.remove(item->text());
- if (!index.child(0, 0).isValid())
+ if (!index(0, 0, idx).isValid())
return;
// Limiting checked to 'checked/unchecked', cause recurrent marking cannot set partially checked, it makes no sense
checked = (checked > 0 ? Qt::Checked : Qt::Unchecked);
QModelIndex child;
- for (int i = 0; (child = index.child(i, 0)).isValid(); i++)
+ for (int i = 0; (child = index(i, 0, idx)).isValid(); i++)
setData(child, checked, Qt::CheckStateRole);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp b/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp
index b3656a6..50189d4 100644
--- a/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/sqleditor.cpp
@@ -17,6 +17,7 @@
#include "searchtextlocator.h"
#include "services/codeformatter.h"
#include "sqlitestudio.h"
+#include "style.h"
#include "dbtree/dbtreeitem.h"
#include "dbtree/dbtree.h"
#include "dbtree/dbtreemodel.h"
@@ -31,6 +32,7 @@
#include <QScrollBar>
#include <QFileDialog>
#include <QtConcurrent/QtConcurrent>
+#include <QStyle>
CFG_KEYS_DEFINE(SqlEditor)
@@ -69,10 +71,9 @@ void SqlEditor::init()
connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int)));
connect(this, SIGNAL(textChanged()), this, SLOT(checkContentSize()));
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(cursorMoved()));
- connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
updateLineNumberAreaWidth();
- highlightCurrentLine();
+ highlightCurrentCursorContext();
completer = new CompleterWindow(this);
connect(completer, SIGNAL(accepted()), this, SLOT(completeSelected()));
@@ -87,11 +88,11 @@ void SqlEditor::init()
connect(autoCompleteTrigger, SIGNAL(triggered()), this, SLOT(checkForAutoCompletion()));
queryParserTrigger = new LazyTrigger(queryParserDelay, this);
- connect(autoCompleteTrigger, SIGNAL(triggered()), this, SLOT(parseContents()));
+ connect(queryParserTrigger, SIGNAL(triggered()), this, SLOT(parseContents()));
connect(this, SIGNAL(textChanged()), this, SLOT(scheduleQueryParser()));
- queryParser = new Parser(Dialect::Sqlite3);
+ queryParser = new Parser();
connect(this, &QWidget::customContextMenuRequested, this, &SqlEditor::customContextMenuRequested);
connect(CFG_UI.Fonts.SqlEditor, SIGNAL(changed(QVariant)), this, SLOT(changeFont(QVariant)));
@@ -215,8 +216,7 @@ bool SqlEditor::handleValidObjectContextMenu(const QPoint& pos)
if (!obj)
return false;
- Dialect dialect = getDialect();
- QString objName = stripObjName(toPlainText().mid(obj->from, (obj->to - obj->from + 1)), dialect);
+ QString objName = stripObjName(toPlainText().mid(obj->from, (obj->to - obj->from + 1)));
validObjContextMenu->clear();
@@ -492,12 +492,12 @@ void SqlEditor::completeSelected()
ExpectedTokenPtr token = completer->getSelected();
QString value = token->value;
if (token->needsWrapping())
- value = wrapObjIfNeeded(value, getDialect());
+ value = wrapObjIfNeeded(value);
if (!token->prefix.isNull())
{
value.prepend(".");
- value.prepend(wrapObjIfNeeded(token->prefix, getDialect()));
+ value.prepend(wrapObjIfNeeded(token->prefix));
}
insertPlainText(value);
@@ -508,7 +508,7 @@ void SqlEditor::checkForAutoCompletion()
if (!db || !autoCompletion || deletionKeyPressed || !richFeaturesEnabled)
return;
- Lexer lexer(getDialect());
+ Lexer lexer;
QString sql = toPlainText();
int curPos = textCursor().position();
TokenList tokens = lexer.tokenize(sql.left(curPos));
@@ -546,11 +546,6 @@ void SqlEditor::refreshValidObjects()
});
}
-Dialect SqlEditor::getDialect()
-{
- return !db ? Dialect::Sqlite3 : db->getDialect();
-}
-
void SqlEditor::setObjectLinks(bool enabled)
{
objectLinksEnabled = enabled;
@@ -579,7 +574,7 @@ void SqlEditor::clearDbObjects()
void SqlEditor::lineNumberAreaPaintEvent(QPaintEvent* event)
{
QPainter painter(lineNumberArea);
- painter.fillRect(event->rect(), CFG_UI.Colors.SqlEditorLineNumAreaBg.get());
+ painter.fillRect(event->rect(), STYLE->extendedPalette().editorLineBase());
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
@@ -589,7 +584,7 @@ void SqlEditor::lineNumberAreaPaintEvent(QPaintEvent* event)
if (block.isVisible() && bottom >= event->rect().top())
{
QString number = QString::number(blockNumber + 1);
- painter.setPen(Qt::black);
+ painter.setPen(style()->standardPalette().text().color());
painter.drawText(0, top, lineNumberArea->width()-2, fontMetrics().height(), Qt::AlignRight, number);
}
@@ -610,27 +605,15 @@ int SqlEditor::lineNumberAreaWidth()
digits++;
}
- int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;
+ int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;
return space;
}
-void SqlEditor::highlightParenthesis()
+void SqlEditor::highlightParenthesis(QList<QTextEdit::ExtraSelection>& selections)
{
if (!richFeaturesEnabled)
return;
- // Clear extra selections
- QList<QTextEdit::ExtraSelection> selections = extraSelections();
-
- // Just keep "current line" highlighting
- QMutableListIterator<QTextEdit::ExtraSelection> it(selections);
- while (it.hasNext())
- {
- if (!it.next().format.property(QTextFormat::FullWidthSelection).toBool())
- it.remove();
- }
- setExtraSelections(selections);
-
// Find out parenthesis under the cursor
int curPos = textCursor().position();
TextBlockData* data = dynamic_cast<TextBlockData*>(textCursor().block().userData());
@@ -664,6 +647,13 @@ void SqlEditor::highlightParenthesis()
// Mark new match
markMatchedParenthesis(thePar->position, matchedPar->position, selections);
+}
+
+void SqlEditor::highlightCurrentCursorContext()
+{
+ QList<QTextEdit::ExtraSelection> selections;
+ highlightCurrentLine(selections);
+ highlightParenthesis(selections);
setExtraSelections(selections);
}
@@ -671,7 +661,8 @@ void SqlEditor::markMatchedParenthesis(int pos1, int pos2, QList<QTextEdit::Extr
{
QTextEdit::ExtraSelection selection;
- selection.format.setBackground(CFG_UI.Colors.SqlEditorParenthesisBg.get());
+ selection.format.setBackground(style()->standardPalette().windowText());
+ selection.format.setForeground(style()->standardPalette().window());
QTextCursor cursor = textCursor();
@@ -841,11 +832,6 @@ void SqlEditor::parseContents()
if (!richFeaturesEnabled)
return;
- // Updating dialect according to current database (if any)
- Dialect dialect = Dialect::Sqlite3;
- if (db && db->isValid())
- dialect = db->getDialect();
-
QString sql = toPlainText();
if (!virtualSqlExpression.isNull())
{
@@ -855,7 +841,6 @@ void SqlEditor::parseContents()
sql = virtualSqlExpression.arg(sql);
}
- queryParser->setDialect(dialect);
if (richFeaturesEnabled)
{
queryParser->parse(sql);
@@ -863,7 +848,6 @@ void SqlEditor::parseContents()
checkForSyntaxErrors();
highlighter->rehighlight();
}
-
}
void SqlEditor::checkForSyntaxErrors()
@@ -903,7 +887,6 @@ void SqlEditor::checkForValidObjects()
return;
QMutexLocker lock(&objectsInNamedDbMutex);
- Dialect dialect = db->getDialect();
QList<SqliteStatement::FullObject> fullObjects;
QString dbName;
for (SqliteQueryPtr query : queryParser->getQueries())
@@ -911,18 +894,18 @@ void SqlEditor::checkForValidObjects()
fullObjects = query->getContextFullObjects();
for (const SqliteStatement::FullObject& fullObj : fullObjects)
{
- dbName = fullObj.database ? stripObjName(fullObj.database->value, dialect) : "main";
+ dbName = fullObj.database ? stripObjName(fullObj.database->value) : "main";
if (!objectsInNamedDb.contains(dbName))
continue;
if (fullObj.type == SqliteStatement::FullObject::DATABASE)
{
// Valid db name
- addDbObject(sqlIndex(fullObj.database->start), sqlIndex(fullObj.database->end), QString::null);
+ addDbObject(sqlIndex(fullObj.database->start), sqlIndex(fullObj.database->end), QString());
continue;
}
- if (!objectsInNamedDb[dbName].contains(stripObjName(fullObj.object->value, dialect)))
+ if (!objectsInNamedDb[dbName].contains(stripObjName(fullObj.object->value)))
continue;
// Valid object name
@@ -999,22 +982,18 @@ void SqlEditor::updateLineNumberAreaWidth()
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}
-void SqlEditor::highlightCurrentLine()
+void SqlEditor::highlightCurrentLine(QList<QTextEdit::ExtraSelection>& selections)
{
- QList<QTextEdit::ExtraSelection> selections;
-
if (!isReadOnly() && isEnabled())
{
QTextEdit::ExtraSelection selection;
- selection.format.setBackground(CFG_UI.Colors.SqlEditorCurrentLineBg.get());
+ selection.format.setBackground(STYLE->extendedPalette().editorLineBase());
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = textCursor();
selection.cursor.clearSelection();
selections.append(selection);
}
-
- setExtraSelections(selections);
}
void SqlEditor::updateLineNumberArea(const QRect& rect, int dy)
@@ -1036,8 +1015,7 @@ void SqlEditor::updateLineNumberArea(const QRect& rect, int dy)
void SqlEditor::cursorMoved()
{
- highlightParenthesis();
-
+ highlightCurrentCursorContext();
if (!cursorMovingByLocator)
{
textLocator->setStartPosition(textCursor().position());
@@ -1321,6 +1299,7 @@ void SqlEditor::changeFont(const QVariant& font)
void SqlEditor::configModified()
{
highlighter->rehighlight();
+ highlightCurrentCursorContext();
}
void SqlEditor::toggleComment()
@@ -1503,7 +1482,7 @@ void SqlEditor::mousePressEvent(QMouseEvent* e)
if (obj && e->button() == Qt::LeftButton)
{
QString objName = toPlainText().mid(obj->from, (obj->to - obj->from + 1));
- openObject(obj->dbName, stripObjName(objName, getDialect()));
+ openObject(obj->dbName, stripObjName(objName));
}
}
@@ -1597,7 +1576,7 @@ void SqlEditor::setVirtualSqlExpression(const QString& value)
if (virtualSqlOffset == -1)
{
virtualSqlOffset = 0;
- virtualSqlExpression = QString::null;
+ virtualSqlExpression = QString();
qWarning() << "Tried to set invalid virtualSqlExpression for SqlEditor. Ignored.";
return;
}
@@ -1657,8 +1636,8 @@ void SqlEditor::LineNumberArea::paintEvent(QPaintEvent* event)
void SqlEditor::changeEvent(QEvent* e)
{
- if (e->type() == QEvent::EnabledChange)
- highlightCurrentLine();
+// if (e->type() == QEvent::EnabledChange)
+// highlightCurrentLine();
QPlainTextEdit::changeEvent(e);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/sqleditor.h b/SQLiteStudio3/guiSQLiteStudio/sqleditor.h
index c56492c..ca79a1c 100644
--- a/SQLiteStudio3/guiSQLiteStudio/sqleditor.h
+++ b/SQLiteStudio3/guiSQLiteStudio/sqleditor.h
@@ -165,13 +165,14 @@ class GUI_API_EXPORT SqlEditor : public QPlainTextEdit, public ExtActionContaine
void refreshValidObjects();
void checkForSyntaxErrors();
void checkForValidObjects();
- Dialect getDialect();
void setObjectLinks(bool enabled);
void addDbObject(int from, int to, const QString& dbName);
void clearDbObjects();
void lineNumberAreaPaintEvent(QPaintEvent* event);
int lineNumberAreaWidth();
- void highlightParenthesis();
+ void highlightParenthesis(QList<QTextEdit::ExtraSelection>& selections);
+ void highlightCurrentLine(QList<QTextEdit::ExtraSelection>& selections);
+ void highlightCurrentCursorContext();
const TextBlockData::Parenthesis* matchParenthesis(QList<const TextBlockData::Parenthesis*> parList, const TextBlockData::Parenthesis* thePar);
void markMatchedParenthesis(int pos1, int pos2, QList<QTextEdit::ExtraSelection>& selections);
void doBackspace(int repeats = 1);
@@ -269,7 +270,6 @@ class GUI_API_EXPORT SqlEditor : public QPlainTextEdit, public ExtActionContaine
void parseContents();
void scheduleQueryParser(bool force = false);
void updateLineNumberAreaWidth();
- void highlightCurrentLine();
void updateLineNumberArea(const QRect&rect, int dy);
void cursorMoved();
void checkContentSize();
diff --git a/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp b/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp
index 55ccc08..92679e2 100644
--- a/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.cpp
@@ -1,10 +1,13 @@
#include "sqlitesyntaxhighlighter.h"
#include "parser/lexer.h"
-#include "uiconfig.h"
#include "services/config.h"
+#include "style.h"
+#include "parser/keywords.h"
#include <QTextDocument>
#include <QDebug>
#include <QPlainTextEdit>
+#include <QApplication>
+#include <QStyle>
SqliteSyntaxHighlighter::SqliteSyntaxHighlighter(QTextDocument *parent) :
QSyntaxHighlighter(parent)
@@ -15,12 +18,6 @@ SqliteSyntaxHighlighter::SqliteSyntaxHighlighter(QTextDocument *parent) :
connect(CFG, SIGNAL(massSaveCommitted()), this, SLOT(setupFormats()));
}
-void SqliteSyntaxHighlighter::setSqliteVersion(int version)
-{
- this->sqliteVersion = version;
- rehighlight();
-}
-
void SqliteSyntaxHighlighter::setFormat(SqliteSyntaxHighlighter::State state, QTextCharFormat format)
{
formats[state] = format;
@@ -36,46 +33,47 @@ void SqliteSyntaxHighlighter::setupFormats()
QTextCharFormat format;
// Standard
- format.setForeground(CFG_UI.Colors.SqlEditorForeground.get());
+ format.setForeground(QApplication::style()->standardPalette().text());
format.setFontWeight(QFont::Normal);
format.setFontItalic(false);
formats[State::STANDARD] = format;
// Parenthesis
+ format.setForeground(QApplication::style()->standardPalette().text());
formats[State::PARENTHESIS] = format;
// String
- format.setForeground(CFG_UI.Colors.SqlEditorStringFg.get());
+ format.setForeground(STYLE->extendedPalette().editorString());
format.setFontWeight(QFont::Normal);
- format.setFontItalic(false);
+ format.setFontItalic(true);
formats[State::STRING] = format;
// Keyword
- format.setForeground(CFG_UI.Colors.SqlEditorKeywordFg.get());
- format.setFontWeight(QFont::Bold);
+ format.setForeground(QApplication::style()->standardPalette().windowText());
+ format.setFontWeight(QFont::ExtraBold);
format.setFontItalic(false);
formats[State::KEYWORD] = format;
// BindParam
- format.setForeground(CFG_UI.Colors.SqlEditorBindParamFg.get());
+ format.setForeground(QApplication::style()->standardPalette().linkVisited());
format.setFontWeight(QFont::Normal);
format.setFontItalic(false);
formats[State::BIND_PARAM] = format;
// Blob
- format.setForeground(CFG_UI.Colors.SqlEditorBlobFg.get());
+ format.setForeground(QApplication::style()->standardPalette().text());
format.setFontWeight(QFont::Normal);
format.setFontItalic(false);
formats[State::BLOB] = format;
// Comment
- format.setForeground(CFG_UI.Colors.SqlEditorCommentFg.get());
+ format.setForeground(QApplication::style()->standardPalette().dark());
format.setFontWeight(QFont::Normal);
format.setFontItalic(true);
formats[State::COMMENT] = format;
// Number
- format.setForeground(CFG_UI.Colors.SqlEditorNumberFg.get());
+ format.setForeground(QApplication::style()->standardPalette().text());
format.setFontWeight(QFont::Normal);
format.setFontItalic(false);
formats[State::NUMBER] = format;
@@ -139,7 +137,7 @@ void SqliteSyntaxHighlighter::highlightBlock(const QString &text)
idxModifier += statePrefix.size();
}
- Lexer lexer(sqliteVersion == 2 ? Dialect::Sqlite2 : Dialect::Sqlite3);
+ Lexer lexer;
lexer.setTolerantMode(true);
lexer.prepare(statePrefix+text);
@@ -157,22 +155,25 @@ void SqliteSyntaxHighlighter::highlightBlock(const QString &text)
TextBlockData* data = new TextBlockData();
int errorStart = -1;
TokenPtr token = lexer.getToken();
+ TokenPtr aheadToken;
while (token)
{
- if (handleToken(token, idxModifier, errorStart, data, prevData))
+ aheadToken = lexer.getToken();
+
+ if (handleToken(token, aheadToken, idxModifier, errorStart, data, prevData))
errorStart = token->start + currentBlock().position();
if (data->getEndsWithQuerySeparator())
errorStart = -1;
handleParenthesis(token, data);
- token = lexer.getToken();
+ token = aheadToken;
}
setCurrentBlockUserData(data);
}
-bool SqliteSyntaxHighlighter::handleToken(TokenPtr token, qint32 idxModifier, int errorStart, TextBlockData* currBlockData,
+bool SqliteSyntaxHighlighter::handleToken(TokenPtr token, TokenPtr aheadToken, qint32 idxModifier, int errorStart, TextBlockData* currBlockData,
TextBlockData* previousBlockData)
{
qint64 start = token->start - idxModifier;
@@ -186,6 +187,9 @@ bool SqliteSyntaxHighlighter::handleToken(TokenPtr token, qint32 idxModifier, in
if (createTriggerContext && token->type == Token::OTHER && (token->value.toLower() == "old" || token->value.toLower() == "new"))
token->type = Token::KEYWORD;
+ if (aheadToken && aheadToken->type == Token::PAR_LEFT && token->type == Token::KEYWORD && isSoftKeyword(token->value))
+ token->type = Token::OTHER;
+
bool limitedDamage = false;
bool querySeparator = (token->type == Token::Type::OPERATOR && token->value == ";");
bool error = isError(start, lgt, &limitedDamage);
@@ -203,7 +207,7 @@ bool SqliteSyntaxHighlighter::handleToken(TokenPtr token, qint32 idxModifier, in
);
bool fatalError = (error && !limitedDamage) || wasError;
- QTextCharFormat format;
+ QTextCharFormat format = formats[State::STANDARD];
// Applying valid object format.
applyValidObjectFormat(format, valid, error, wasError);
@@ -245,7 +249,7 @@ void SqliteSyntaxHighlighter::applyValidObjectFormat(QTextCharFormat& format, bo
if (isError || wasError || !isValid)
return;
- format.setForeground(CFG_UI.Colors.SqlEditorValidObject.get());
+ format.setForeground(QApplication::style()->standardPalette().link());
if (objectLinksEnabled)
format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.h b/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.h
index 48649d4..b17c45f 100644
--- a/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.h
+++ b/SQLiteStudio3/guiSQLiteStudio/sqlitesyntaxhighlighter.h
@@ -54,7 +54,6 @@ class GUI_API_EXPORT SqliteSyntaxHighlighter : public QSyntaxHighlighter
explicit SqliteSyntaxHighlighter(QTextDocument *parent);
- void setSqliteVersion(int version);
void setFormat(State state, QTextCharFormat format);
QTextCharFormat getFormat(State state) const;
@@ -123,7 +122,7 @@ class GUI_API_EXPORT SqliteSyntaxHighlighter : public QSyntaxHighlighter
* @param idxModifier Modifier for text highlighting in case of previous state defined by multi-character token. See getPreviousStatePrefix() for details.
* @return true if the token is being marked as invalid (syntax error).
*/
- bool handleToken(TokenPtr token, qint32 idxModifier, int errorStart, TextBlockData* currBlockData, TextBlockData* previousBlockData);
+ bool handleToken(TokenPtr token, TokenPtr aheadToken, qint32 idxModifier, int errorStart, TextBlockData* currBlockData, TextBlockData* previousBlockData);
bool isError(int start, int lgt, bool* limitedDamage);
bool isValid(int start, int lgt);
@@ -156,7 +155,6 @@ class GUI_API_EXPORT SqliteSyntaxHighlighter : public QSyntaxHighlighter
void handleParenthesis(TokenPtr token, TextBlockData* data);
static const int regulartTextBlockState = static_cast<int>(TextBlockState::REGULAR);
- int sqliteVersion = 3;
QHash<State,QTextCharFormat> formats;
QHash<Token::Type,State> tokenTypeMapping;
QList<Error> errors;
diff --git a/SQLiteStudio3/guiSQLiteStudio/sqlview.cpp b/SQLiteStudio3/guiSQLiteStudio/sqlview.cpp
index e65a60f..6c38915 100644
--- a/SQLiteStudio3/guiSQLiteStudio/sqlview.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/sqlview.cpp
@@ -11,11 +11,6 @@ SqlView::SqlView(QWidget *parent) :
setReadOnly(true);
}
-void SqlView::setSqliteVersion(int version)
-{
- highlighter->setSqliteVersion(version);
-}
-
void SqlView::setTextBackgroundColor(int from, int to, const QColor& color)
{
bool wasRo = false;
diff --git a/SQLiteStudio3/guiSQLiteStudio/sqlview.h b/SQLiteStudio3/guiSQLiteStudio/sqlview.h
index 7358a43..85e5b54 100644
--- a/SQLiteStudio3/guiSQLiteStudio/sqlview.h
+++ b/SQLiteStudio3/guiSQLiteStudio/sqlview.h
@@ -12,7 +12,6 @@ class GUI_API_EXPORT SqlView : public QTextEdit
public:
explicit SqlView(QWidget *parent = 0);
- void setSqliteVersion(int version);
void setTextBackgroundColor(int from, int to, const QColor& color);
private:
diff --git a/SQLiteStudio3/guiSQLiteStudio/statusfield.cpp b/SQLiteStudio3/guiSQLiteStudio/statusfield.cpp
index 571fcba..11eed59 100644
--- a/SQLiteStudio3/guiSQLiteStudio/statusfield.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/statusfield.cpp
@@ -13,6 +13,8 @@
#include <QVariantAnimation>
#include <QDebug>
+const QString StatusField::colorTpl = "QLabel {color: %1}";
+
StatusField::StatusField(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::StatusField)
@@ -57,20 +59,20 @@ void StatusField::changeEvent(QEvent *e)
void StatusField::info(const QString &text)
{
- addEntry(ICONS.STATUS_INFO, text, CFG_UI.Colors.StatusFieldInfoFg.get());
+ addEntry(ICONS.STATUS_INFO, text, style()->standardPalette().text().color(), INFO);
}
void StatusField::warn(const QString &text)
{
- addEntry(ICONS.STATUS_WARNING, text, CFG_UI.Colors.StatusFieldWarnFg.get());
+ addEntry(ICONS.STATUS_WARNING, text, style()->standardPalette().text().color(), WARN);
}
void StatusField::error(const QString &text)
{
- addEntry(ICONS.STATUS_ERROR, text, CFG_UI.Colors.StatusFieldErrorFg.get());
+ addEntry(ICONS.STATUS_ERROR, text, QColor(Qt::red), ERROR);
}
-void StatusField::addEntry(const QIcon &icon, const QString &text, const QColor& color)
+void StatusField::addEntry(const QIcon &icon, const QString &text, const QColor& color, EntryRole role)
{
int row = ui->tableWidget->rowCount();
ui->tableWidget->setRowCount(row+1);
@@ -86,6 +88,7 @@ void StatusField::addEntry(const QIcon &icon, const QString &text, const QColor&
item = new QTableWidgetItem();
item->setIcon(icon);
+ item->setData(Qt::UserRole, role);
ui->tableWidget->setItem(row, 0, item);
itemsCreated << item;
@@ -95,16 +98,17 @@ void StatusField::addEntry(const QIcon &icon, const QString &text, const QColor&
item = new QTableWidgetItem(timeStr);
item->setForeground(QBrush(color));
item->setFont(font);
+ item->setData(Qt::UserRole, role);
ui->tableWidget->setItem(row, 1, item);
itemsCreated << item;
item = new QTableWidgetItem();
item->setForeground(QBrush(color));
item->setFont(font);
+ item->setData(Qt::UserRole, role);
ui->tableWidget->setItem(row, 2, item);
itemsCreated << item;
- static_qstring(colorTpl, "QLabel {color: %1}");
// While QLabel does detect if the text is rich automatically, we don't want to use qlabel for plain text,
// because it's not wrapped correctly if the text is longer.
if (text.contains("<"))
@@ -117,6 +121,8 @@ void StatusField::addEntry(const QIcon &icon, const QString &text, const QColor&
label->setStyleSheet(colorTpl.arg(color.name()));
connect(label, SIGNAL(linkActivated(QString)), this, SIGNAL(linkActivated(QString)));
ui->tableWidget->setCellWidget(row, 2, label);
+ ui->tableWidget->item(row, 2)->setData(Qt::UserRole, role);
+ ui->tableWidget->item(row, 2)->setData(Qt::UserRole+1, true);
}
else
{
@@ -127,34 +133,38 @@ void StatusField::addEntry(const QIcon &icon, const QString &text, const QColor&
setVisible(true);
ui->tableWidget->scrollToBottom();
- if (isVisible() && !noFlashing)
- flashItems(itemsCreated, color);
}
-void StatusField::flashItems(const QList<QTableWidgetItem*>& items, const QColor& color)
+void StatusField::refreshColors()
{
- QColor alphaColor = color;
- alphaColor.setAlpha(0);
-
- QColor finalColor = color;
- finalColor.setAlpha(150);
-
- QVariantAnimation* anim = new QVariantAnimation();
- anim->setDuration(500);
- anim->setEasingCurve(QEasingCurve::OutQuad);
- anim->setStartValue(finalColor);
- anim->setEndValue(alphaColor);
-
- itemAnimations << anim;
- connect(anim, &QObject::destroyed, [this, anim]() {itemAnimations.removeOne(anim);});
-
- connect(anim, &QVariantAnimation::valueChanged, [items](const QVariant& value)
- {
- for (QTableWidgetItem* item : items)
- item->setBackground(value.value<QColor>());
- });
-
- anim->start(QAbstractAnimation::DeleteWhenStopped);
+ const QColor stdColor = style()->standardPalette().text().color();
+ const QColor errColor = QColor(Qt::red);
+ EntryRole role;
+ bool hasLabel;
+ QLabel* label = nullptr;
+ for (QTableWidgetItem* item : ui->tableWidget->findItems("", Qt::MatchContains)) {
+ role = (EntryRole)item->data(Qt::UserRole).toInt();
+
+ hasLabel = item->data(Qt::UserRole+1).toBool();
+ label = hasLabel ? dynamic_cast<QLabel*>(ui->tableWidget->cellWidget(item->row(), item->column())) : nullptr;
+
+ switch (role)
+ {
+ case INFO:
+ case WARN:
+ item->setForeground(stdColor);
+ if (label != nullptr)
+ label->setStyleSheet(colorTpl.arg(stdColor.name()));
+
+ break;
+ case ERROR:
+ item->setForeground(errColor);
+ if (label != nullptr)
+ label->setStyleSheet(colorTpl.arg(stdColor.name()));
+
+ break;
+ }
+ }
}
void StatusField::setupMenu()
@@ -177,7 +187,6 @@ void StatusField::setupMenu()
void StatusField::readRecentMessages()
{
- noFlashing = true;
for (const QString& msg : NotifyManager::getInstance()->getRecentInfos())
info(msg);
@@ -186,8 +195,6 @@ void StatusField::readRecentMessages()
for (const QString& msg : NotifyManager::getInstance()->getRecentErrors())
error(msg);
-
- noFlashing = false;
}
void StatusField::customContextMenuRequested(const QPoint &pos)
diff --git a/SQLiteStudio3/guiSQLiteStudio/statusfield.h b/SQLiteStudio3/guiSQLiteStudio/statusfield.h
index ac07f51..6f9ad22 100644
--- a/SQLiteStudio3/guiSQLiteStudio/statusfield.h
+++ b/SQLiteStudio3/guiSQLiteStudio/statusfield.h
@@ -27,7 +27,14 @@ class GUI_API_EXPORT StatusField : public QDockWidget
void changeEvent(QEvent *e);
private:
- void addEntry(const QIcon& icon, const QString& text, const QColor &color);
+ enum EntryRole
+ {
+ INFO,
+ WARN,
+ ERROR
+ };
+
+ void addEntry(const QIcon& icon, const QString& text, const QColor& color, EntryRole role);
void flashItems(const QList<QTableWidgetItem*>& items, const QColor& color);
void setupMenu();
void readRecentMessages();
@@ -37,11 +44,12 @@ class GUI_API_EXPORT StatusField : public QDockWidget
QAction* copyAction = nullptr;
QAction* clearAction = nullptr;
QList<QAbstractAnimation*> itemAnimations;
- bool noFlashing = false;
static const int timeStampColumnWidth = 70;
static const int itemCountLimit = 30;
+ static const int itemRole = Qt::UserRole;
static constexpr const char* timeStampFormat = "hh:mm:ss";
+ static const QString colorTpl;
private slots:
void customContextMenuRequested(const QPoint& pos);
@@ -51,6 +59,9 @@ class GUI_API_EXPORT StatusField : public QDockWidget
void reset();
void fontChanged(const QVariant& variant);
+ public slots:
+ void refreshColors();
+
signals:
void linkActivated(const QString& link);
};
diff --git a/SQLiteStudio3/guiSQLiteStudio/style.cpp b/SQLiteStudio3/guiSQLiteStudio/style.cpp
new file mode 100644
index 0000000..525a832
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/style.cpp
@@ -0,0 +1,48 @@
+#include "style.h"
+#include "themetuner.h"
+#include "common/global.h"
+#include "mainwindow.h"
+#include <QApplication>
+#include <QToolTip>
+
+Style* Style::instance = nullptr;
+
+Style* Style::getInstance()
+{
+ if (instance == nullptr)
+ instance = new Style(QApplication::style());
+
+ return instance;
+}
+
+const ExtendedPalette& Style::extendedPalette() const
+{
+ return extPalette;
+}
+
+void Style::setStyle(QStyle *style, const QString &styleName)
+{
+ setBaseStyle(style);
+
+ QApplication::setPalette(initialPalette); // reset palette, cause styles don't provide
+ // full palette when changed in runtime (i.e. windowsvista)
+ QApplication::setStyle(this);
+ QApplication::setPalette(standardPalette());
+ THEME_TUNER->tuneTheme(styleName);
+ QToolTip::setPalette(standardPalette());
+
+ extPalette.styleChanged(this, styleName);
+
+ MAINWINDOW->getMdiArea()->setBackground(extPalette.mdiAreaBase());
+}
+
+QString Style::name() const
+{
+ return baseStyle()->objectName();
+}
+
+Style::Style(QStyle *style)
+ : QProxyStyle(style)
+{
+ initialPalette = style->standardPalette();
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/style.h b/SQLiteStudio3/guiSQLiteStudio/style.h
new file mode 100644
index 0000000..ccb5e9e
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/style.h
@@ -0,0 +1,29 @@
+#ifndef STYLE_H
+#define STYLE_H
+
+#include "extendedpalette.h"
+#include <QPalette>
+#include <QProxyStyle>
+
+
+class Style : public QProxyStyle
+{
+ public:
+ static Style* getInstance();
+
+ const ExtendedPalette &extendedPalette() const;
+ void setStyle(QStyle* style, const QString& styleName);
+ QString name() const;
+
+ private:
+ static Style* instance;
+
+ Style(QStyle* style);
+
+ ExtendedPalette extPalette;
+ QPalette initialPalette;
+};
+
+#define STYLE Style::getInstance()
+
+#endif // STYLE_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp b/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp
index fd0c338..b209bbc 100644
--- a/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/taskbar.cpp
@@ -204,7 +204,7 @@ bool TaskBar::handleMouseMoveEvent(QMouseEvent* event)
drag->setMimeData(generateMimeData());
dragStartIndex = tasks.indexOf(dragStartTask);
- drag->start(Qt::MoveAction);
+ drag->exec(Qt::MoveAction);
return true;
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/themetuner.cpp b/SQLiteStudio3/guiSQLiteStudio/themetuner.cpp
index e48865f..89092d6 100644
--- a/SQLiteStudio3/guiSQLiteStudio/themetuner.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/themetuner.cpp
@@ -2,10 +2,12 @@
#include "uiconfig.h"
#include "mainwindow.h"
#include "uiconfig.h"
+#include "style.h"
#include <QApplication>
#include <QFile>
#include <QStyle>
#include <QDebug>
+#include <QWizard>
ThemeTuner* ThemeTuner::instance = nullptr;
@@ -22,7 +24,7 @@ void ThemeTuner::tuneTheme(const QString& themeName)
void ThemeTuner::tuneCurrentTheme()
{
- tuneTheme(QApplication::style()->objectName());
+ tuneTheme(STYLE->name());
}
void ThemeTuner::manageCompactLayout(QWidget* w)
@@ -49,6 +51,23 @@ QString ThemeTuner::getDefaultCss(const QString& themeName) const
return css;
}
+void ThemeTuner::darkThemeFix(QWizard* wizard)
+{
+ QString themeName = STYLE->name();
+ if (qwizardThemeTuneRequired.contains(themeName))
+ wizard->setWizardStyle(QWizard::ClassicStyle);
+}
+
+void ThemeTuner::registerQWizardThemeTuneRequired(const QString& styleName)
+{
+ qwizardThemeTuneRequired << styleName;
+}
+
+void ThemeTuner::deregisterQWizardThemeTuneRequired(const QString& styleName)
+{
+ qwizardThemeTuneRequired.removeOne(styleName);
+}
+
ThemeTuner* ThemeTuner::getInstance()
{
if (!instance)
diff --git a/SQLiteStudio3/guiSQLiteStudio/themetuner.h b/SQLiteStudio3/guiSQLiteStudio/themetuner.h
index 9804464..805ca94 100644
--- a/SQLiteStudio3/guiSQLiteStudio/themetuner.h
+++ b/SQLiteStudio3/guiSQLiteStudio/themetuner.h
@@ -1,20 +1,29 @@
#ifndef THEMETUNER_H
#define THEMETUNER_H
+#include "guiSQLiteStudio_global.h"
+#include <functional>
#include <QObject>
#include <QString>
#include <QHash>
-class ThemeTuner : public QObject
+class QWizard;
+
+class GUI_API_EXPORT ThemeTuner : public QObject
{
Q_OBJECT
public:
+ typedef std::function<void(const QString&, QWizard*)> QWizardThemeTuner;
+
void tuneTheme(const QString& themeName);
void tuneCurrentTheme();
void manageCompactLayout(QWidget* w);
void manageCompactLayout(QList<QWidget*> wList);
QString getDefaultCss(const QString& themeName = QString()) const;
+ void darkThemeFix(QWizard* wizard);
+ void registerQWizardThemeTuneRequired(const QString& styleName);
+ void deregisterQWizardThemeTuneRequired(const QString& styleName);
static ThemeTuner* getInstance();
static void cleanUp();
@@ -30,6 +39,7 @@ class ThemeTuner : public QObject
QString defaultGeneralCss;
QHash<QString, QString> defaultPerStyleCss;
QList<QWidget*> widgetsForCompactLayout;
+ QStringList qwizardThemeTuneRequired;
static ThemeTuner* instance;
@@ -40,4 +50,6 @@ class ThemeTuner : public QObject
#define THEME_TUNER ThemeTuner::getInstance()
+
+
#endif // THEMETUNER_H
diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts
index ebd49cf..3962775 100644
--- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts
+++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_ru.ts
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
-<TS version="2.1" language="ru_RU">
+<TS version="2.0" language="ru_RU">
<context>
<name>AboutDialog</name>
<message>
@@ -15,7 +15,7 @@
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;SQLiteStudio v%1&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Free, open-source, cross-platform SQLite database manager.&lt;br/&gt;&lt;a href=&quot;http://sqlitestudio.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://sqlitestudio.pl&lt;/span&gt;&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;%2&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Author and active maintainer:&lt;br/&gt;SalSoft (&lt;a href=&quot;http://salsoft.com.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://salsoft.com.pl&lt;/span&gt;&lt;/a&gt;)&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="vanished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;SQLiteStudio v%1&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Бесплатный кроссплатформенный менеджер баз данных SQLite с открытым исходным кодом.&lt;br/&gt;&lt;a href=&quot;http://sqlitestudio.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://sqlitestudio.pl&lt;/span&gt;&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;%2&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Автор и активный разработчик:&lt;br/&gt;SalSoft (&lt;a href=&quot;http://salsoft.com.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://salsoft.com.pl&lt;/span&gt;&lt;/a&gt;)&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;SQLiteStudio v%1&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Бесплатный кроссплатформенный менеджер баз данных SQLite с открытым исходным кодом.&lt;br/&gt;&lt;a href=&quot;http://sqlitestudio.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://sqlitestudio.pl&lt;/span&gt;&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;%2&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Автор и активный разработчик:&lt;br/&gt;SalSoft (&lt;a href=&quot;http://salsoft.com.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://salsoft.com.pl&lt;/span&gt;&lt;/a&gt;)&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../dialogs/aboutdialog.ui" line="41"/>
@@ -60,7 +60,7 @@
<message>
<location filename="../dialogs/aboutdialog.ui" line="30"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;SQLiteStudio v%1&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Free, open-source, cross-platform SQLite database manager.&lt;br/&gt;&lt;a href=&quot;https://sqlitestudio.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://sqlitestudio.pl&lt;/span&gt;&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;%2&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Author and active maintainer:&lt;br/&gt;SalSoft (&lt;a href=&quot;https://salsoft.com.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://salsoft.com.pl&lt;/span&gt;&lt;/a&gt;)&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;SQLiteStudio вер.%1&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Бесплатный кроссплатформенный менеджер баз данных SQLite с открытым исходным кодом.&lt;br/&gt;&lt;a href=&quot;https://sqlitestudio.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://sqlitestudio.pl&lt;/span&gt;&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;%2&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Автор и активный разработчик:&lt;br/&gt;SalSoft (&lt;a href=&quot;https://salsoft.com.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://salsoft.com.pl&lt;/span&gt;&lt;/a&gt;)&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../dialogs/aboutdialog.ui" line="148"/>
@@ -98,217 +98,217 @@
<message>
<location filename="../dialogs/bindparamsdialog.ui" line="17"/>
<source>Query parameters</source>
- <translation type="unfinished"></translation>
+ <translation>Параметры запроса</translation>
</message>
<message>
<location filename="../dialogs/bindparamsdialog.ui" line="26"/>
<source>Please provide values for query parameters</source>
- <translation type="unfinished"></translation>
+ <translation>Пожалуйста укажите значения для параметров запроса</translation>
</message>
</context>
<context>
<name>BugDialog</name>
<message>
<source>Bugs and ideas</source>
- <translation type="vanished">Ошибки и предложения</translation>
+ <translation>Ошибки и предложения</translation>
</message>
<message>
<source>Reporter</source>
- <translation type="vanished">Отправитель</translation>
+ <translation>Отправитель</translation>
</message>
<message>
<source>E-mail address</source>
- <translation type="vanished">Адрес e-mail</translation>
+ <translation>Адрес e-mail</translation>
</message>
<message>
<source>Log in</source>
- <translation type="vanished">Вход</translation>
+ <translation>Вход</translation>
</message>
<message>
<source>Short description</source>
- <translation type="vanished">Краткое описание</translation>
+ <translation>Краткое описание</translation>
</message>
<message>
<source>Detailed description</source>
- <translation type="vanished">Подробное описание</translation>
+ <translation>Подробное описание</translation>
</message>
<message>
<source>Show more details</source>
- <translation type="vanished">Показать дополнительную информацию</translation>
+ <translation>Показать дополнительную информацию</translation>
</message>
<message>
<source>SQLiteStudio version</source>
- <translation type="vanished">Версия SQLiteStudio</translation>
+ <translation>Версия SQLiteStudio</translation>
</message>
<message>
<source>Operating system</source>
- <translation type="vanished">Операционная система</translation>
+ <translation>Операционная система</translation>
</message>
<message>
<source>Loaded plugins</source>
- <translation type="vanished">Загруженные модули</translation>
+ <translation>Загруженные модули</translation>
</message>
<message>
<source>Send</source>
- <translation type="vanished">Отправить</translation>
+ <translation>Отправить</translation>
</message>
<message>
<source>You can see all your reported bugs and ideas by selecting menu &apos;%1&apos; and then &apos;%2&apos;.</source>
- <translation type="vanished">Вы можете просмотреть все отправленные вами отчёты об ошибках и предложения, выбрав в меню &apos;%1&apos; пункт &apos;%2&apos;.</translation>
+ <translation>Вы можете просмотреть все отправленные вами отчёты об ошибках и предложения, выбрав в меню &apos;%1&apos; пункт &apos;%2&apos;.</translation>
</message>
<message>
<source>A bug report sent successfully.</source>
- <translation type="vanished">Отчёт об ошибке успешно отправлен.</translation>
+ <translation>Отчёт об ошибке успешно отправлен.</translation>
</message>
<message>
<source>An error occurred while sending a bug report: %1
%2</source>
- <translation type="vanished">При отправке отчёта об ошибке возникла проблема: %1
+ <translation>При отправке отчёта об ошибке возникла проблема: %1
%2</translation>
</message>
<message>
<source>You can retry sending. The contents will be restored when you open a report dialog after an error like this.</source>
- <translation type="vanished">Вы можете повторить отправку. После такой ошибки содержимое полей окна отправки отчёта будет восстановлено при повторном открытии.</translation>
+ <translation>Вы можете повторить отправку. После такой ошибки содержимое полей окна отправки отчёта будет восстановлено при повторном открытии.</translation>
</message>
<message>
<source>An idea proposal sent successfully.</source>
- <translation type="vanished">Предложение по улучшению было успешно отправлено.</translation>
+ <translation>Предложение по улучшению было успешно отправлено.</translation>
</message>
<message>
<source>An error occurred while sending an idea proposal: %1
%2</source>
- <translation type="vanished">При отправке предложения по улучшению возникла проблема: %1
+ <translation>При отправке предложения по улучшению возникла проблема: %1
%2</translation>
</message>
<message>
<source>A bug report</source>
- <translation type="vanished">Отчёт об ошибке</translation>
+ <translation>Отчёт об ошибке</translation>
</message>
<message>
<source>Describe problem in few words</source>
- <translation type="vanished">Опишите проблему в нескольких словах</translation>
+ <translation>Опишите проблему в нескольких словах</translation>
</message>
<message>
<source>Describe problem and how to reproduce it</source>
- <translation type="vanished">Опишите проблему и шаги для её воспроизведения</translation>
+ <translation>Опишите проблему и шаги для её воспроизведения</translation>
</message>
<message>
<source>A new feature idea</source>
- <translation type="vanished">Предложение по улучшению функционала</translation>
+ <translation>Предложение по улучшению функционала</translation>
</message>
<message>
<source>A title for your idea</source>
- <translation type="vanished">Название для вашего предложения</translation>
+ <translation>Название для вашего предложения</translation>
</message>
<message>
<source>Describe your idea in more details</source>
- <translation type="vanished">Опишите ваше предложение более подробно</translation>
+ <translation>Опишите ваше предложение более подробно</translation>
</message>
<message>
<source>Reporting as an unregistered user, using e-mail address.</source>
- <translation type="vanished">Отправка от незарегистрированного пользователя, используя адрес e-mail</translation>
+ <translation>Отправка от незарегистрированного пользователя, используя адрес e-mail</translation>
</message>
<message>
<source>Reporting as a registered user.</source>
- <translation type="vanished">Отправка от зарегистрированного пользователя</translation>
+ <translation>Отправка от зарегистрированного пользователя</translation>
</message>
<message>
<source>Log out</source>
- <translation type="vanished">Выход</translation>
+ <translation>Выход</translation>
</message>
<message>
<source>Providing true email address will make it possible to contact you regarding your report. To learn more, press &apos;help&apos; button on the right side.</source>
- <translation type="vanished">Указание действительного адреса e-mail поможет связаться с вами касательно вашего отчёта. Для подробной информации нажмите кнопку Помощь справа.</translation>
+ <translation>Указание действительного адреса e-mail поможет связаться с вами касательно вашего отчёта. Для подробной информации нажмите кнопку Помощь справа.</translation>
</message>
<message>
<source>Enter vaild e-mail address, or log in.</source>
- <translation type="vanished">Введите действительный адрес e-mail либо выполните вход.</translation>
+ <translation>Введите действительный адрес e-mail либо выполните вход.</translation>
</message>
<message>
<source>Short description requires at least 10 characters, but not more than 100. Longer description can be entered in the field below.</source>
- <translation type="vanished">Краткое описание должно содержать от 10 до 100 символов. Более подробное описание можно ввести в поле ниже.</translation>
+ <translation>Краткое описание должно содержать от 10 до 100 символов. Более подробное описание можно ввести в поле ниже.</translation>
</message>
<message>
<source>Long description requires at least 30 characters.</source>
- <translation type="vanished">Детальное описание должно содержать как минимум 30 символов.</translation>
+ <translation>Детальное описание должно содержать как минимум 30 символов.</translation>
</message>
</context>
<context>
<name>BugReportHistoryWindow</name>
<message>
<source>Title</source>
- <translation type="vanished">Заголовок</translation>
+ <translation>Заголовок</translation>
</message>
<message>
<source>Reported at</source>
- <translation type="vanished">Дата отправки</translation>
+ <translation>Дата отправки</translation>
</message>
<message>
<source>URL</source>
- <translation type="vanished">URL</translation>
+ <translation>URL</translation>
</message>
<message>
<source>Reports history</source>
- <translation type="vanished">История отчётов</translation>
+ <translation>История отчётов</translation>
</message>
<message>
<source>Clear reports history</source>
- <translation type="vanished">Очистить историю отчётов</translation>
+ <translation>Очистить историю отчётов</translation>
</message>
<message>
<source>Delete selected entry</source>
- <translation type="vanished">Удалить выбранную запись</translation>
+ <translation>Удалить выбранную запись</translation>
</message>
<message>
<source>Invalid response from server.</source>
- <translation type="vanished">Некорректный ответ сервера.</translation>
+ <translation>Некорректный ответ сервера.</translation>
</message>
</context>
<context>
<name>BugReportLoginDialog</name>
<message>
<source>Log in</source>
- <translation type="vanished">Вход</translation>
+ <translation>Вход</translation>
</message>
<message>
<source>Credentials</source>
- <translation type="vanished">Данные для входа</translation>
+ <translation>Данные для входа</translation>
</message>
<message>
<source>Login:</source>
- <translation type="vanished">Имя пользователя:</translation>
+ <translation>Имя пользователя:</translation>
</message>
<message>
<source>Password:</source>
- <translation type="vanished">Пароль:</translation>
+ <translation>Пароль:</translation>
</message>
<message>
<source>Validation</source>
- <translation type="vanished">Проверка</translation>
+ <translation>Проверка</translation>
</message>
<message>
<source>Validate</source>
- <translation type="vanished">Проверить</translation>
+ <translation>Проверить</translation>
</message>
<message>
<source>Validation result message</source>
- <translation type="vanished">Статус проверки</translation>
+ <translation>Статус проверки</translation>
</message>
<message>
<source>Abort</source>
- <translation type="vanished">Прервать</translation>
+ <translation>Прервать</translation>
</message>
<message>
<source>A login must be at least 2 characters long.</source>
- <translation type="vanished">Имя пользователя должно состоять как минимум из двух символов.</translation>
+ <translation>Имя пользователя должно состоять как минимум из двух символов.</translation>
</message>
<message>
<source>A password must be at least 5 characters long.</source>
- <translation type="vanished">Пароль должен состоять как минимум из пяти символов.</translation>
+ <translation>Пароль должен состоять как минимум из пяти символов.</translation>
</message>
<message>
<source>Valid</source>
- <translation type="vanished">Верно</translation>
+ <translation>Верно</translation>
</message>
</context>
<context>
@@ -400,7 +400,7 @@
</message>
<message>
<source>Collations editor window has uncommited modifications.</source>
- <translation type="vanished">В редакторе сравнений имеются неподтверждённые изменения.</translation>
+ <translation>В редакторе сравнений имеются неподтверждённые изменения.</translation>
</message>
</context>
<context>
@@ -454,16 +454,16 @@
<message>
<location filename="../constraints/columndefaultpanel.cpp" line="78"/>
<source>Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters.</source>
- <translation type="unfinished"></translation>
+ <translation>Некорректное выражение для значения по умолчанию: %1. Если необходимо использовать простую строку как значение, не забудьте поместить её в кавычки.</translation>
</message>
<message>
<location filename="../constraints/columndefaultpanel.cpp" line="89"/>
<source>Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters.</source>
- <translation type="unfinished"></translation>
+ <translation>Некорректное выражение для значения по умолчанию. Если необходимо использовать простую строку как значение, не забудьте поместить её в кавычки.</translation>
</message>
<message>
<source>Invalid default value expression: %1</source>
- <translation type="vanished">Некорректное выражение для значения по умолчанию: %1</translation>
+ <translation>Некорректное выражение для значения по умолчанию: %1</translation>
</message>
<message>
<location filename="../constraints/columndefaultpanel.cpp" line="92"/>
@@ -667,12 +667,12 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/columndialog.cpp" line="389"/>
<source>Cannot use type other than INTEGER if AUTOINCREMENT is enabled in PRIMARY KEY.</source>
- <translation type="unfinished"></translation>
+ <translation>Невозможно использовать тип данных, отличный от INTEGER, если в первичном ключе установлен автоинкремент.</translation>
</message>
<message>
<location filename="../dialogs/columndialog.cpp" line="390"/>
<source>INTEGER type was enforced due to enabled AUTOINCREMENT in PRIMARY KEY.</source>
- <translation type="unfinished"></translation>
+ <translation>В качестве типа данных был принудительно выбран INTEGER, так как в первичном ключе установлен автоинкремент.</translation>
</message>
<message>
<location filename="../dialogs/columndialog.cpp" line="412"/>
@@ -779,7 +779,7 @@ but it&apos;s okay to use it.</source>
<message>
<source>Autoincrement (only for %1 type columns)</source>
<comment>column primary key</comment>
- <translation type="vanished">Автоинкремент (только для столбцов типа %1)</translation>
+ <translation>Автоинкремент (только для столбцов типа %1)</translation>
</message>
</context>
<context>
@@ -998,7 +998,7 @@ but it&apos;s okay to use it.</source>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&amp;lt;p&amp;gt;When editing a cell which used to have NULL value and entering empty string as new value, then this option determinates whether the new value should remain NULL (have this option enabled), or should it be overwritten with empty string value (have this option disabled).&amp;lt;/p&amp;gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="vanished">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&amp;lt;p&amp;gt;Если редактируется ячейка, содержащая NULL, и вводится пустая строка в качестве значения, то эта опция определяет, останется ли в качестве значения ячейки NULL (если опция активирована), или значение будет заменено на пустую строку (если эта опция деактивирована).&amp;lt;/p&amp;gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&amp;lt;p&amp;gt;Если редактируется ячейка, содержащая NULL, и вводится пустая строка в качестве значения, то эта опция определяет, останется ли в качестве значения ячейки NULL (если опция активирована), или значение будет заменено на пустую строку (если эта опция деактивирована).&amp;lt;/p&amp;gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="518"/>
@@ -1007,7 +1007,7 @@ but it&apos;s okay to use it.</source>
</message>
<message>
<source>General.KeepNullWhenEmptyValue</source>
- <translation type="vanished">General.KeepNullWhenEmptyValue</translation>
+ <translation>General.KeepNullWhenEmptyValue</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="502"/>
@@ -1105,7 +1105,7 @@ but it&apos;s okay to use it.</source>
</message>
<message>
<source>Don&apos;t show DDL preview dialog when commiting schema changes</source>
- <translation type="vanished">Не показывать диалог предпросмотра DDL при подтверждении изменений схемы</translation>
+ <translation>Не показывать диалог предпросмотра DDL при подтверждении изменений схемы</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="831"/>
@@ -1288,12 +1288,12 @@ but it&apos;s okay to use it.</source>
<location filename="../dialogs/configdialog.ui" line="424"/>
<location filename="../dialogs/configdialog.ui" line="434"/>
<source>&lt;p&gt;Maximum number of configurations of Populate Table dialog stored in configuration. Value of 100 should be sufficient.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;Макисмальное количество конфигураций окна Заполнения таблицы, сохраняемых в конфигурации программы. 100 конфигураций должно хватить.&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="427"/>
<source>Number of memorized table populating configurations</source>
- <translation type="unfinished"></translation>
+ <translation>Количество запоминаемых конфигураций заполнения таблицы</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="515"/>
@@ -1347,12 +1347,12 @@ but it&apos;s okay to use it.</source>
<location filename="../dialogs/configdialog.ui" line="866"/>
<location filename="../dialogs/configdialog.ui" line="892"/>
<source>&lt;p&gt;Maximum number of query parameters (:param, @param, $param, ?) stored in history. When you re-use parameter with the same name/position, SQLiteStudio will pre-initialize it with most recent memorized value (you will still be able to change it). Value of 1000 should be sufficient.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;Максимальное количество параметров запроса (:param, @param, $param, ?), сохраняемых в истории. Когда вы повторно используете параметр с тем же именем/расположением, SQLiteStudio преварительно инициализирует его последним запомненным значением (которое затем можно изменить). 1000 параметров должно хватить.&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="895"/>
<source>Number of memorized query parameters</source>
- <translation type="unfinished"></translation>
+ <translation>Количество запоминаемых параметров запроса</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1132"/>
@@ -1526,15 +1526,15 @@ but it&apos;s okay to use it.</source>
</message>
<message>
<source>&lt;p&gt;Any data changes will be outlined with this color, until they&apos;re commited to the database.&lt;/p&gt;</source>
- <translation type="vanished">&lt;p&gt;Все изменения данных будут обрамлены этим цветом, пока не будут записаны в базу данных.&lt;/p&gt;</translation>
+ <translation>&lt;p&gt;Все изменения данных будут обрамлены этим цветом, пока не будут записаны в базу данных.&lt;/p&gt;</translation>
</message>
<message>
<source>Uncommited data outline color</source>
- <translation type="vanished">Цвет обрамления неподтверждённых изменений</translation>
+ <translation>Цвет обрамления неподтверждённых изменений</translation>
</message>
<message>
<source>&lt;p&gt;In case of error while commiting data changes, the problematic cell will be outlined with this color.&lt;/p&gt;</source>
- <translation type="vanished">&lt;p&gt;В случае ошибки при подтверждении изменений данных, этим цветом будут обрамлены проблемные ячейки.&lt;/p&gt;</translation>
+ <translation>&lt;p&gt;В случае ошибки при подтверждении изменений данных, этим цветом будут обрамлены проблемные ячейки.&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="2027"/>
@@ -1870,18 +1870,18 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dataview.cpp" line="947"/>
<source>Filter</source>
- <translation type="unfinished"></translation>
+ <translation>Фильтр</translation>
</message>
<message>
<location filename="../dataview.cpp" line="950"/>
<source>Hit Enter key or press &quot;Apply filter&quot; button on toolbar to apply new value.</source>
- <translation type="unfinished"></translation>
+ <translation>Нажмите Enter или кнопку &quot;Применить фильтр&quot; на панели инструментов чтобы применить новое значение</translation>
</message>
<message>
<location filename="../dataview.cpp" line="996"/>
<source>Show filter inputs per column</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation>Показывать поле ввода для фильтра в каждом столбце</translation>
</message>
<message>
<location filename="../dataview.cpp" line="1000"/>
@@ -2091,7 +2091,7 @@ Browsing other pages will be possible after the row counting is done.</source>
</message>
<message>
<source>Generate automatically</source>
- <translation type="vanished">Сгенерировать автоматически</translation>
+ <translation>Сгенерировать автоматически</translation>
</message>
<message>
<location filename="../dialogs/dbdialog.ui" line="91"/>
@@ -2138,7 +2138,7 @@ Browsing other pages will be possible after the row counting is done.</source>
</message>
<message>
<source>Generate name basing on file path</source>
- <translation type="vanished">Генерировать имя на основе пути к файлу</translation>
+ <translation>Генерировать имя на основе пути к файлу</translation>
</message>
<message>
<source>Permanent</source>
@@ -2177,11 +2177,11 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dialogs/dbdialog.cpp" line="484"/>
<source>&lt;p&gt;Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;Автоматическая генерация имени отключена, так как имя было задано вручную. Для автоматической генерации необходимо удалить содержимое из поля имени.&lt;/p&gt;</translation>
</message>
<message>
<source>&lt;p&gt;Automatic name generation was disabled, becuase the name was edited manually. To restore automatic generation please erase contents of the name field.&lt;/p&gt;</source>
- <translation type="vanished">&lt;p&gt;Автоматическая генерация имени отключена, так как имя было задано вручную. Для автоматической генерации необходимо удалить содержимое из поля имени.&lt;/p&gt;</translation>
+ <translation>&lt;p&gt;Автоматическая генерация имени отключена, так как имя было задано вручную. Для автоматической генерации необходимо удалить содержимое из поля имени.&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/dbdialog.cpp" line="493"/>
@@ -2200,7 +2200,7 @@ Browsing other pages will be possible after the row counting is done.</source>
</message>
<message>
<source>Auto-generated</source>
- <translation type="vanished">Автоматически сгенерировано</translation>
+ <translation>Автоматически сгенерировано</translation>
</message>
<message>
<source>The name will be auto-generated</source>
@@ -2208,7 +2208,7 @@ Browsing other pages will be possible after the row counting is done.</source>
</message>
<message>
<source>Type the name</source>
- <translation type="vanished">Введите имя</translation>
+ <translation>Введите имя</translation>
</message>
</context>
<context>
@@ -2326,23 +2326,23 @@ Browsing other pages will be possible after the row counting is done.</source>
</message>
<message>
<source>Add a database</source>
- <translation type="vanished">Добавить базу данных</translation>
+ <translation>Добавить базу данных</translation>
</message>
<message>
<source>Edit the database</source>
- <translation type="vanished">Редактировать базу данных</translation>
+ <translation>Редактировать базу данных</translation>
</message>
<message>
<source>Remove the database</source>
- <translation type="vanished">Удалить базу данных</translation>
+ <translation>Удалить базу данных</translation>
</message>
<message>
<source>Connect to the database</source>
- <translation type="vanished">Подключиться к базе данных</translation>
+ <translation>Подключиться к базе данных</translation>
</message>
<message>
<source>Disconnect from the database</source>
- <translation type="vanished">Отключиться от базы данных</translation>
+ <translation>Отключиться от базы данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="145"/>
@@ -2351,31 +2351,31 @@ Browsing other pages will be possible after the row counting is done.</source>
</message>
<message>
<source>Export the database</source>
- <translation type="vanished">Экспортировать базу данных</translation>
+ <translation>Экспортировать базу данных</translation>
</message>
<message>
<source>Convert database type</source>
- <translation type="vanished">Сконвертировать тип базы данных</translation>
+ <translation>Измениить тип базы данных</translation>
</message>
<message>
<source>Vacuum</source>
- <translation type="vanished">Выполнить VACUUM</translation>
+ <translation>Выполнить VACUUM</translation>
</message>
<message>
<source>Integrity check</source>
- <translation type="vanished">Проверить целостность</translation>
+ <translation>Проверить целостность</translation>
</message>
<message>
<source>Create a table</source>
- <translation type="vanished">Создать таблицу</translation>
+ <translation>Создать таблицу</translation>
</message>
<message>
<source>Edit the table</source>
- <translation type="vanished">Редактировать таблицу</translation>
+ <translation>Редактировать таблицу</translation>
</message>
<message>
<source>Delete the table</source>
- <translation type="vanished">Удалить таблицу</translation>
+ <translation>Удалить таблицу</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="153"/>
@@ -2404,39 +2404,39 @@ Browsing other pages will be possible after the row counting is done.</source>
</message>
<message>
<source>Create an index</source>
- <translation type="vanished">Создать индекс</translation>
+ <translation>Создать индекс</translation>
</message>
<message>
<source>Edit the index</source>
- <translation type="vanished">Редактировать индекс</translation>
+ <translation>Редактировать индекс</translation>
</message>
<message>
<source>Delete the index</source>
- <translation type="vanished">Удалить индекс</translation>
+ <translation>Удалить индекс</translation>
</message>
<message>
<source>Create a trigger</source>
- <translation type="vanished">Создать триггер</translation>
+ <translation>Создать триггер</translation>
</message>
<message>
<source>Edit the trigger</source>
- <translation type="vanished">Редактировать триггер</translation>
+ <translation>Редактировать триггер</translation>
</message>
<message>
<source>Delete the trigger</source>
- <translation type="vanished">Удалить триггер</translation>
+ <translation>Удалить триггер</translation>
</message>
<message>
<source>Create a view</source>
- <translation type="vanished">Создать представление</translation>
+ <translation>Создать представление</translation>
</message>
<message>
<source>Edit the view</source>
- <translation type="vanished">Редактировать представление</translation>
+ <translation>Редактировать представление</translation>
</message>
<message>
<source>Delete the view</source>
- <translation type="vanished">Удалить представление</translation>
+ <translation>Удалить представление</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="167"/>
@@ -2465,131 +2465,131 @@ Browsing other pages will be possible after the row counting is done.</source>
</message>
<message>
<source>Refresh all database schemas</source>
- <translation type="vanished">Обновить структуры всех баз данных</translation>
+ <translation>Обновить структуры всех баз данных</translation>
</message>
<message>
<source>Refresh selected database schema</source>
- <translation type="vanished">Обновить структуру выбранной базы данных</translation>
+ <translation>Обновить структуру выбранной базы данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="101"/>
<source>Execution from file cancelled. Any queries executed so far have been rolled back.</source>
- <translation type="unfinished"></translation>
+ <translation>Выполнение запросов из файла отменено. Все выполненные ранее из него запросы откачены.</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="140"/>
<source>&amp;Add a database</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Добавить базу данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="141"/>
<source>&amp;Edit the database</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Редактировать базу данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="142"/>
<source>&amp;Remove the database</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Удалить базу данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="143"/>
<source>&amp;Connect to the database</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Подключиться к базе данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="144"/>
<source>&amp;Disconnect from the database</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Отключиться от базы данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="146"/>
<source>&amp;Export the database</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Экспортировать базу данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="147"/>
<source>Con&amp;vert database type</source>
- <translation type="unfinished"></translation>
+ <translation>И&amp;зменить тип базы данных</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="148"/>
<source>Vac&amp;uum</source>
- <translation type="unfinished"></translation>
+ <translation>Оп&amp;ерация VACUUM</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="149"/>
<source>&amp;Integrity check</source>
- <translation type="unfinished"></translation>
+ <translation>Проверить &amp;целостность</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="150"/>
<source>Create a &amp;table</source>
- <translation type="unfinished"></translation>
+ <translation>Создать &amp;таблицу</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="151"/>
<source>Edit the t&amp;able</source>
- <translation type="unfinished"></translation>
+ <translation>Редактировать т&amp;аблицу</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="152"/>
<source>Delete the ta&amp;ble</source>
- <translation type="unfinished"></translation>
+ <translation>Удалить та&amp;блицу</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="158"/>
<source>Create an &amp;index</source>
- <translation type="unfinished"></translation>
+ <translation>Создать &amp;индекс</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="159"/>
<source>Edit the i&amp;ndex</source>
- <translation type="unfinished"></translation>
+ <translation>Редактировать и&amp;ндекс</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="160"/>
<source>Delete the in&amp;dex</source>
- <translation type="unfinished"></translation>
+ <translation>Удалить инде&amp;кс</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="161"/>
<source>Create a trig&amp;ger</source>
- <translation type="unfinished"></translation>
+ <translation>Создать три&amp;ггер</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="162"/>
<source>Edit the trigg&amp;er</source>
- <translation type="unfinished"></translation>
+ <translation>Редактиро&amp;вать триггер</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="163"/>
<source>Delete the trigge&amp;r</source>
- <translation type="unfinished"></translation>
+ <translation>Уда&amp;лить триггер</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="164"/>
<source>Create a &amp;view</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Создать представление</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="165"/>
<source>Edit the v&amp;iew</source>
- <translation type="unfinished"></translation>
+ <translation>Редактироват&amp;ь представление</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="166"/>
<source>Delete the vi&amp;ew</source>
- <translation type="unfinished"></translation>
+ <translation>Удалить &amp;представление</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="172"/>
<source>&amp;Refresh all database schemas</source>
- <translation type="unfinished"></translation>
+ <translation>Обновить структуры всех баз данн&amp;ых</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="173"/>
<source>Re&amp;fresh selected database schema</source>
- <translation type="unfinished"></translation>
+ <translation>Обновить структуру выбранной базы данны&amp;х</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="174"/>
@@ -2600,12 +2600,12 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="179"/>
<source>Open file&apos;s directory</source>
- <translation type="unfinished"></translation>
+ <translation>Открыть папку с этим файлом</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="180"/>
<source>Execute SQL from file</source>
- <translation type="unfinished"></translation>
+ <translation>Выполнить SQL-запросы из файла</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="355"/>
@@ -2684,32 +2684,32 @@ All objects from this group will be moved to parent group.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="1872"/>
<source>Could not execute SQL, because application has failed to start transaction: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Невозможно выполнить SQL-запрос, так как приложению не удалось начать транзакцию: %1</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1886"/>
<source>Could not open file &apos;%1&apos; for reading: %2</source>
- <translation type="unfinished">Невозможно открыть файл &apos;%1&apos; для чтения: %2</translation>
+ <translation>Невозможно открыть файл &apos;%1&apos; для чтения: %2</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1972"/>
<source>Could not execute SQL, because application has failed to commit the transaction: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Невозможно выполнить SQL-запрос, так как приложению не удалось завершить транзакцию: %1</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1976"/>
<source>Finished executing %1 queries in %2 seconds. %3 were not executed due to errors.</source>
- <translation type="unfinished"></translation>
+ <translation>Завершено выполнение %1 запросов за %2 секунд. %3 запросов не было выполнено из-за ошибок.</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1981"/>
<source>Finished executing %1 queries in %2 seconds.</source>
- <translation type="unfinished"></translation>
+ <translation>Завершено выполнение %1 запросов за %2 секунд.</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1987"/>
<source>Could not execute SQL due to error.</source>
- <translation type="unfinished"></translation>
+ <translation>Невозможно выполнить SQL-запрос из-за ошибки.</translation>
</message>
<message>
<source>Delete database</source>
@@ -2761,11 +2761,11 @@ All objects from this group will be moved to parent group.</source>
</message>
<message>
<source>Autoincrement value for table &apos;%1&apos; has been reset successfly.</source>
- <translation type="vanished">Сброс счётчика автоинкремента у таблицы &apos;%1&apos; успешно выполнен.</translation>
+ <translation>Сброс счётчика автоинкремента у таблицы &apos;%1&apos; успешно выполнен.</translation>
</message>
<message>
<source>Are you sure you want to delete all data from table &apos;%1&apos;?</source>
- <translation type="vanished">Вы действительно хотите удалить все данные из таблицы &apos;%1&apos;?</translation>
+ <translation>Вы действительно хотите удалить все данные из таблицы &apos;%1&apos;?</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1579"/>
@@ -3108,7 +3108,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<location filename="../windows/editorwindow.cpp" line="398"/>
<source>Delete selected SQL history entries</source>
<comment>sql editor</comment>
- <translation type="unfinished"></translation>
+ <translation>Удалить выбранные записи из истории SQL-запросов</translation>
</message>
<message>
<location filename="../windows/editorwindow.cpp" line="472"/>
@@ -3152,7 +3152,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
</message>
<message>
<source>Editor window &quot;%1&quot; has uncommited data.</source>
- <translation type="vanished">В окне редактора &quot;%1&quot; имеются неподтверждённые данные.</translation>
+ <translation>В окне редактора &quot;%1&quot; имеются неподтверждённые данные.</translation>
</message>
</context>
<context>
@@ -3178,57 +3178,57 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="14"/>
<source>Execute SQL from file</source>
- <translation type="unfinished"></translation>
+ <translation>Выполнение SQL-запросов из файла</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="23"/>
<source>Input file</source>
- <translation type="unfinished"></translation>
+ <translation>Файл-источник</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="29"/>
<source>Path to file</source>
- <translation type="unfinished"></translation>
+ <translation>Путь к файлу</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="36"/>
<source>Browse for file</source>
- <translation type="unfinished"></translation>
+ <translation>Выбрать файл</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="53"/>
<source>Options</source>
- <translation type="unfinished">Опции</translation>
+ <translation>Опции</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="59"/>
<source>File encoding</source>
- <translation type="unfinished"></translation>
+ <translation>Кодировка файла</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="69"/>
<source>Skip failing SQL statements</source>
- <translation type="unfinished"></translation>
+ <translation>Пропуск неудавшихся SQL-запросов</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.cpp" line="49"/>
<source>SQL scripts (*.sql);;All files (*)</source>
- <translation type="unfinished">Скрипты SQL (*.sql);;Все файлы (*)</translation>
+ <translation>Скрипты SQL (*.sql);;Все файлы (*)</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.cpp" line="50"/>
<source>Execute SQL file</source>
- <translation type="unfinished"></translation>
+ <translation>Выполнить SQL-запросы из файла</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.cpp" line="64"/>
<source>Please provide file to be executed.</source>
- <translation type="unfinished"></translation>
+ <translation>Пожалуйста укажите файл с SQL-запросами</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.cpp" line="71"/>
<source>Provided file does not exist or cannot be read.</source>
- <translation type="unfinished"></translation>
+ <translation>Указанный файл не существует или не может быть прочитан.</translation>
</message>
</context>
<context>
@@ -3447,32 +3447,32 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="14"/>
<source>Execution errors</source>
- <translation type="unfinished"></translation>
+ <translation>Ошибки выполнения</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="26"/>
<source>Following errors were encountered during execution of SQL statements from the file:</source>
- <translation type="unfinished"></translation>
+ <translation>При выполнении SQL-запросов из файла возникли следующие ошибки:</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="49"/>
<source>SQL</source>
- <translation type="unfinished"></translation>
+ <translation>SQL-запрос</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="54"/>
<source>Error</source>
- <translation type="unfinished">Ошибка</translation>
+ <translation>Ошибка</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="68"/>
<source>Statements that were executed successfully were commited.</source>
- <translation type="unfinished"></translation>
+ <translation>Успешно выполненные запросы были записаны в базу.</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="81"/>
<source>Statements that were executed successfully were rolled back.</source>
- <translation type="unfinished"></translation>
+ <translation>Успешно выполненные запросы были откачены.</translation>
</message>
</context>
<context>
@@ -3704,7 +3704,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
</message>
<message>
<source>Functions editor window has uncommited modifications.</source>
- <translation type="vanished">В окне редактора функций имеются неподтверждённые изменения.</translation>
+ <translation>В окне редактора функций имеются неподтверждённые изменения.</translation>
</message>
</context>
<context>
@@ -4060,47 +4060,47 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
</message>
<message>
<source>Open SQL editor</source>
- <translation type="vanished">Открыть редактор SQL</translation>
+ <translation>Открыть редактор SQL</translation>
</message>
<message>
<source>Open DDL history</source>
- <translation type="vanished">Открыть историю DDL</translation>
+ <translation>Открыть историю DDL</translation>
</message>
<message>
<source>Open SQL functions editor</source>
- <translation type="vanished">Открыть редактор функций SQL</translation>
+ <translation>Открыть редактор функций SQL</translation>
</message>
<message>
<source>Open collations editor</source>
- <translation type="vanished">Открыть редактор сравнений</translation>
+ <translation>Открыть редактор сравнений</translation>
</message>
<message>
<source>Import</source>
- <translation type="vanished">Импорт</translation>
+ <translation>Импорт</translation>
</message>
<message>
<source>Export</source>
- <translation type="vanished">Экспорт</translation>
+ <translation>Экспорт</translation>
</message>
<message>
<source>Open configuration dialog</source>
- <translation type="vanished">Открыть диалог конфигурации</translation>
+ <translation>Открыть диалог конфигурации</translation>
</message>
<message>
<source>Tile windows</source>
- <translation type="vanished">Расположить окна плиткой</translation>
+ <translation>Расположить окна плиткой</translation>
</message>
<message>
<source>Tile windows horizontally</source>
- <translation type="vanished">Расположить окна по горизонтали</translation>
+ <translation>Расположить окна по горизонтали</translation>
</message>
<message>
<source>Tile windows vertically</source>
- <translation type="vanished">Расположить окна по вертикали</translation>
+ <translation>Расположить окна по вертикали</translation>
</message>
<message>
<source>Cascade windows</source>
- <translation type="vanished">Расположить окна каскадом</translation>
+ <translation>Расположить окна каскадом</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="247"/>
@@ -4119,23 +4119,23 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
</message>
<message>
<source>Close selected window</source>
- <translation type="vanished">Закрыть выбранное окно</translation>
+ <translation>Закрыть выбранное окно</translation>
</message>
<message>
<source>Close all windows but selected</source>
- <translation type="vanished">Закрыть все окна, кроме выбранного</translation>
+ <translation>Закрыть все окна, кроме выбранного</translation>
</message>
<message>
<source>Close all windows</source>
- <translation type="vanished">Закрыть все окна</translation>
+ <translation>Закрыть все окна</translation>
</message>
<message>
<source>Restore recently closed window</source>
- <translation type="vanished">Восстановить недавно закрытые окна</translation>
+ <translation>Восстановить недавно закрытые окна</translation>
</message>
<message>
<source>Rename selected window</source>
- <translation type="vanished">Переименовать выбранное окно</translation>
+ <translation>Переименовать выбранное окно</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="257"/>
@@ -4149,58 +4149,58 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
</message>
<message>
<source>Report a bug</source>
- <translation type="vanished">Сообщить об ошибке</translation>
+ <translation>Сообщить об ошибке</translation>
</message>
<message>
<source>Propose a new feature</source>
- <translation type="vanished">Предложить новый функционал</translation>
+ <translation>Предложить новый функционал</translation>
</message>
<message>
<source>About</source>
- <translation type="vanished">О программе</translation>
+ <translation>О программе</translation>
</message>
<message>
<source>Licenses</source>
- <translation type="vanished">Лицензии</translation>
+ <translation>Лицензии</translation>
</message>
<message>
<source>Open home page</source>
- <translation type="vanished">Открыть домашнюю страницу</translation>
+ <translation>Открыть домашнюю страницу</translation>
</message>
<message>
<source>Open forum page</source>
- <translation type="vanished">Открыть страницу форума</translation>
+ <translation>Открыть страницу форума</translation>
</message>
<message>
<source>User Manual</source>
- <translation type="vanished">Руководство пользователя</translation>
+ <translation>Руководство пользователя</translation>
</message>
<message>
<source>SQLite documentation</source>
- <translation type="vanished">Документация по SQLite</translation>
+ <translation>Документация по SQLite</translation>
</message>
<message>
<source>Report history</source>
- <translation type="vanished">История отчётов</translation>
+ <translation>История отчётов</translation>
</message>
<message>
<source>Check for updates</source>
- <translation type="vanished">Проверить обновления</translation>
+ <translation>Проверить обновления</translation>
</message>
<message>
<source>Database</source>
<comment>menubar</comment>
- <translation type="vanished">База данных</translation>
+ <translation>База данных</translation>
</message>
<message>
<source>Structure</source>
<comment>menubar</comment>
- <translation type="vanished">Структура</translation>
+ <translation>Структура</translation>
</message>
<message>
<source>View</source>
<comment>menubar</comment>
- <translation type="vanished">Вид</translation>
+ <translation>Вид</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="352"/>
@@ -4211,175 +4211,175 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<source>Tools</source>
<comment>menubar</comment>
- <translation type="vanished">Инструменты</translation>
+ <translation>Инструменты</translation>
</message>
<message>
<source>Help</source>
- <translation type="vanished">Справка</translation>
+ <translation>Справка</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="233"/>
<source>Open SQL &amp;editor</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Открыть редактор SQL</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="234"/>
<source>Open DDL &amp;history</source>
- <translation type="unfinished"></translation>
+ <translation>О&amp;ткрыть историю DDL</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="235"/>
<source>Open SQL &amp;functions editor</source>
- <translation type="unfinished"></translation>
+ <translation>От&amp;крыть редактор функций SQL</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="236"/>
<source>Open &amp;collations editor</source>
- <translation type="unfinished"></translation>
+ <translation>Отк&amp;рыть редактор сравнений</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="237"/>
<source>Open ex&amp;tension manager</source>
- <translation type="unfinished"></translation>
+ <translation>Откр&amp;ыть менеджер расширений</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="238"/>
<source>&amp;Import</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Импорт</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="239"/>
<source>E&amp;xport</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Экспорт</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="241"/>
<source>Open confi&amp;guration dialog</source>
- <translation type="unfinished"></translation>
+ <translation>Открыт&amp;ь диалог конфигурации</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="243"/>
<source>&amp;Tile windows</source>
- <translation type="unfinished"></translation>
+ <translation>Р&amp;асположить окна плиткой</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="244"/>
<source>Tile windows &amp;horizontally</source>
- <translation type="unfinished"></translation>
+ <translation>Распо&amp;ложить окна по горизонтали</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="245"/>
<source>Tile windows &amp;vertically</source>
- <translation type="unfinished"></translation>
+ <translation>Располо&amp;жить окна по вертикали</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="246"/>
<source>&amp;Cascade windows</source>
- <translation type="unfinished"></translation>
+ <translation>Ра&amp;сположить окна каскадом</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="251"/>
<source>Close selected &amp;window</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Закрыть выбранное окно</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="252"/>
<source>Close all windows &amp;but selected</source>
- <translation type="unfinished"></translation>
+ <translation>Закрыть &amp;все окна, кроме выбранного</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="253"/>
<source>Close &amp;all windows</source>
- <translation type="unfinished"></translation>
+ <translation>Закрыть вс&amp;е окна</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="254"/>
<source>Re&amp;store recently closed window</source>
- <translation type="unfinished"></translation>
+ <translation>Восста&amp;новить последнее закрытое окно</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="255"/>
<source>&amp;Rename selected window</source>
- <translation type="unfinished"></translation>
+ <translation>Переи&amp;меновать выбранное окно</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="259"/>
<source>Report a &amp;bug</source>
- <translation type="unfinished"></translation>
+ <translation>Сообщить об о&amp;шибке</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="260"/>
<source>Propose a new &amp;feature</source>
- <translation type="unfinished"></translation>
+ <translation>Предложить новую &amp;функцию</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="261"/>
<source>&amp;About</source>
- <translation type="unfinished"></translation>
+ <translation>О про&amp;грамме</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="262"/>
<source>&amp;Licenses</source>
- <translation type="unfinished"></translation>
+ <translation>Ли&amp;цензии</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="263"/>
<source>Open home &amp;page</source>
- <translation type="unfinished"></translation>
+ <translation>Открыть домашн&amp;юю страницу</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="264"/>
<source>Open fo&amp;rum page</source>
- <translation type="unfinished"></translation>
+ <translation>Открыть страниц&amp;у форума</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="265"/>
<source>User &amp;Manual</source>
- <translation type="unfinished"></translation>
+ <translation>Руководство пользовател&amp;я</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="266"/>
<source>SQLite &amp;documentation</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Документация по SQLite</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="267"/>
<source>Bugs and feature &amp;requests</source>
- <translation type="unfinished"></translation>
+ <translation>Оши&amp;бки и предложения</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="269"/>
<source>Check for &amp;updates</source>
- <translation type="unfinished"></translation>
+ <translation>&amp;Проверить обновления</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="307"/>
<source>&amp;Database</source>
<comment>menubar</comment>
- <translation type="unfinished"></translation>
+ <translation>&amp;База данных</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="327"/>
<source>&amp;Structure</source>
<comment>menubar</comment>
- <translation type="unfinished"></translation>
+ <translation>&amp;Структура</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="348"/>
<source>&amp;View</source>
<comment>menubar</comment>
- <translation type="unfinished"></translation>
+ <translation>&amp;Вид</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="373"/>
<source>&amp;Tools</source>
<comment>menubar</comment>
- <translation type="unfinished"></translation>
+ <translation>&amp;Инструменты</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="388"/>
<source>&amp;Help</source>
- <translation type="unfinished"></translation>
+ <translation>С&amp;правка</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="550"/>
@@ -4437,7 +4437,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<name>MdiWindow</name>
<message>
<source>Uncommited changes</source>
- <translation type="vanished">Неподтверждённые изменения</translation>
+ <translation>Неподтверждённые изменения</translation>
</message>
<message>
<location filename="../mdiwindow.cpp" line="199"/>
@@ -4471,7 +4471,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditor.cpp" line="94"/>
<source>Open another tab</source>
- <translation type="unfinished"></translation>
+ <translation>Открыть дополнительную вкладку</translation>
</message>
<message>
<location filename="../multieditor/multieditor.cpp" line="333"/>
@@ -4495,7 +4495,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<name>MultiEditorBool</name>
<message>
<source>Boolean</source>
- <translation type="vanished">Логическое</translation>
+ <translation>Логическое</translation>
</message>
</context>
<context>
@@ -4503,14 +4503,14 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditorbool.cpp" line="214"/>
<source>Boolean</source>
- <translation type="unfinished">Логическое</translation>
+ <translation>Логическое</translation>
</message>
</context>
<context>
<name>MultiEditorDate</name>
<message>
<source>Date</source>
- <translation type="vanished">Дата</translation>
+ <translation>Дата</translation>
</message>
</context>
<context>
@@ -4518,14 +4518,14 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditordate.cpp" line="86"/>
<source>Date</source>
- <translation type="unfinished">Дата</translation>
+ <translation>Дата</translation>
</message>
</context>
<context>
<name>MultiEditorDateTime</name>
<message>
<source>Date &amp; time</source>
- <translation type="vanished">Дата и время</translation>
+ <translation>Дата и время</translation>
</message>
</context>
<context>
@@ -4533,14 +4533,14 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditordatetime.cpp" line="274"/>
<source>Date &amp; time</source>
- <translation type="unfinished">Дата и время</translation>
+ <translation>Дата и время</translation>
</message>
</context>
<context>
<name>MultiEditorHex</name>
<message>
<source>Hex</source>
- <translation type="vanished">Шестнадцатеричное</translation>
+ <translation>Шестнадцатеричное</translation>
</message>
</context>
<context>
@@ -4548,7 +4548,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditorhex.cpp" line="91"/>
<source>Hex</source>
- <translation type="unfinished">Шестнадцатеричное</translation>
+ <translation>Шестнадцатеричное</translation>
</message>
</context>
<context>
@@ -4556,7 +4556,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<source>Number</source>
<comment>numeric multi editor tab name</comment>
- <translation type="vanished">Число</translation>
+ <translation>Число</translation>
</message>
</context>
<context>
@@ -4565,14 +4565,14 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<location filename="../multieditor/multieditornumeric.cpp" line="109"/>
<source>Number</source>
<comment>numeric multi editor tab name</comment>
- <translation type="unfinished">Число</translation>
+ <translation>Число</translation>
</message>
</context>
<context>
<name>MultiEditorText</name>
<message>
<source>Text</source>
- <translation type="vanished">Текст</translation>
+ <translation>Текст</translation>
</message>
<message>
<location filename="../multieditor/multieditortext.cpp" line="102"/>
@@ -4615,14 +4615,14 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditortext.cpp" line="184"/>
<source>Text</source>
- <translation type="unfinished">Текст</translation>
+ <translation>Текст</translation>
</message>
</context>
<context>
<name>MultiEditorTime</name>
<message>
<source>Time</source>
- <translation type="vanished">Время</translation>
+ <translation>Время</translation>
</message>
</context>
<context>
@@ -4630,7 +4630,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditortime.cpp" line="89"/>
<source>Time</source>
- <translation type="unfinished">Время</translation>
+ <translation>Время</translation>
</message>
</context>
<context>
@@ -4707,11 +4707,11 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/newversiondialog.ui" line="109"/>
<source>This application will be closed and the update installer will start to download and install all the updates.</source>
- <translation type="unfinished"></translation>
+ <translation>Приложение будет закрыто, и установщик обновлений начнёт загрузку и установку обновлений.</translation>
</message>
<message>
<source>Current version</source>
- <translation type="vanished">Текущая версия</translation>
+ <translation>Текущая версия</translation>
</message>
<message>
<location filename="../dialogs/newversiondialog.ui" line="75"/>
@@ -4730,7 +4730,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
</message>
<message>
<source>The update will be automatically downloaded and installed. This will also restart application at the end.</source>
- <translation type="vanished">Обновление будет автоматически загружено и установлено. В конце процесса приложение будет перезапущено.</translation>
+ <translation>Обновление будет автоматически загружено и установлено. В конце процесса приложение будет перезапущено.</translation>
</message>
<message>
<location filename="../dialogs/newversiondialog.ui" line="116"/>
@@ -4902,7 +4902,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../datagrid/sqlqueryview.h" line="23"/>
<source>Copy cell(s) contents together with header to clipboard</source>
- <translation type="unfinished"></translation>
+ <translation>Копировать имя столбца и содержимое ячеек в буфер обмена</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="25"/>
@@ -5264,11 +5264,11 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
</message>
<message>
<source>Reports history window</source>
- <translation type="vanished">Окно истории отчётов</translation>
+ <translation>Окно истории отчётов</translation>
</message>
<message>
<source>Delete selected entry</source>
- <translation type="vanished">Удалить выбранную запись</translation>
+ <translation>Удалить выбранную запись</translation>
</message>
<message>
<location filename="../windows/editorwindow.h" line="26"/>
@@ -5318,7 +5318,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/editorwindow.h" line="35"/>
<source>Delete selected SQL history entries</source>
- <translation type="unfinished"></translation>
+ <translation>Удалить выбранные записи из истории SQL-запросов</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="31"/>
@@ -5440,7 +5440,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<name>QuitConfirmDialog</name>
<message>
<source>Uncommited changes</source>
- <translation type="vanished">Неподтверждённые изменения</translation>
+ <translation>Неподтверждённые изменения</translation>
</message>
<message>
<location filename="../dialogs/quitconfirmdialog.ui" line="14"/>
@@ -5749,7 +5749,7 @@ find next</source>
</message>
<message>
<source>This cell is not editable, because: %1</source>
- <translation type="vanished">Эта ячейка нередактируема, причина: %1</translation>
+ <translation>Эта ячейка нередактируема, причина: %1</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryitem.cpp" line="423"/>
@@ -5761,7 +5761,7 @@ find next</source>
<name>SqlQueryItemDelegate</name>
<message>
<source>Cannot edit this cell. Details: %2</source>
- <translation type="vanished">Невозможно редактировать данную ячейку. Подробности: %2</translation>
+ <translation>Невозможно редактировать данную ячейку. Подробности: %2</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryitemdelegate.cpp" line="53"/>
@@ -5804,11 +5804,11 @@ find next</source>
</message>
<message>
<source>Uncommited data</source>
- <translation type="vanished">Неподтверждённые данные</translation>
+ <translation>Неподтверждённые данные</translation>
</message>
<message>
<source>There are uncommited data changes. Do you want to proceed anyway? All uncommited changes will be lost.</source>
- <translation type="vanished">Имеются неподтверждённые изменения данных. Вы действительно хотите продолжить? Все неподтверждённые изменения будут утеряны.</translation>
+ <translation>Имеются неподтверждённые изменения данных. Вы действительно хотите продолжить? Все неподтверждённые изменения будут утеряны.</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="376"/>
@@ -5822,7 +5822,7 @@ find next</source>
</message>
<message>
<source>An error occurred while commiting the transaction: %1</source>
- <translation type="vanished">При завершении транзакции возникла ошибка: %1</translation>
+ <translation>При завершении транзакции возникла ошибка: %1</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="455"/>
@@ -5836,7 +5836,7 @@ find next</source>
</message>
<message>
<source>An error occurred while commiting the data: %1</source>
- <translation type="vanished">При подтверждении данных произошла ошибка: %1</translation>
+ <translation>При подтверждении данных произошла ошибка: %1</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="118"/>
@@ -5861,7 +5861,7 @@ find next</source>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="987"/>
<source>Number of rows per page was decreased to %1 due to number of columns (%2) in the data view.</source>
- <translation type="unfinished"></translation>
+ <translation>Количество строк на странице было уменьшено до %1 из-за большого количества столбцов (%2) в окне данных.</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="1165"/>
@@ -5935,7 +5935,7 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="90"/>
<source>Copy with headers</source>
- <translation type="unfinished"></translation>
+ <translation>Копировать с именами столбцов</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="98"/>
@@ -5980,7 +5980,7 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="163"/>
<source>Show value in a viewer</source>
- <translation type="unfinished"></translation>
+ <translation>Показать значение в просмотрщике</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="181"/>
@@ -6010,12 +6010,12 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="680"/>
<source>Trim pasted text?</source>
- <translation type="unfinished"></translation>
+ <translation>Обрезать вставленный текст?</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="681"/>
<source>The pasted text contains leading or trailing white space. Trim it automatically?</source>
- <translation type="unfinished"></translation>
+ <translation>В начале либо конце вставленного текста находятся непечатаемые символы. Обрезать их автоматически?</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="776"/>
@@ -6027,7 +6027,7 @@ find next</source>
<name>SqlTableModel</name>
<message>
<source>Error while commiting new row: %1</source>
- <translation type="vanished">Ошибка при подтверждении новой строки: %1</translation>
+ <translation>Ошибка при подтверждении новой строки: %1</translation>
</message>
<message>
<location filename="../datagrid/sqltablemodel.cpp" line="82"/>
@@ -6045,112 +6045,112 @@ find next</source>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="63"/>
<source>Filter extensions</source>
- <translation type="unfinished"></translation>
+ <translation>Фильтр расширений</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="107"/>
<source>Leave empty to use default function</source>
- <translation type="unfinished"></translation>
+ <translation>Оставьте пустым для использования функции по умолчанию</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="128"/>
<source>Extension file</source>
- <translation type="unfinished"></translation>
+ <translation>Файл расширения</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="135"/>
<source>Initialization function</source>
- <translation type="unfinished"></translation>
+ <translation>Инициализирующая функция</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="151"/>
<source>Databases</source>
- <translation type="unfinished">Базы данных</translation>
+ <translation>Базы данных</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="157"/>
<source>Register in all databases</source>
- <translation type="unfinished">Зарегистрировать во всех базах данных</translation>
+ <translation>Зарегистрировать во всех базах данных</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="164"/>
<source>Register in following databases:</source>
- <translation type="unfinished">Зарегистрировать в следующих базах данных:</translation>
+ <translation>Зарегистрировать в следующих базах данных:</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="43"/>
<source>Extension manager window has uncommitted modifications.</source>
- <translation type="unfinished"></translation>
+ <translation>В менеджере расширений имеются неподтверждённые изменения.</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="64"/>
<source>Extension manager</source>
- <translation type="unfinished"></translation>
+ <translation>Менеджер расширений</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="69"/>
<source>Commit all extension changes</source>
- <translation type="unfinished"></translation>
+ <translation>Подтвердить все изменения расширений</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="70"/>
<source>Rollback all extension changes</source>
- <translation type="unfinished"></translation>
+ <translation>Откатить все изменения расширений</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="72"/>
<source>Add new extension</source>
- <translation type="unfinished"></translation>
+ <translation>Добавить новое расширение</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="73"/>
<source>Remove selected extension</source>
- <translation type="unfinished"></translation>
+ <translation>Удалить выбранное расширение</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="75"/>
<source>Editing extensions manual</source>
- <translation type="unfinished"></translation>
+ <translation>Руководство по редактированию расширений</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="235"/>
<source>File with given path does not exist or is not readable.</source>
- <translation type="unfinished"></translation>
+ <translation>Файл по указанному пути не существует или не читается.</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="241"/>
<source>Unable to load extension: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Невозможно загрузить расширение: %1</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="355"/>
<source>Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore.</source>
- <translation type="unfinished"></translation>
+ <translation>Некорректное имя инициализирующей функции. Имя функции может состоять только из английских букв, цифр и подчёркивания.</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="424"/>
<source>Dynamic link libraries (*.dll);;All files (*)</source>
- <translation type="unfinished"></translation>
+ <translation>Динамически подключаемые библиотеки (*.dll);;Все файлы (*)</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="426"/>
<source>Shared objects (*.so);;All files (*)</source>
- <translation type="unfinished"></translation>
+ <translation>Общие объекты (*.so);;Все файлы (*)</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="428"/>
<source>Dynamic libraries (*.dylib);;All files (*)</source>
- <translation type="unfinished"></translation>
+ <translation>Динамические библиотеки (*.dylib);;Все файлы (*)</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="430"/>
<source>All files (*)</source>
- <translation type="unfinished">Все файлы (*)</translation>
+ <translation>Все файлы (*)</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="432"/>
<source>Open file</source>
- <translation type="unfinished">Открыть файл</translation>
+ <translation>Открыть файл</translation>
</message>
</context>
<context>
@@ -6728,11 +6728,11 @@ Do you want to commit the structure, or do you want to go back to the structure
</message>
<message>
<source>Commited changes for table &apos;%1&apos; successfly.</source>
- <translation type="vanished">Изменения в таблицу &apos;%1&apos; внесены успешно.</translation>
+ <translation>Изменения в таблицу &apos;%1&apos; внесены успешно.</translation>
</message>
<message>
<source>Commited changes for table &apos;%1&apos; (named before &apos;%2&apos;) successfly.</source>
- <translation type="vanished">Изменения в таблицу &apos;%1&apos; (предыдущее название &apos;%2&apos;) внесены успешно.</translation>
+ <translation>Изменения в таблицу &apos;%1&apos; (предыдущее название &apos;%2&apos;) внесены успешно.</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="866"/>
@@ -6757,7 +6757,7 @@ Do you want to commit the structure, or do you want to go back to the structure
</message>
<message>
<source>Autoincrement value for table &apos;%1&apos; has been reset successfly.</source>
- <translation type="vanished">Сброс счётчика автоинкремента у таблицы &apos;%1&apos; успешно выполнен.</translation>
+ <translation>Сброс счётчика автоинкремента у таблицы &apos;%1&apos; успешно выполнен.</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="977"/>
@@ -6810,12 +6810,12 @@ Are you sure you want to create a table with blank name?</source>
</message>
<message>
<source>Uncommited changes</source>
- <translation type="vanished">Неподтверждённые изменения</translation>
+ <translation>Неподтверждённые изменения</translation>
</message>
<message>
<source>There are uncommited structure modifications. You cannot browse or edit data until you have table structure settled.
Do you want to commit the structure, or do you want to go back to the structure tab?</source>
- <translation type="vanished">Имеются неподтверждённые изменения структуры. Невозможно просматривать или редактировать данные, пока структура таблицы не подтверждена.
+ <translation>Имеются неподтверждённые изменения структуры. Невозможно просматривать или редактировать данные, пока структура таблицы не подтверждена.
Подтвердить структуру таблицы или вернуться на вкладку структуры?</translation>
</message>
<message>
@@ -6878,15 +6878,15 @@ Do you want to commit the structure, or do you want to go back to the structure
</message>
<message>
<source>Table window &quot;%1&quot; has uncommited structure modifications and data.</source>
- <translation type="vanished">В окне таблицы &quot;%1&quot; имеются неподтверждённые изменения структуры и данных.</translation>
+ <translation>В окне таблицы &quot;%1&quot; имеются неподтверждённые изменения структуры и данных.</translation>
</message>
<message>
<source>Table window &quot;%1&quot; has uncommited data.</source>
- <translation type="vanished">В окне таблицы &quot;%1&quot; имеются неподтверждённые изменения данных.</translation>
+ <translation>В окне таблицы &quot;%1&quot; имеются неподтверждённые изменения данных.</translation>
</message>
<message>
<source>Table window &quot;%1&quot; has uncommited structure modifications.</source>
- <translation type="vanished">В окне таблицы &quot;%1&quot; имеются неподтверждённые изменения структуры.</translation>
+ <translation>В окне таблицы &quot;%1&quot; имеются неподтверждённые изменения структуры.</translation>
</message>
</context>
<context>
@@ -7231,15 +7231,15 @@ Do you want to commit the structure, or do you want to go back to the structure
</message>
<message>
<source>View window &quot;%1&quot; has uncommited structure modifications and data.</source>
- <translation type="vanished">В окне представления &quot;%1&quot; имеются неподтверждённые изменения структуры и данных.</translation>
+ <translation>В окне представления &quot;%1&quot; имеются неподтверждённые изменения структуры и данных.</translation>
</message>
<message>
<source>View window &quot;%1&quot; has uncommited data.</source>
- <translation type="vanished">В окне представления &quot;%1&quot; имеются неподтверждённые изменения данных.</translation>
+ <translation>В окне представления &quot;%1&quot; имеются неподтверждённые изменения данных.</translation>
</message>
<message>
<source>View window &quot;%1&quot; has uncommited structure modifications.</source>
- <translation type="vanished">В окне представления &quot;%1&quot; имеются неподтверждённые изменения структуры.</translation>
+ <translation>В окне представления &quot;%1&quot; имеются неподтверждённые изменения структуры.</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="569"/>
@@ -7248,12 +7248,12 @@ Do you want to commit the structure, or do you want to go back to the structure
</message>
<message>
<source>Uncommited changes</source>
- <translation type="vanished">Неподтверждённые изменения</translation>
+ <translation>Неподтверждённые изменения</translation>
</message>
<message>
<source>There are uncommited structure modifications. You cannot browse or edit data until you have the view structure settled.
Do you want to commit the structure, or do you want to go back to the structure tab?</source>
- <translation type="vanished">Имеются неподтверждённые изменения структуры. Невозможно просматривать или редактировать данные, пока структура представления не подтверждена.
+ <translation>Имеются неподтверждённые изменения структуры. Невозможно просматривать или редактировать данные, пока структура представления не подтверждена.
Подтвердить структуру представления или вернуться на вкладку структуры?</translation>
</message>
<message>
@@ -7268,11 +7268,11 @@ Do you want to commit the structure, or do you want to go back to the structure
</message>
<message>
<source>Commited changes for view &apos;%1&apos; successfly.</source>
- <translation type="vanished">Изменения в представление &apos;%1&apos; внесены успешно.</translation>
+ <translation>Изменения в представление &apos;%1&apos; внесены успешно.</translation>
</message>
<message>
<source>Commited changes for view &apos;%1&apos; (named before &apos;%2&apos;) successfly.</source>
- <translation type="vanished">Изменения в представление &apos;%1&apos; (предыдущее название &apos;%2&apos;) внесены успешно.</translation>
+ <translation>Изменения в представление &apos;%1&apos; (предыдущее название &apos;%2&apos;) внесены успешно.</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="650"/>
diff --git a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts
index cbfc48e..8a046cd 100644
--- a/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts
+++ b/SQLiteStudio3/guiSQLiteStudio/translations/guiSQLiteStudio_zh_CN.ts
@@ -60,12 +60,12 @@
<message>
<location filename="../dialogs/aboutdialog.ui" line="30"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;SQLiteStudio v%1&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Free, open-source, cross-platform SQLite database manager.&lt;br/&gt;&lt;a href=&quot;https://sqlitestudio.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://sqlitestudio.pl&lt;/span&gt;&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;%2&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Author and active maintainer:&lt;br/&gt;SalSoft (&lt;a href=&quot;https://salsoft.com.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://salsoft.com.pl&lt;/span&gt;&lt;/a&gt;)&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;SQLiteStudio v%1&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;自由,开源,跨平台的 SQLite 数据库管理工具。&lt;br/&gt;&lt;a href=&quot;https://sqlitestudio.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://sqlitestudio.pl&lt;/span&gt;&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;%2&lt;br/&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;作者和活跃维护人:&lt;br/&gt;SalSoft (&lt;a href=&quot;https://salsoft.com.pl&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://salsoft.com.pl&lt;/span&gt;&lt;/a&gt;)&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../dialogs/aboutdialog.ui" line="148"/>
<source>Qt version:</source>
- <translation>Qt版本:</translation>
+ <translation>Qt 版本:</translation>
</message>
<message>
<location filename="../dialogs/aboutdialog.cpp" line="39"/>
@@ -98,12 +98,12 @@
<message>
<location filename="../dialogs/bindparamsdialog.ui" line="17"/>
<source>Query parameters</source>
- <translation type="unfinished"></translation>
+ <translation>查询参数</translation>
</message>
<message>
<location filename="../dialogs/bindparamsdialog.ui" line="26"/>
<source>Please provide values for query parameters</source>
- <translation type="unfinished"></translation>
+ <translation>请提供一个值作为查询参数</translation>
</message>
</context>
<context>
@@ -318,7 +318,7 @@
<message>
<location filename="../windows/collationseditor.ui" line="75"/>
<source>Filter collations</source>
- <translation>过滤器排序规则</translation>
+ <translation>筛选排序规则</translation>
</message>
<message>
<location filename="../windows/collationseditor.ui" line="198"/>
@@ -353,7 +353,7 @@
<message>
<location filename="../windows/collationseditor.cpp" line="52"/>
<source>Collations editor</source>
- <translation>排序编辑器</translation>
+ <translation>排序规则编辑器</translation>
</message>
<message>
<location filename="../windows/collationseditor.cpp" line="57"/>
@@ -363,7 +363,7 @@
<message>
<location filename="../windows/collationseditor.cpp" line="58"/>
<source>Rollback all collation changes</source>
- <translation>回滚所有排序更改</translation>
+ <translation>回滚所有排序规则更改</translation>
</message>
<message>
<location filename="../windows/collationseditor.cpp" line="60"/>
@@ -398,7 +398,7 @@
<message>
<location filename="../windows/collationseditor.cpp" line="388"/>
<source>Collations editor window has uncommitted modifications.</source>
- <translation type="unfinished"></translation>
+ <translation>排序规则编辑器存在未提交的改动。</translation>
</message>
<message>
<source>Collations editor window has uncommited modifications.</source>
@@ -418,12 +418,12 @@
<message>
<location filename="../constraints/columncollatepanel.ui" line="41"/>
<source>Collation name:</source>
- <translation>排序名称:</translation>
+ <translation>排序规则名称:</translation>
</message>
<message>
<location filename="../constraints/columncollatepanel.ui" line="73"/>
<source>Named constraint:</source>
- <translation>约束名:</translation>
+ <translation>已命名的约束:</translation>
</message>
<message>
<location filename="../constraints/columncollatepanel.cpp" line="80"/>
@@ -451,17 +451,17 @@
<message>
<location filename="../constraints/columndefaultpanel.cpp" line="39"/>
<source>Enter a default value expression.</source>
- <translation>默认值表达式。</translation>
+ <translation>输入默认值表达式。</translation>
</message>
<message>
<location filename="../constraints/columndefaultpanel.cpp" line="78"/>
<source>Invalid default value expression: %1. If you want to use simple string as value, remember to surround it with quote characters.</source>
- <translation type="unfinished"></translation>
+ <translation>无效的默认值表达式:%1。如果你想使用简单的字符串作为值,记得用引号将其框起来。</translation>
</message>
<message>
<location filename="../constraints/columndefaultpanel.cpp" line="89"/>
<source>Invalid default value expression. If you want to use simple string as value, remember to surround it with quote characters.</source>
- <translation type="unfinished"></translation>
+ <translation>无效的默认值表达式。如果你想使用简单的字符串作为值,记得用引号将其框起来。</translation>
</message>
<message>
<source>Invalid default value expression: %1</source>
@@ -654,12 +654,12 @@
<location filename="../dialogs/columndialog.cpp" line="298"/>
<source>This constraint is not officially supported by SQLite 2,
but it&apos;s okay to use it.</source>
- <translation>SQLite2没有官方支持该约束,但是可以使用。</translation>
+ <translation>SQLite 2 没有官方支持该约束,但是可以使用。</translation>
</message>
<message>
<location filename="../dialogs/columndialog.cpp" line="387"/>
<source>Scale is not allowed for INTEGER PRIMARY KEY columns.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">小数长度在 INTEGER PRIMARY KEY 类型字段中不被允许。</translation>
</message>
<message>
<location filename="../dialogs/columndialog.cpp" line="388"/>
@@ -708,17 +708,17 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../constraints/columnforeignkeypanel.ui" line="29"/>
<source>Foreign table:</source>
- <translation></translation>
+ <translation type="unfinished">外部表:</translation>
</message>
<message>
<location filename="../constraints/columnforeignkeypanel.ui" line="45"/>
<source>Foreign column:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">外部字段:</translation>
</message>
<message>
<location filename="../constraints/columnforeignkeypanel.ui" line="58"/>
<source>Reactions</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">响应</translation>
</message>
<message>
<location filename="../constraints/columnforeignkeypanel.ui" line="97"/>
@@ -728,7 +728,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../constraints/columnforeignkeypanel.ui" line="115"/>
<source>Named constraint</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">已命名的约束</translation>
</message>
<message>
<location filename="../constraints/columnforeignkeypanel.ui" line="122"/>
@@ -738,12 +738,12 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../constraints/columnforeignkeypanel.cpp" line="40"/>
<source>Pick the foreign table.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">选择一个外部表。</translation>
</message>
<message>
<location filename="../constraints/columnforeignkeypanel.cpp" line="41"/>
<source>Pick the foreign column.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">选择一个外部字段。</translation>
</message>
<message>
<location filename="../constraints/columnforeignkeypanel.cpp" line="42"/>
@@ -756,7 +756,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../constraints/columnprimarykeypanel.ui" line="26"/>
<source>Autoincrement</source>
- <translation>Autoincrement</translation>
+ <translation type="unfinished">Autoincrement</translation>
</message>
<message>
<location filename="../constraints/columnprimarykeypanel.ui" line="48"/>
@@ -766,17 +766,17 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../constraints/columnprimarykeypanel.ui" line="83"/>
<source>Named constraint:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">已命名的约束:</translation>
</message>
<message>
<location filename="../constraints/columnprimarykeypanel.ui" line="111"/>
<source>On conflict:</source>
- <translation>冲突:</translation>
+ <translation>当冲突时:</translation>
</message>
<message>
<location filename="../constraints/columnprimarykeypanel.cpp" line="87"/>
<source>Enter a name of the constraint.</source>
- <translation type="unfinished"></translation>
+ <translation>输入约束名称</translation>
</message>
<message>
<source>Autoincrement (only for %1 type columns)</source>
@@ -789,12 +789,12 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../constraints/columnuniqueandnotnullpanel.ui" line="41"/>
<source>Named constraint:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">已命名的约束:</translation>
</message>
<message>
<location filename="../constraints/columnuniqueandnotnullpanel.ui" line="69"/>
<source>On conflict:</source>
- <translation>冲突:</translation>
+ <translation>当冲突时:</translation>
</message>
<message>
<location filename="../constraints/columnuniqueandnotnullpanel.cpp" line="73"/>
@@ -856,7 +856,7 @@ but it&apos;s okay to use it.</source>
<location filename="../completer/completerwindow.cpp" line="185"/>
<source>Operator: %1</source>
<comment>completer statusbar</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">操作符:%1</translation>
</message>
<message>
<location filename="../completer/completerwindow.cpp" line="187"/>
@@ -880,7 +880,7 @@ but it&apos;s okay to use it.</source>
<location filename="../completer/completerwindow.cpp" line="193"/>
<source>Collation: %1</source>
<comment>completer statusbar</comment>
- <translation type="unfinished"></translation>
+ <translation>排序规则:%1</translation>
</message>
<message>
<location filename="../completer/completerwindow.cpp" line="195"/>
@@ -955,7 +955,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="351"/>
<source>Database dialog window</source>
- <translation type="unfinished"></translation>
+ <translation>数据库对话窗口</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="357"/>
@@ -980,7 +980,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="418"/>
<source>Data browsing and editing</source>
- <translation>流量和编辑数据</translation>
+ <translation>浏览和编辑数据</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="495"/>
@@ -996,7 +996,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="488"/>
<source>Limit initial data column width to (in pixels):</source>
- <translation>限制宽度(单位:像素):</translation>
+ <translation>限制初始数据列宽度(单位:像素):</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="502"/>
@@ -1006,7 +1006,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="505"/>
<source>Show column and row details tooltip in data view</source>
- <translation type="unfinished"></translation>
+ <translation>在数据视图中展示字段与行的细节</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="515"/>
@@ -1016,7 +1016,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="544"/>
<source>Inserting new row in data grid</source>
- <translation type="unfinished"></translation>
+ <translation>在网格视图中插入新行</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="550"/>
@@ -1036,32 +1036,32 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="601"/>
<source>&lt;p&gt;When enabled, Table Windows will show up with the data tab, instead of the structure tab.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">&lt;p&gt;启用后,表窗口将显示数据选项卡,而不是结构选项卡。&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="614"/>
<source>&lt;p&gt;When enabled the &quot;Data&quot; tab will be placed as first tab in every Table Window, instead of being at second place.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">&lt;p&gt;启用后,“数据”选项卡将作为第一个选项卡放置在每个表窗口中,而不是位于第二位。&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="617"/>
<source>Place data tab as first tab in a Table Window</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">将数据作为表窗口的第一项</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="636"/>
<source>&lt;p&gt;When enabled, View Windows will show up with the data tab, instead of the structure tab.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">&lt;p&gt;启用后,视图窗口将显示数据选项卡,而不是结构选项卡。&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="649"/>
<source>&lt;p&gt;When enabled the &quot;Data&quot; tab will be placed as first tab in every View Window, instead of being at second place.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">&lt;p&gt;启用后,“数据”选项卡将作为第一个选项卡放置在每个视图窗口中,而不是位于第二个位置。&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="652"/>
<source>Place data tab as first tab in a View Window</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">将数据选项卡作为视图窗口的第一选项卡</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="696"/>
@@ -1081,7 +1081,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="786"/>
<source>Schema editing</source>
- <translation>架构编辑</translation>
+ <translation type="unfinished">架构编辑</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="798"/>
@@ -1100,7 +1100,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="831"/>
<source>SQL queries</source>
- <translation>SQL查询</translation>
+ <translation>SQL 查询</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="843"/>
@@ -1146,7 +1146,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="943"/>
<source>Status Field</source>
- <translation type="unfinished"></translation>
+ <translation>状态栏</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="949"/>
@@ -1156,17 +1156,17 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="952"/>
<source>Always open Status panel when new message is printed</source>
- <translation type="unfinished"></translation>
+ <translation>当有新信息被输出时,总是打开状态面板</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="994"/>
<source>Filter shortcuts by name or key combination</source>
- <translation type="unfinished"></translation>
+ <translation>以名称或按键组合筛选快捷键</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1035"/>
<source>Action</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">操作</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1040"/>
@@ -1187,17 +1187,17 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="1107"/>
<source>Compact layout</source>
- <translation type="unfinished"></translation>
+ <translation>紧凑布局</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1113"/>
<source>&lt;p&gt;Compact layout reduces all margins and spacing on the UI to minimum, making space for displaying more data. It makes the interface a little bit less aesthetic, but allows to display more data at once.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;紧凑布局会将 UI 中的边框与空白降低到最小值,然后用这些空白展示更多数据。这会使界面看起来有一点不美观,但是允许一次展示更多数据。&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1116"/>
<source>Use compact layout</source>
- <translation type="unfinished"></translation>
+ <translation>使用紧凑布局</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="166"/>
@@ -1218,7 +1218,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="258"/>
<source>Expand tables node when connected to a database</source>
- <translation>当连接到数据库时,展开数据库节点。</translation>
+ <translation>当连接到数据库时,展开数据库节点</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="268"/>
@@ -1253,7 +1253,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="315"/>
<source>Expand views node when connected to a database</source>
- <translation type="unfinished"></translation>
+ <translation>当连接到数据库时,展开视图节点</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="325"/>
@@ -1263,7 +1263,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="328"/>
<source>Sort objects (tables, indexes, triggers and views) alphabetically</source>
- <translation type="unfinished"></translation>
+ <translation>按字母顺序排序对象(表,索引,触发器与视图)</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="338"/>
@@ -1284,7 +1284,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="518"/>
<source>Keep NULL value when entering empty value</source>
- <translation type="unfinished"></translation>
+ <translation>当输入空值时保持 NULL 值</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="528"/>
@@ -1294,12 +1294,12 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="531"/>
<source>Use DEFAULT value (if defined), when committing NULL value</source>
- <translation type="unfinished"></translation>
+ <translation>当提交 NULL 值时使用 DEFAULT 值(如果已被定义)</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="595"/>
<source>Table windows</source>
- <translation type="unfinished"></translation>
+ <translation>表窗口</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="604"/>
@@ -1309,7 +1309,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="630"/>
<source>View windows</source>
- <translation type="unfinished"></translation>
+ <translation>视图窗口</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="639"/>
@@ -1319,7 +1319,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="818"/>
<source>Don&apos;t show DDL preview dialog when committing schema changes</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">当提交 schema 更改时不要展示 DDL 预览对话框</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="866"/>
@@ -1335,7 +1335,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="1132"/>
<source>Main window dock areas</source>
- <translation type="unfinished"></translation>
+ <translation>主窗口停靠区域</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1138"/>
@@ -1350,7 +1350,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="1280"/>
<source>Hide built-in plugins</source>
- <translation type="unfinished"></translation>
+ <translation>隐藏内建插件</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1309"/>
@@ -1380,7 +1380,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="1596"/>
<source>SQL editor font</source>
- <translation>SQL编辑器字体</translation>
+ <translation>SQL 编辑器字体</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1612"/>
@@ -1405,7 +1405,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="1718"/>
<source>SQL editor colors</source>
- <translation>SQL编辑器颜色</translation>
+ <translation>SQL 编辑器颜色</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1724"/>
@@ -1415,7 +1415,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="1731"/>
<source>&lt;p&gt;SQL strings are enclosed with single quote characters.&lt;/p&gt;</source>
- <translation>&lt;p&gt;单引号内的SQL字符串&lt;/p&gt;</translation>
+ <translation>&lt;p&gt;单引号内的 SQL 字符串&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1734"/>
@@ -1445,7 +1445,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="1873"/>
<source>BLOB value foreground</source>
- <translation>BLOB值的颜色</translation>
+ <translation>BLOB 值的颜色</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1880"/>
@@ -1480,12 +1480,12 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="1966"/>
<source>Valid objects foreground</source>
- <translation type="unfinished"></translation>
+ <translation>合法对象的颜色</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1992"/>
<source>Data view colors</source>
- <translation type="unfinished"></translation>
+ <translation>数据视图颜色</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="1998"/>
@@ -1495,7 +1495,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="2001"/>
<source>Uncommitted data outline color</source>
- <translation type="unfinished"></translation>
+ <translation>未提交数据的轮廓颜色</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="2024"/>
@@ -1505,12 +1505,12 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="2027"/>
<source>Commit error outline color</source>
- <translation type="unfinished"></translation>
+ <translation>提交错误的轮廓颜色</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="2050"/>
<source>NULL value foreground</source>
- <translation>NULL值的颜色</translation>
+ <translation>NULL 值的颜色</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="2073"/>
@@ -1535,7 +1535,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/configdialog.ui" line="2134"/>
<source>Status field colors</source>
- <translation type="unfinished"></translation>
+ <translation>状态栏颜色</translation>
</message>
<message>
<location filename="../dialogs/configdialog.ui" line="2140"/>
@@ -1592,7 +1592,7 @@ but it&apos;s okay to use it.</source>
<location filename="../dialogs/configdialog.cpp" line="799"/>
<source>Conflicts:</source>
<comment>plugin details</comment>
- <translation type="unfinished"></translation>
+ <translation>冲突:</translation>
</message>
<message>
<location filename="../dialogs/configdialog.cpp" line="803"/>
@@ -1646,27 +1646,27 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../constraints/constraintcheckpanel.ui" line="20"/>
<source>The condition</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">条件</translation>
</message>
<message>
<location filename="../constraints/constraintcheckpanel.ui" line="35"/>
<source>Named constraint:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">已命名的约束:</translation>
</message>
<message>
<location filename="../constraints/constraintcheckpanel.ui" line="51"/>
<source>On conflict</source>
- <translation type="unfinished"></translation>
+ <translation>当冲突时</translation>
</message>
<message>
<location filename="../constraints/constraintcheckpanel.cpp" line="46"/>
<source>Enter a valid condition.</source>
- <translation type="unfinished"></translation>
+ <translation>输入一个合法的条件。</translation>
</message>
<message>
<location filename="../constraints/constraintcheckpanel.cpp" line="47"/>
<source>Enter a name of the constraint.</source>
- <translation type="unfinished"></translation>
+ <translation>输一个约束的名称。</translation>
</message>
</context>
<context>
@@ -1675,49 +1675,49 @@ but it&apos;s okay to use it.</source>
<location filename="../dialogs/constraintdialog.cpp" line="62"/>
<source>New constraint</source>
<comment>constraint dialog</comment>
- <translation type="unfinished">新约束</translation>
+ <translation>新约束</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="63"/>
<source>Create</source>
<comment>constraint dialog</comment>
- <translation type="unfinished"></translation>
+ <translation>创建</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="66"/>
<source>Edit constraint</source>
<comment>dialog window</comment>
- <translation type="unfinished">编辑约束</translation>
+ <translation>编辑约束</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="67"/>
<source>Apply</source>
<comment>constraint dialog</comment>
- <translation type="unfinished"></translation>
+ <translation>应用</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="170"/>
<source>Primary key</source>
<comment>table constraints</comment>
- <translation type="unfinished"></translation>
+ <translation>主键</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="174"/>
<source>Foreign key</source>
<comment>table constraints</comment>
- <translation type="unfinished"></translation>
+ <translation>外键</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="178"/>
<source>Unique</source>
<comment>table constraints</comment>
- <translation type="unfinished">唯一</translation>
+ <translation>唯一</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="182"/>
<source>Not NULL</source>
<comment>table constraints</comment>
- <translation type="unfinished">非空</translation>
+ <translation>非 NULL</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="186"/>
@@ -1729,13 +1729,13 @@ but it&apos;s okay to use it.</source>
<location filename="../dialogs/constraintdialog.cpp" line="190"/>
<source>Collate</source>
<comment>table constraints</comment>
- <translation type="unfinished">排序规则</translation>
+ <translation>排序规则</translation>
</message>
<message>
<location filename="../dialogs/constraintdialog.cpp" line="194"/>
<source>Default</source>
<comment>table constraints</comment>
- <translation type="unfinished">默认</translation>
+ <translation>默认</translation>
</message>
</context>
<context>
@@ -1744,37 +1744,37 @@ but it&apos;s okay to use it.</source>
<location filename="../windows/constrainttabmodel.cpp" line="68"/>
<source>Table</source>
<comment>table constraints</comment>
- <translation type="unfinished">表</translation>
+ <translation>表</translation>
</message>
<message>
<location filename="../windows/constrainttabmodel.cpp" line="109"/>
<source>Column (%1)</source>
<comment>table constraints</comment>
- <translation type="unfinished"></translation>
+ <translation>字段(%1)</translation>
</message>
<message>
<location filename="../windows/constrainttabmodel.cpp" line="153"/>
<source>Scope</source>
<comment>table constraints</comment>
- <translation type="unfinished"></translation>
+ <translation>作用域</translation>
</message>
<message>
<location filename="../windows/constrainttabmodel.cpp" line="155"/>
<source>Type</source>
<comment>table constraints</comment>
- <translation type="unfinished">类型</translation>
+ <translation>类型</translation>
</message>
<message>
<location filename="../windows/constrainttabmodel.cpp" line="157"/>
<source>Details</source>
<comment>table constraints</comment>
- <translation type="unfinished">详情</translation>
+ <translation>详情</translation>
</message>
<message>
<location filename="../windows/constrainttabmodel.cpp" line="159"/>
<source>Name</source>
<comment>table constraints</comment>
- <translation type="unfinished">名称</translation>
+ <translation>名称</translation>
</message>
</context>
<context>
@@ -1782,7 +1782,7 @@ but it&apos;s okay to use it.</source>
<message>
<location filename="../dialogs/cssdebugdialog.ui" line="14"/>
<source>SQLiteStudio CSS console</source>
- <translation type="unfinished"></translation>
+ <translation>SQLiteStudio CSS 控制台</translation>
</message>
</context>
<context>
@@ -1791,29 +1791,29 @@ but it&apos;s okay to use it.</source>
<location filename="../dataview.cpp" line="105"/>
<source>Filter data</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation>筛选数据</translation>
</message>
<message>
<location filename="../dataview.cpp" line="114"/>
<source>Grid view</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">网格视图</translation>
</message>
<message>
<location filename="../dataview.cpp" line="115"/>
<source>Form view</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">表格视图</translation>
</message>
<message>
<location filename="../dataview.cpp" line="206"/>
<source>Refresh table data</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation>刷新表数据</translation>
</message>
<message>
<location filename="../dataview.cpp" line="223"/>
<source>First page</source>
<comment>data view</comment>
- <translation>首页</translation>
+ <translation>第一页</translation>
</message>
<message>
<location filename="../dataview.cpp" line="224"/>
@@ -1831,71 +1831,71 @@ but it&apos;s okay to use it.</source>
<location filename="../dataview.cpp" line="227"/>
<source>Last page</source>
<comment>data view</comment>
- <translation>末页</translation>
+ <translation>最后一页</translation>
</message>
<message>
<location filename="../dataview.cpp" line="947"/>
<source>Filter</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">筛选</translation>
</message>
<message>
<location filename="../dataview.cpp" line="950"/>
<source>Hit Enter key or press &quot;Apply filter&quot; button on toolbar to apply new value.</source>
- <translation type="unfinished"></translation>
+ <translation>按下回车或点击工具栏上的应用筛选按钮来应用新值。</translation>
</message>
<message>
<location filename="../dataview.cpp" line="996"/>
<source>Show filter inputs per column</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation>在每一个字段上展示筛选器输入</translation>
</message>
<message>
<location filename="../dataview.cpp" line="1000"/>
<source>Apply filter</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation>应用筛选</translation>
</message>
<message>
<location filename="../dataview.cpp" line="236"/>
<source>Commit changes for selected cells</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">提交选中单元格的更改</translation>
</message>
<message>
<location filename="../dataview.cpp" line="237"/>
<source>Rollback changes for selected cells</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">回滚选中单元格的修改</translation>
</message>
<message>
<location filename="../dataview.cpp" line="238"/>
<source>Show grid view of results</source>
<comment>sql editor</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">展示结果的网格视图</translation>
</message>
<message>
<location filename="../dataview.cpp" line="239"/>
<source>Show form view of results</source>
<comment>sql editor</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">展示结果的表格视图</translation>
</message>
<message>
<location filename="../dataview.cpp" line="978"/>
<source>Filter by text</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation>以文本筛选</translation>
</message>
<message>
<location filename="../dataview.cpp" line="979"/>
<source>Filter by the Regular Expression</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation>以正则表达式筛选</translation>
</message>
<message>
<location filename="../dataview.cpp" line="980"/>
<source>Filter by SQL expression</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation>以 SQL 表达式筛选</translation>
</message>
<message>
<location filename="../dataview.cpp" line="324"/>
@@ -1913,19 +1913,19 @@ but it&apos;s okay to use it.</source>
<location filename="../dataview.cpp" line="350"/>
<source>Place new rows above selected row</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">放置新行于选中行之上</translation>
</message>
<message>
<location filename="../dataview.cpp" line="351"/>
<source>Place new rows below selected row</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">放置新行于选中行之下</translation>
</message>
<message>
<location filename="../dataview.cpp" line="352"/>
<source>Place new rows at the end of the data view</source>
<comment>data view</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">放置新行于数据视图末尾</translation>
</message>
<message>
<location filename="../dataview.cpp" line="656"/>
@@ -1969,7 +1969,7 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dialogs/dbconverterdialog.ui" line="59"/>
<source>This is the file that will be created as a result of the conversion.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">此文件将会被创建,并作为转换的结果。</translation>
</message>
<message>
<location filename="../dialogs/dbconverterdialog.ui" line="66"/>
@@ -1979,7 +1979,7 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dialogs/dbconverterdialog.ui" line="73"/>
<source>Name of the new database:</source>
- <translation type="unfinished"></translation>
+ <translation>新数据库的名称:</translation>
</message>
<message>
<location filename="../dialogs/dbconverterdialog.ui" line="90"/>
@@ -1994,17 +1994,17 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dialogs/dbconverterdialog.cpp" line="129"/>
<source>Enter valid and writable file path.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">输入一个合法的且可写的文件的路径。</translation>
</message>
<message>
<location filename="../dialogs/dbconverterdialog.cpp" line="131"/>
<source>Entered file exists and will be overwritten.</source>
- <translation type="unfinished"></translation>
+ <translation>输入一个存在的且可覆写的文件。</translation>
</message>
<message>
<location filename="../dialogs/dbconverterdialog.cpp" line="135"/>
<source>Enter a not empty, unique name (as in the list of databases on the left).</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">输入一个非空,唯一的名称(用于左侧的数据库列表)</translation>
</message>
<message>
<location filename="../dialogs/dbconverterdialog.cpp" line="140"/>
@@ -2091,13 +2091,13 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dialogs/dbdialog.ui" line="79"/>
<source>Name (on the list)</source>
- <translation type="unfinished"></translation>
+ <translation>名称(显示在列表中)</translation>
</message>
<message>
<location filename="../dialogs/dbdialog.ui" line="97"/>
<source>&lt;p&gt;Enable this if you want the database to be stored in configuration file and restored every time SQLiteStudio is started.&lt;/p&gt;</source>
<extracomment>aasfd</extracomment>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;如果您想让这个数据库被存储在配置文件中并且在 SQLiteStudio 每次启动中被恢复,请勾选此项。&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/dbdialog.cpp" line="155"/>
@@ -2112,17 +2112,17 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dialogs/dbdialog.cpp" line="467"/>
<source>Enter an unique database name.</source>
- <translation type="unfinished"></translation>
+ <translation>请输入一个唯一的数据库名称。</translation>
</message>
<message>
<location filename="../dialogs/dbdialog.cpp" line="477"/>
<source>This name is already in use. Please enter unique name.</source>
- <translation type="unfinished"></translation>
+ <translation>此名称已被使用,请输入一个唯一的名称。</translation>
</message>
<message>
<location filename="../dialogs/dbdialog.cpp" line="484"/>
<source>&lt;p&gt;Automatic name generation was disabled, because the name was edited manually. To restore automatic generation please erase contents of the name field.&lt;/p&gt;</source>
- <translation type="unfinished"></translation>
+ <translation>&lt;p&gt;自动命名已被禁用,因为名称已被手动编辑。为了恢复自动命名,请删除名称中的所有内容。&lt;/p&gt;</translation>
</message>
<message>
<location filename="../dialogs/dbdialog.cpp" line="493"/>
@@ -2199,23 +2199,24 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dbobjectdialogs.cpp" line="282"/>
<source>Delete objects</source>
- <translation type="unfinished">删除对象</translation>
+ <translation>删除对象</translation>
</message>
<message>
<location filename="../dbobjectdialogs.cpp" line="283"/>
<source>Are you sure you want to delete following objects:
%1</source>
- <translation type="unfinished"></translation>
+ <translation>您确认要删除以下对象吗:
+%1</translation>
</message>
<message>
<location filename="../dbobjectdialogs.cpp" line="290"/>
<source>Cannot start transaction. Details: %1</source>
- <translation type="unfinished"></translation>
+ <translation>无法开始事务。详情:%1</translation>
</message>
<message>
<location filename="../dbobjectdialogs.cpp" line="327"/>
<source>Cannot commit transaction. Details: %1</source>
- <translation type="unfinished"></translation>
+ <translation>无法提交事务。详情:%1</translation>
</message>
</context>
<context>
@@ -2228,7 +2229,7 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dbtree/dbtree.ui" line="73"/>
<source>Filter by name</source>
- <translation>过滤名</translation>
+ <translation>按名称过滤</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="134"/>
@@ -2326,7 +2327,7 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="155"/>
<source>Populate table</source>
- <translation>填充表</translation>
+ <translation type="unfinished">填充表</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="156"/>
@@ -2336,7 +2337,7 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="157"/>
<source>Reset autoincrement sequence</source>
- <translation>重设 autoincrement</translation>
+ <translation type="unfinished">重设 autoincrement</translation>
</message>
<message>
<source>Create an index</source>
@@ -2415,117 +2416,117 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="140"/>
<source>&amp;Add a database</source>
- <translation type="unfinished"></translation>
+ <translation>添加数据库(&amp;A)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="141"/>
<source>&amp;Edit the database</source>
- <translation type="unfinished"></translation>
+ <translation>编辑数据库(&amp;E)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="142"/>
<source>&amp;Remove the database</source>
- <translation type="unfinished"></translation>
+ <translation>移除数据库(&amp;R)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="143"/>
<source>&amp;Connect to the database</source>
- <translation type="unfinished"></translation>
+ <translation>连接到数据库(&amp;C)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="144"/>
<source>&amp;Disconnect from the database</source>
- <translation type="unfinished"></translation>
+ <translation>断开数据库连接(&amp;D)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="146"/>
<source>&amp;Export the database</source>
- <translation type="unfinished"></translation>
+ <translation>导出该数据库(&amp;E)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="147"/>
<source>Con&amp;vert database type</source>
- <translation type="unfinished"></translation>
+ <translation>转换数据库类型(&amp;V)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="148"/>
<source>Vac&amp;uum</source>
- <translation type="unfinished"></translation>
+ <translation>清理(&amp;U)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="149"/>
<source>&amp;Integrity check</source>
- <translation type="unfinished"></translation>
+ <translation>检查完整性(&amp;I)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="150"/>
<source>Create a &amp;table</source>
- <translation type="unfinished"></translation>
+ <translation>新建表(&amp;T)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="151"/>
<source>Edit the t&amp;able</source>
- <translation type="unfinished"></translation>
+ <translation>编辑该表(&amp;A)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="152"/>
<source>Delete the ta&amp;ble</source>
- <translation type="unfinished"></translation>
+ <translation>删除该表(&amp;B)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="158"/>
<source>Create an &amp;index</source>
- <translation type="unfinished"></translation>
+ <translation>创建索引(&amp;I)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="159"/>
<source>Edit the i&amp;ndex</source>
- <translation type="unfinished"></translation>
+ <translation>编辑该索引(&amp;N)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="160"/>
<source>Delete the in&amp;dex</source>
- <translation type="unfinished"></translation>
+ <translation>删除该索引(&amp;D)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="161"/>
<source>Create a trig&amp;ger</source>
- <translation type="unfinished"></translation>
+ <translation>创建触发器(&amp;G)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="162"/>
<source>Edit the trigg&amp;er</source>
- <translation type="unfinished"></translation>
+ <translation>编辑该触发器(&amp;E)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="163"/>
<source>Delete the trigge&amp;r</source>
- <translation type="unfinished"></translation>
+ <translation>删除该触发器(&amp;R)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="164"/>
<source>Create a &amp;view</source>
- <translation type="unfinished"></translation>
+ <translation>创建视图(&amp;V)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="165"/>
<source>Edit the v&amp;iew</source>
- <translation type="unfinished"></translation>
+ <translation>编辑该视图(&amp;I)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="166"/>
<source>Delete the vi&amp;ew</source>
- <translation type="unfinished"></translation>
+ <translation>删除该视图(&amp;E)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="172"/>
<source>&amp;Refresh all database schemas</source>
- <translation type="unfinished"></translation>
+ <translation>刷新全部数据库的结构(&amp;R)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="173"/>
<source>Re&amp;fresh selected database schema</source>
- <translation type="unfinished"></translation>
+ <translation>刷新已选数据库的结构(&amp;F)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="174"/>
@@ -2536,12 +2537,12 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="179"/>
<source>Open file&apos;s directory</source>
- <translation type="unfinished"></translation>
+ <translation>打开文件目录</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="180"/>
<source>Execute SQL from file</source>
- <translation type="unfinished"></translation>
+ <translation>从文件执行 SQL</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="355"/>
@@ -2557,7 +2558,7 @@ Browsing other pages will be possible after the row counting is done.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="375"/>
<source>Generate query for table</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">生成对表的查询</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1086"/>
@@ -2590,23 +2591,24 @@ All objects from this group will be moved to parent group.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="1171"/>
<source>Are you sure you want to remove database &apos;%1&apos; from the list?</source>
- <translation type="unfinished"></translation>
+ <translation>您确认要移除数据库 %1 吗?</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1179"/>
<source>Are you sure you want to remove following databases from the list:
%1</source>
- <translation type="unfinished"></translation>
+ <translation>您确认要移除以下存在于列表中的数据库吗:
+%1</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1181"/>
<source>Remove database</source>
- <translation type="unfinished"></translation>
+ <translation>移除数据库</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1487"/>
<source>Vacuum (%1)</source>
- <translation type="unfinished"></translation>
+ <translation>清理(%1)</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1546"/>
@@ -2616,37 +2618,37 @@ All objects from this group will be moved to parent group.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="1566"/>
<source>Are you sure you want to delete all data from table(s): %1?</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">您想要删除表:%1的所有数据吗?</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1872"/>
<source>Could not execute SQL, because application has failed to start transaction: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">应用程序无法开始事务,因此无法执行 SQL:%1</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1886"/>
<source>Could not open file &apos;%1&apos; for reading: %2</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法以写模式打开文件 %1:%2</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1972"/>
<source>Could not execute SQL, because application has failed to commit the transaction: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">应用程序无法提交事务,因此无法执行 SQL:%1</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1976"/>
<source>Finished executing %1 queries in %2 seconds. %3 were not executed due to errors.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">在 %2 秒内完成执行 %1 个查询。 %3 个由于错误而没有被执行。</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1981"/>
<source>Finished executing %1 queries in %2 seconds.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">在 %2 秒内完成 %1 个查询。</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1987"/>
<source>Could not execute SQL due to error.</source>
- <translation type="unfinished"></translation>
+ <translation>由于错误,无法执行 SQL。</translation>
</message>
<message>
<source>Delete database</source>
@@ -2684,17 +2686,17 @@ All objects from this group will be moved to parent group.</source>
<message>
<location filename="../dbtree/dbtree.cpp" line="1537"/>
<source>Reset autoincrement</source>
- <translation>重置autoincrement</translation>
+ <translation type="unfinished">重置autoincrement</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1537"/>
<source>Are you sure you want to reset autoincrement value for table &apos;%1&apos;?</source>
- <translation>您确定要重设“%1”的autoincrement吗?</translation>
+ <translation type="unfinished">您确定要重设“%1”的autoincrement吗?</translation>
</message>
<message>
<location filename="../dbtree/dbtree.cpp" line="1544"/>
<source>An error occurred while trying to reset autoincrement value for table &apos;%1&apos;: %2</source>
- <translation>在重设表“%1”的autoincrement时出现错误:%2</translation>
+ <translation type="unfinished">在重设表“%1”的autoincrement时出现错误:%2</translation>
</message>
<message>
<source>Autoincrement value for table &apos;%1&apos; has been reset successfly.</source>
@@ -2861,7 +2863,7 @@ All objects from this group will be moved to parent group.</source>
<message>
<location filename="../dbtree/dbtreemodel.cpp" line="1213"/>
<source>Referenced tables</source>
- <translation>参照表</translation>
+ <translation type="unfinished">参照表</translation>
</message>
<message>
<location filename="../dbtree/dbtreemodel.cpp" line="1214"/>
@@ -2878,7 +2880,8 @@ All objects from this group will be moved to parent group.</source>
<location filename="../dbtree/dbtreemodel.cpp" line="1224"/>
<source>Following object already exists in the target database.
Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</source>
- <translation type="unfinished"></translation>
+ <translation>以下的对象已经存在于目标数据库中。
+请输入一个新的,唯一的名称,或按下 &apos;%1&apos; 终止操作:</translation>
</message>
<message>
<location filename="../dbtree/dbtreemodel.cpp" line="1237"/>
@@ -2913,7 +2916,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/ddlhistorywindow.cpp" line="124"/>
<source>DDL history</source>
- <translation>DDL历史</translation>
+ <translation>DDL 历史</translation>
</message>
</context>
<context>
@@ -2942,7 +2945,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/editorwindow.ui" line="42"/>
<source>Query</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">查询</translation>
</message>
<message>
<location filename="../windows/editorwindow.ui" line="115"/>
@@ -2963,7 +2966,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<location filename="../windows/editorwindow.cpp" line="176"/>
<location filename="../windows/editorwindow.cpp" line="178"/>
<source>SQL editor %1</source>
- <translation>SQL编辑器 %1</translation>
+ <translation>SQL 编辑器 %1</translation>
</message>
<message>
<location filename="../windows/editorwindow.cpp" line="336"/>
@@ -3046,12 +3049,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/editorwindow.cpp" line="574"/>
<source>Query finished in %1 second(s). Rows affected: %2</source>
- <translation type="unfinished"></translation>
+ <translation>查询在 %1 秒内完成。影响的行数:%2</translation>
</message>
<message>
<location filename="../windows/editorwindow.cpp" line="578"/>
<source>Query finished in %1 second(s).</source>
- <translation type="unfinished"></translation>
+ <translation>查询在 %1 秒内完成。</translation>
</message>
<message>
<location filename="../windows/editorwindow.cpp" line="692"/>
@@ -3061,7 +3064,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/editorwindow.cpp" line="692"/>
<source>Are you sure you want to erase the entire SQL execution history? This cannot be undone.</source>
- <translation>确定要删除全部的SQL执行历史吗?删除后不能恢复。</translation>
+ <translation>确定要删除全部的 SQL 执行历史吗?删除后不能恢复。</translation>
</message>
<message>
<location filename="../windows/editorwindow.cpp" line="717"/>
@@ -3071,12 +3074,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/editorwindow.cpp" line="738"/>
<source>No database selected in the SQL editor. Cannot create a view for unknown database.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">没有在 SQL 编辑器中选中的数据库。无法为未知数据库创建视图。</translation>
</message>
<message>
<location filename="../windows/editorwindow.cpp" line="768"/>
<source>Editor window &quot;%1&quot; has uncommitted data.</source>
- <translation type="unfinished"></translation>
+ <translation>编辑器“%1”里有未提交的数据库。</translation>
</message>
<message>
<source>Editor window &quot;%1&quot; has uncommited data.</source>
@@ -3106,57 +3109,57 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="14"/>
<source>Execute SQL from file</source>
- <translation type="unfinished"></translation>
+ <translation>从文件执行 SQL</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="23"/>
<source>Input file</source>
- <translation type="unfinished"></translation>
+ <translation>输入文件</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="29"/>
<source>Path to file</source>
- <translation type="unfinished"></translation>
+ <translation>文件路径</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="36"/>
<source>Browse for file</source>
- <translation type="unfinished"></translation>
+ <translation>浏览文件</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="53"/>
<source>Options</source>
- <translation type="unfinished">选项</translation>
+ <translation>选项</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="59"/>
<source>File encoding</source>
- <translation type="unfinished"></translation>
+ <translation>文件编码</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.ui" line="69"/>
<source>Skip failing SQL statements</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">跳过失败的 SQL statements</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.cpp" line="49"/>
<source>SQL scripts (*.sql);;All files (*)</source>
- <translation type="unfinished">SQL文件 (*.sql);;所有文件 (*)</translation>
+ <translation>SQL 脚本 (*.sql);;所有文件 (*)</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.cpp" line="50"/>
<source>Execute SQL file</source>
- <translation type="unfinished"></translation>
+ <translation>执行 SQL 文件</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.cpp" line="64"/>
<source>Please provide file to be executed.</source>
- <translation type="unfinished"></translation>
+ <translation>请提供一个文件以供执行。</translation>
</message>
<message>
<location filename="../dialogs/execfromfiledialog.cpp" line="71"/>
<source>Provided file does not exist or cannot be read.</source>
- <translation type="unfinished"></translation>
+ <translation>提供的文件不存在或无法读取。</translation>
</message>
</context>
<context>
@@ -3229,17 +3232,17 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/exportdialog.ui" line="175"/>
<source>Note, that exporting table indexes and triggers may be unsupported by some output formats.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">注意,某些输出格式可能不支持导出表索引与触发器。</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.ui" line="189"/>
<source>Select database objects to export</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">选择数据库对象进行导出</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.ui" line="202"/>
<source>Export data from tables</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">从表中导出数据</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.ui" line="212"/>
@@ -3332,42 +3335,42 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/exportdialog.cpp" line="207"/>
<source>Select at least one object to export.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">至少选择一个对象进行导出。</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.cpp" line="230"/>
<source>You must provide a file name to export to.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">您必须选择一个导出文件。</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.cpp" line="237"/>
<source>Path you provided is an existing directory. You cannot overwrite it.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">您提供的路径是一个存在的目录,您不能覆写它。</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.cpp" line="243"/>
<source>The directory &apos;%1&apos; does not exist.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">目录 &apos;%1&apos; 不存在。</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.cpp" line="249"/>
<source>The file &apos;%1&apos; exists and will be overwritten.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">文件“%1”存在且将被覆写。</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.cpp" line="429"/>
<source>All files (*)</source>
- <translation type="unfinished">所有文件 (*)</translation>
+ <translation>所有文件 (*)</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.cpp" line="432"/>
<source>Pick file to export to</source>
- <translation type="unfinished"></translation>
+ <translation>选择一个导出文件</translation>
</message>
<message>
<location filename="../dialogs/exportdialog.cpp" line="771"/>
<source>Internal error during export. This is a bug. Please report it.</source>
- <translation type="unfinished"></translation>
+ <translation>导出时发生了内部错误,这是一个 Bug,请反馈它。</translation>
</message>
</context>
<context>
@@ -3375,32 +3378,32 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="14"/>
<source>Execution errors</source>
- <translation type="unfinished"></translation>
+ <translation>执行错误</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="26"/>
<source>Following errors were encountered during execution of SQL statements from the file:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">从文件执行 SQL statements 期间遇到以下错误:</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="49"/>
<source>SQL</source>
- <translation type="unfinished"></translation>
+ <translation>SQL</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="54"/>
<source>Error</source>
- <translation type="unfinished">错误</translation>
+ <translation>错误</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="68"/>
<source>Statements that were executed successfully were commited.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">成功执行的 Statements 已被提交。</translation>
</message>
<message>
<location filename="../dialogs/fileexecerrorsdialog.ui" line="81"/>
<source>Statements that were executed successfully were rolled back.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">成功执行的 Statements 已被回滚。</translation>
</message>
</context>
<context>
@@ -3417,7 +3420,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../forms/sqlformatterplugin.ui" line="20"/>
<source>Active SQL formatter plugin</source>
- <translation>激活SQL语句格式化插件</translation>
+ <translation type="unfinished">激活 SQL 语句格式化插件</translation>
</message>
</context>
<context>
@@ -3426,13 +3429,13 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<location filename="../formview.cpp" line="247"/>
<source>Commit row</source>
<comment>form view</comment>
- <translation>提交</translation>
+ <translation type="unfinished">提交</translation>
</message>
<message>
<location filename="../formview.cpp" line="248"/>
<source>Rollback row</source>
<comment>form view</comment>
- <translation>回滚</translation>
+ <translation type="unfinished">回滚</translation>
</message>
<message>
<location filename="../formview.cpp" line="249"/>
@@ -3462,7 +3465,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<location filename="../formview.cpp" line="253"/>
<source>Insert new row</source>
<comment>form view</comment>
- <translation>新插入行</translation>
+ <translation>插入新行</translation>
</message>
<message>
<location filename="../formview.cpp" line="254"/>
@@ -3527,12 +3530,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<location filename="../windows/functionseditor.ui" line="313"/>
<location filename="../windows/functionseditor.cpp" line="426"/>
<source>Function implementation code:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">函数实现代码:</translation>
</message>
<message>
<location filename="../windows/functionseditor.ui" line="333"/>
<source>Final step implementation code:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">最终一步实现代码:</translation>
</message>
<message>
<location filename="../windows/functionseditor.cpp" line="54"/>
@@ -3612,7 +3615,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/functionseditor.cpp" line="426"/>
<source>Per step code:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">每一步的代码:</translation>
</message>
<message>
<location filename="../windows/functionseditor.cpp" line="432"/>
@@ -3628,7 +3631,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/functionseditor.cpp" line="631"/>
<source>Functions editor window has uncommitted modifications.</source>
- <translation type="unfinished"></translation>
+ <translation>函数编辑器窗口有未提交的更改。</translation>
</message>
</context>
<context>
@@ -3745,7 +3748,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/indexdialog.ui" line="88"/>
<source>On table:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">在表:</translation>
</message>
<message>
<location filename="../dialogs/indexdialog.ui" line="142"/>
@@ -3765,12 +3768,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/indexdialog.ui" line="70"/>
<source>Column</source>
- <translation type="unfinished">字段</translation>
+ <translation>字段</translation>
</message>
<message>
<location filename="../dialogs/indexdialog.ui" line="80"/>
<source>Collation</source>
- <translation type="unfinished"></translation>
+ <translation>排序规则</translation>
</message>
<message>
<location filename="../dialogs/indexdialog.ui" line="75"/>
@@ -3785,12 +3788,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/indexdialog.ui" line="108"/>
<source>Moves selected index column up in the order, making it more significant in the index.</source>
- <translation type="unfinished"></translation>
+ <translation>向上移动选中的索引,使它在索引中变得更重要。</translation>
</message>
<message>
<location filename="../dialogs/indexdialog.ui" line="118"/>
<source>Moves selected index column down in the order, making it less significant in the index.</source>
- <translation type="unfinished"></translation>
+ <translation>向下移动选中的索引,使它在索引中变得不重要。</translation>
</message>
<message>
<location filename="../dialogs/indexdialog.ui" line="149"/>
@@ -3825,7 +3828,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/indexdialog.cpp" line="207"/>
<source>Pick the table for the index.</source>
- <translation type="unfinished"></translation>
+ <translation>为索引选择一个表。</translation>
</message>
<message>
<location filename="../dialogs/indexdialog.cpp" line="208"/>
@@ -3835,7 +3838,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/indexdialog.cpp" line="209"/>
<source>Enter a valid condition.</source>
- <translation type="unfinished"></translation>
+ <translation>输入一个合法的条件。</translation>
</message>
<message>
<location filename="../dialogs/indexdialog.cpp" line="276"/>
@@ -3865,7 +3868,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<location filename="../dialogs/indexdialog.cpp" line="765"/>
<source>An error occurred while executing SQL statements:
%1</source>
- <translation>在执行SQL语句时发生了错误:%1</translation>
+ <translation>在执行 SQL 语句时发生了错误:%1</translation>
</message>
</context>
<context>
@@ -3908,7 +3911,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/indexexprcolumndialog.cpp" line="119"/>
<source>Invalid expression.</source>
- <translation type="unfinished"></translation>
+ <translation>无效的表达式。</translation>
</message>
</context>
<context>
@@ -3929,7 +3932,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../mainwindow.ui" line="81"/>
<source>Database toolbar</source>
- <translation>数据工具栏</translation>
+ <translation>数据库工具栏</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="92"/>
@@ -3949,7 +3952,8 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../mainwindow.ui" line="134"/>
<source>View toolbar</source>
- <translation>查看工具栏</translation>
+ <translatorcomment>查看这个词,在后面的翻译中翻译起来,有些地方的语句极其不通顺,故使用视图代替之。而且根据其菜单结构,主要是排布窗口,控件,比起查看,视图更佳</translatorcomment>
+ <translation>视图工具栏</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="109"/>
@@ -3969,12 +3973,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../mainwindow.cpp" line="123"/>
<source>Running in debug mode. Press %1 or use &apos;Help / Open debug console&apos; menu entry to open the debug console.</source>
- <translation type="unfinished"></translation>
+ <translation>正在以调试模式运行。按下 %1 或使用 帮助/打开调试控制台 菜单来打开调试控制台。</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="125"/>
<source>Running in debug mode. Debug messages are printed to the standard output.</source>
- <translation type="unfinished"></translation>
+ <translation>正在以调试模式运行。调试信息将会被输出在标准输出中。</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="190"/>
@@ -4064,7 +4068,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../mainwindow.cpp" line="258"/>
<source>Open CSS Console</source>
- <translation>打开CSS控制台</translation>
+ <translation type="unfinished">打开 CSS 控制台</translation>
</message>
<message>
<source>Report a bug</source>
@@ -4139,166 +4143,166 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../mainwindow.cpp" line="233"/>
<source>Open SQL &amp;editor</source>
- <translation type="unfinished"></translation>
+ <translation>打开 SQL 编辑器(&amp;E)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="234"/>
<source>Open DDL &amp;history</source>
- <translation type="unfinished"></translation>
+ <translation>打开数据库定义(DDL)历史(&amp;H)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="235"/>
<source>Open SQL &amp;functions editor</source>
- <translation type="unfinished"></translation>
+ <translation>打开 SQL 函数编辑器(&amp;F)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="236"/>
<source>Open &amp;collations editor</source>
- <translation type="unfinished"></translation>
+ <translation>打开排序规则编辑器(&amp;C)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="237"/>
<source>Open ex&amp;tension manager</source>
- <translation type="unfinished"></translation>
+ <translation>打开扩展管理器(&amp;T)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="238"/>
<source>&amp;Import</source>
- <translation type="unfinished"></translation>
+ <translation>导入(&amp;I)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="239"/>
<source>E&amp;xport</source>
- <translation type="unfinished"></translation>
+ <translation>导出(&amp;X)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="241"/>
<source>Open confi&amp;guration dialog</source>
- <translation type="unfinished"></translation>
+ <translation>打开配置对话框(&amp;G)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="243"/>
<source>&amp;Tile windows</source>
- <translation type="unfinished"></translation>
+ <translation>平铺窗口(&amp;T)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="244"/>
<source>Tile windows &amp;horizontally</source>
- <translation type="unfinished"></translation>
+ <translation>水平排列窗口(&amp;H)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="245"/>
<source>Tile windows &amp;vertically</source>
- <translation type="unfinished"></translation>
+ <translation>垂直排列窗口(&amp;V)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="246"/>
<source>&amp;Cascade windows</source>
- <translation type="unfinished"></translation>
+ <translation>层叠窗口(&amp;C)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="251"/>
<source>Close selected &amp;window</source>
- <translation type="unfinished"></translation>
+ <translation>关闭当前窗口(&amp;W)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="252"/>
<source>Close all windows &amp;but selected</source>
- <translation type="unfinished"></translation>
+ <translation>关闭其它窗口(&amp;B)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="253"/>
<source>Close &amp;all windows</source>
- <translation type="unfinished"></translation>
+ <translation>关闭全部窗口(&amp;A)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="254"/>
<source>Re&amp;store recently closed window</source>
- <translation type="unfinished"></translation>
+ <translation>恢复最近关闭的窗口(&amp;S)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="255"/>
<source>&amp;Rename selected window</source>
- <translation type="unfinished"></translation>
+ <translation>重命名当前窗口(&amp;R)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="259"/>
<source>Report a &amp;bug</source>
- <translation type="unfinished"></translation>
+ <translation>提交 Bug (&amp;B)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="260"/>
<source>Propose a new &amp;feature</source>
- <translation type="unfinished"></translation>
+ <translation>提交新功能建议(&amp;F)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="261"/>
<source>&amp;About</source>
- <translation type="unfinished"></translation>
+ <translation>关于(&amp;A)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="262"/>
<source>&amp;Licenses</source>
- <translation type="unfinished"></translation>
+ <translation>许可(&amp;L)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="263"/>
<source>Open home &amp;page</source>
- <translation type="unfinished"></translation>
+ <translation>访问主页(&amp;P)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="264"/>
<source>Open fo&amp;rum page</source>
- <translation type="unfinished"></translation>
+ <translation>访问论坛(&amp;R)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="265"/>
<source>User &amp;Manual</source>
- <translation type="unfinished"></translation>
+ <translation>用户手册(&amp;M)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="266"/>
<source>SQLite &amp;documentation</source>
- <translation type="unfinished"></translation>
+ <translation>SQLite 文档(&amp;D)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="267"/>
<source>Bugs and feature &amp;requests</source>
- <translation type="unfinished"></translation>
+ <translation>提交 Bug 与请求新功能(&amp;R)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="269"/>
<source>Check for &amp;updates</source>
- <translation type="unfinished"></translation>
+ <translation>检查更新(&amp;U)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="307"/>
<source>&amp;Database</source>
<comment>menubar</comment>
- <translation type="unfinished"></translation>
+ <translation>数据库(&amp;D)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="327"/>
<source>&amp;Structure</source>
<comment>menubar</comment>
- <translation type="unfinished"></translation>
+ <translation>结构(&amp;S)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="348"/>
<source>&amp;View</source>
<comment>menubar</comment>
- <translation type="unfinished"></translation>
+ <translation>视图(&amp;V)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="373"/>
<source>&amp;Tools</source>
<comment>menubar</comment>
- <translation type="unfinished"></translation>
+ <translation>工具(&amp;T)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="388"/>
<source>&amp;Help</source>
- <translation type="unfinished"></translation>
+ <translation>帮助(&amp;H)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="550"/>
@@ -4349,7 +4353,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../mainwindow.cpp" line="917"/>
<source>Could not add database %1 to list.</source>
- <translation>未能将数据%1添加到列表</translation>
+ <translation>未能将数据 %1 添加到列表</translation>
</message>
</context>
<context>
@@ -4361,7 +4365,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../mdiwindow.cpp" line="199"/>
<source>Uncommitted changes</source>
- <translation type="unfinished"></translation>
+ <translation>未提交的更改</translation>
</message>
<message>
<location filename="../mdiwindow.cpp" line="204"/>
@@ -4385,17 +4389,17 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditor.cpp" line="81"/>
<source>Configure editors for this data type</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">为数据类型设置编辑器</translation>
</message>
<message>
<location filename="../multieditor/multieditor.cpp" line="94"/>
<source>Open another tab</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">打开另一个选项卡</translation>
</message>
<message>
<location filename="../multieditor/multieditor.cpp" line="333"/>
<source>Data editor plugin &apos;%1&apos; not loaded, while it is defined for editing &apos;%1&apos; data type.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">数据编辑器插件 &apos;%1&apos; 没有被加载,尽管它被定义为编辑 &apos;%1&apos; 数据类型。</translation>
</message>
<message>
<location filename="../multieditor/multieditor.cpp" line="426"/>
@@ -4422,7 +4426,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditorbool.cpp" line="214"/>
<source>Boolean</source>
- <translation type="unfinished">布尔</translation>
+ <translation>布尔</translation>
</message>
</context>
<context>
@@ -4437,7 +4441,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditordate.cpp" line="86"/>
<source>Date</source>
- <translation type="unfinished">日期</translation>
+ <translation>日期</translation>
</message>
</context>
<context>
@@ -4452,7 +4456,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditordatetime.cpp" line="274"/>
<source>Date &amp; time</source>
- <translation type="unfinished">日期和时间</translation>
+ <translation>日期和时间</translation>
</message>
</context>
<context>
@@ -4467,7 +4471,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../multieditor/multieditorhex.cpp" line="91"/>
<source>Hex</source>
- <translation type="unfinished">十六进制</translation>
+ <translation>十六进制</translation>
</message>
</context>
<context>
@@ -4626,7 +4630,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/newversiondialog.ui" line="109"/>
<source>This application will be closed and the update installer will start to download and install all the updates.</source>
- <translation type="unfinished"></translation>
+ <translation>此应用将会被关闭,然后更新安装程序将会启动,下载并且安装所有更新。</translation>
</message>
<message>
<source>Current version</source>
@@ -4667,12 +4671,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/populateconfigdialog.ui" line="14"/>
<source>Populating configuration</source>
- <translation>配置填充</translation>
+ <translation type="unfinished">配置填充</translation>
</message>
<message>
<location filename="../dialogs/populateconfigdialog.cpp" line="54"/>
<source>Configuring &lt;b&gt;%1&lt;/b&gt; for column &lt;b&gt;%2&lt;/b&gt;</source>
- <translation>给字段 &lt;b&gt;%2&lt;/b&gt; 配置 &lt;b&gt;%1&lt;/b&gt;</translation>
+ <translation type="unfinished">给字段 &lt;b&gt;%2&lt;/b&gt; 配置 &lt;b&gt;%1&lt;/b&gt;</translation>
</message>
</context>
<context>
@@ -4700,7 +4704,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/populatedialog.ui" line="102"/>
<source>Number of rows to populate:</source>
- <translation>填充的行数:</translation>
+ <translation type="unfinished">填充的行数:</translation>
</message>
<message>
<location filename="../dialogs/populatedialog.cpp" line="42"/>
@@ -4811,32 +4815,32 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../datagrid/sqlqueryview.h" line="21"/>
<source>Data grid view</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">数据网格视图</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="22"/>
<source>Copy cell(s) contents to clipboard</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">复制单元格内容至剪贴板</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="23"/>
<source>Copy cell(s) contents together with header to clipboard</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">复制单元格内容与表头至剪贴板</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="25"/>
<source>Paste cell(s) contents from clipboard</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">从剪贴板粘贴单元格数据</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="27"/>
<source>Set empty value to selected cell(s)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">将选中的单元格设置为空值</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="28"/>
<source>Set NULL value to selected cell(s)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">将选中的单元格设置为 NULL</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="29"/>
@@ -4851,12 +4855,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../datagrid/sqlqueryview.h" line="31"/>
<source>Delete selected data row</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除选中的数据行</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="32"/>
<source>Insert new data row</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">插入新数据行</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.h" line="33"/>
@@ -4866,47 +4870,47 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dataview.cpp" line="633"/>
<source>Total pages available: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">可用页数:%1</translation>
</message>
<message>
<location filename="../dataview.cpp" line="643"/>
<source>Total rows loaded: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">已加载行数:%1</translation>
</message>
<message>
<location filename="../dataview.h" line="21"/>
<source>Data view (both grid and form)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">数据视图(网格 + 表格)</translation>
</message>
<message>
<location filename="../dataview.h" line="22"/>
<source>Refresh data</source>
- <translation type="unfinished"></translation>
+ <translation>刷新数据</translation>
</message>
<message>
<location filename="../dataview.h" line="23"/>
<source>Switch to grid view of the data</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">切换至数据的网格视图</translation>
</message>
<message>
<location filename="../dataview.h" line="24"/>
<source>Switch to form view of the data</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">切换至数据的表格视图</translation>
</message>
<message>
<location filename="../dbtree/dbtree.h" line="28"/>
<source>Database list</source>
- <translation type="unfinished">数据库列表</translation>
+ <translation>数据库列表</translation>
</message>
<message>
<location filename="../dbtree/dbtree.h" line="29"/>
<source>Delete selected item</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除选中项</translation>
</message>
<message>
<location filename="../dbtree/dbtree.h" line="30"/>
<source>Clear filter contents</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">清除筛选器内容</translation>
</message>
<message>
<location filename="../dbtree/dbtree.h" line="31"/>
@@ -4921,134 +4925,134 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dbtree/dbtree.h" line="33"/>
<source>Add database</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加数据库</translation>
</message>
<message>
<location filename="../dbtree/dbtree.h" line="34"/>
<source>Select all items</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">选中所有项</translation>
</message>
<message>
<location filename="../dbtree/dbtree.h" line="35"/>
<source>Copy selected item(s)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">复制选中项</translation>
</message>
<message>
<location filename="../dbtree/dbtree.h" line="36"/>
<location filename="../multieditor/multieditortext.h" line="15"/>
<location filename="../sqleditor.h" line="31"/>
<source>Paste from clipboard</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">从剪贴板粘贴</translation>
</message>
<message>
<location filename="../dbtree/dbtreeitemfactory.cpp" line="47"/>
<source>Tables</source>
- <translation type="unfinished"></translation>
+ <translation>表</translation>
</message>
<message>
<location filename="../dbtree/dbtreeitemfactory.cpp" line="52"/>
<source>Indexes</source>
- <translation type="unfinished"></translation>
+ <translation>索引</translation>
</message>
<message>
<location filename="../dbtree/dbtreeitemfactory.cpp" line="57"/>
<source>Triggers</source>
- <translation type="unfinished">触发器</translation>
+ <translation>触发器</translation>
</message>
<message>
<location filename="../dbtree/dbtreeitemfactory.cpp" line="62"/>
<source>Views</source>
- <translation type="unfinished"></translation>
+ <translation>视图</translation>
</message>
<message>
<location filename="../dbtree/dbtreeitemfactory.cpp" line="67"/>
<source>Columns</source>
- <translation type="unfinished">字段</translation>
+ <translation>字段</translation>
</message>
<message>
<location filename="../formview.h" line="16"/>
<source>Data form view</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">数据表格视图</translation>
</message>
<message>
<location filename="../formview.h" line="17"/>
<source>Commit changes for current row</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">提交当前行的更改</translation>
</message>
<message>
<location filename="../formview.h" line="18"/>
<source>Rollback changes for current row</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">回滚当前行的更改</translation>
</message>
<message>
<location filename="../formview.h" line="19"/>
<source>Go to first row on current page</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前往当前页的第一行</translation>
</message>
<message>
<location filename="../formview.h" line="20"/>
<source>Go to next row</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前往下一行</translation>
</message>
<message>
<location filename="../formview.h" line="21"/>
<source>Go to previous row</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前往上一行</translation>
</message>
<message>
<location filename="../formview.h" line="22"/>
<source>Go to last row on current page</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前往当前页的最后一行</translation>
</message>
<message>
<location filename="../formview.h" line="23"/>
<source>Insert new row</source>
- <translation type="unfinished">新插入行</translation>
+ <translation>插入新行</translation>
</message>
<message>
<location filename="../formview.h" line="24"/>
<source>Delete current row</source>
- <translation type="unfinished">删除当前行</translation>
+ <translation>删除当前行</translation>
</message>
<message>
<location filename="../mainwindow.h" line="44"/>
<source>Main window</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">主窗口</translation>
</message>
<message>
<location filename="../mainwindow.h" line="45"/>
<source>Open SQL editor</source>
- <translation type="unfinished">打开SQL编辑器</translation>
+ <translation>打开 SQL 编辑器</translation>
</message>
<message>
<location filename="../mainwindow.h" line="46"/>
<source>Previous window</source>
- <translation type="unfinished">上一个窗口</translation>
+ <translation>上一个窗口</translation>
</message>
<message>
<location filename="../mainwindow.h" line="47"/>
<source>Next window</source>
- <translation type="unfinished">下一个窗口</translation>
+ <translation>下一个窗口</translation>
</message>
<message>
<location filename="../mainwindow.h" line="48"/>
<source>Hide status area</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">隐藏状态栏</translation>
</message>
<message>
<location filename="../mainwindow.h" line="49"/>
<source>Open configuration dialog</source>
- <translation type="unfinished">打开配置对话框</translation>
+ <translation>打开配置对话框</translation>
</message>
<message>
<location filename="../mainwindow.h" line="50"/>
<source>Open Debug Console</source>
- <translation type="unfinished">打开调试终端</translation>
+ <translation>打开调试终端</translation>
</message>
<message>
<location filename="../mainwindow.h" line="51"/>
<source>Open CSS Console</source>
- <translation type="unfinished">打开CSS控制台</translation>
+ <translation>打开 CSS 控制台</translation>
</message>
<message>
<location filename="../multieditor/multieditortext.h" line="12"/>
@@ -5059,31 +5063,31 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<location filename="../multieditor/multieditortext.h" line="13"/>
<location filename="../sqleditor.h" line="29"/>
<source>Cut selected text</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">剪切选中文本</translation>
</message>
<message>
<location filename="../multieditor/multieditortext.h" line="14"/>
<location filename="../sqleditor.h" line="30"/>
<source>Copy selected text</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">复制选中文本</translation>
</message>
<message>
<location filename="../multieditor/multieditortext.h" line="16"/>
<location filename="../sqleditor.h" line="32"/>
<source>Delete selected text</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除选中文本</translation>
</message>
<message>
<location filename="../multieditor/multieditortext.h" line="17"/>
<location filename="../sqleditor.h" line="34"/>
<source>Undo</source>
- <translation type="unfinished">撤销</translation>
+ <translation>撤销</translation>
</message>
<message>
<location filename="../multieditor/multieditortext.h" line="18"/>
<location filename="../sqleditor.h" line="35"/>
<source>Redo</source>
- <translation type="unfinished">恢复</translation>
+ <translation>重做</translation>
</message>
<message>
<location filename="../sqleditor.h" line="28"/>
@@ -5093,17 +5097,17 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../sqleditor.h" line="33"/>
<source>Select whole editor contents</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">选中整个编辑器的内容</translation>
</message>
<message>
<location filename="../sqleditor.h" line="36"/>
<source>Save contents into a file</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">将内容保存至文件</translation>
</message>
<message>
<location filename="../sqleditor.h" line="37"/>
<source>Load contents from a file</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">从文件加载内容</translation>
</message>
<message>
<location filename="../sqleditor.h" line="38"/>
@@ -5128,17 +5132,17 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../sqleditor.h" line="42"/>
<source>Delete current line</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除当前行</translation>
</message>
<message>
<location filename="../sqleditor.h" line="43"/>
<source>Request code assistant</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">请求代码辅助</translation>
</message>
<message>
<location filename="../sqleditor.h" line="44"/>
<source>Format contents</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">格式化内容</translation>
</message>
<message>
<location filename="../sqleditor.h" line="45"/>
@@ -5168,18 +5172,18 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../uiutils.cpp" line="32"/>
<source>All SQLite databases</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">所有 SQLite 数据库</translation>
</message>
<message>
<location filename="../uiutils.cpp" line="35"/>
<source>All files</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">所有文件</translation>
</message>
<message>
<location filename="../uiutils.cpp" line="39"/>
<location filename="../uiutils.cpp" line="41"/>
<source>Database file</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">数据库文件</translation>
</message>
<message>
<source>Delete selected entry</source>
@@ -5188,7 +5192,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/editorwindow.h" line="26"/>
<source>SQL editor window</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">SQL 编辑器窗口</translation>
</message>
<message>
<location filename="../windows/editorwindow.h" line="27"/>
@@ -5213,12 +5217,12 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/editorwindow.h" line="31"/>
<source>Go to next editor tab</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前往下一编辑器选项卡</translation>
</message>
<message>
<location filename="../windows/editorwindow.h" line="32"/>
<source>Go to previous editor tab</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前往上一编辑器选项卡</translation>
</message>
<message>
<location filename="../windows/editorwindow.h" line="33"/>
@@ -5238,27 +5242,27 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/tablewindow.h" line="31"/>
<source>Table window</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">表窗口</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="32"/>
<source>Refresh table structure</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新表结构</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="33"/>
<source>Add new column</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加新字段</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="34"/>
<source>Edit selected column</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑选中字段</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="35"/>
<source>Delete selected column</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除选中字段</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="36"/>
@@ -5268,77 +5272,77 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/tablewindow.h" line="37"/>
<source>Import data to the table</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">导入数据至表中</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="38"/>
<source>Add new table constraint</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加新的表约束</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="39"/>
<source>Edit selected table constraint</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑选中的表约束</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="40"/>
<source>Delete selected table constraint</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除选中的表约束</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="41"/>
<source>Refresh table index list</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新表索引列表</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="42"/>
<source>Add new index</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加新索引</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="43"/>
<source>Edit selected index</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑选中索引</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="44"/>
<source>Delete selected index</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除选中索引</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="45"/>
<source>Refresh table trigger list</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新表触发器列表</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="46"/>
<location filename="../windows/viewwindow.h" line="25"/>
<source>Add new trigger</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加新触发器</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="47"/>
<location filename="../windows/viewwindow.h" line="26"/>
<source>Edit selected trigger</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑选中触发器</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="48"/>
<location filename="../windows/viewwindow.h" line="27"/>
<source>Delete selected trigger</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除选中触发器</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="49"/>
<location filename="../windows/viewwindow.h" line="28"/>
<source>Go to next tab</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前往下一选项卡</translation>
</message>
<message>
<location filename="../windows/tablewindow.h" line="50"/>
<location filename="../windows/viewwindow.h" line="29"/>
<source>Go to previous tab</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前往上一选项卡</translation>
</message>
<message>
<location filename="../windows/viewwindow.h" line="23"/>
@@ -5348,7 +5352,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../windows/viewwindow.h" line="24"/>
<source>Refresh view trigger list</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新视图触发器列表</translation>
</message>
</context>
<context>
@@ -5360,7 +5364,7 @@ Please enter new, unique name, or press &apos;%1&apos; to abort the operation:</
<message>
<location filename="../dialogs/quitconfirmdialog.ui" line="14"/>
<source>Uncommitted changes</source>
- <translation type="unfinished"></translation>
+ <translation>未提交的更改</translation>
</message>
<message>
<location filename="../dialogs/quitconfirmdialog.ui" line="20"/>
@@ -5390,7 +5394,7 @@ Following items are pending:</source>
<message>
<location filename="../dialogs/searchtextdialog.ui" line="43"/>
<source>Search backwards</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">反向搜索</translation>
</message>
<message>
<location filename="../dialogs/searchtextdialog.ui" line="50"/>
@@ -5424,7 +5428,7 @@ find next</source>
<message>
<location filename="../dialogs/sortdialog.ui" line="14"/>
<source>Sort by columns</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">按字段排序</translation>
</message>
<message>
<location filename="../dialogs/sortdialog.ui" line="45"/>
@@ -5441,17 +5445,17 @@ find next</source>
<message>
<location filename="../dialogs/sortdialog.cpp" line="178"/>
<source>Sort by: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">按:%1 排序</translation>
</message>
<message>
<location filename="../dialogs/sortdialog.cpp" line="242"/>
<source>Move column up</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">上移字段</translation>
</message>
<message>
<location filename="../dialogs/sortdialog.cpp" line="243"/>
<source>Move column down</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">下移字段</translation>
</message>
</context>
<context>
@@ -5520,7 +5524,7 @@ find next</source>
<location filename="../sqleditor.cpp" line="133"/>
<source>Select file to save SQL</source>
<comment>sql editor</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">选择 SQL 要保存到的文件</translation>
</message>
<message>
<location filename="../sqleditor.cpp" line="134"/>
@@ -5591,7 +5595,7 @@ find next</source>
<message>
<location filename="../sqleditor.cpp" line="259"/>
<source>Saved SQL contents to file: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">保存 SQL 内容至文件:%1</translation>
</message>
<message>
<location filename="../sqleditor.cpp" line="453"/>
@@ -5611,12 +5615,12 @@ find next</source>
<message>
<location filename="../sqleditor.cpp" line="249"/>
<source>Could not open file &apos;%1&apos; for writing: %2</source>
- <translation type="unfinished"></translation>
+ <translation>无法以写模式打开文件 %1:%2</translation>
</message>
<message>
<location filename="../sqleditor.cpp" line="1097"/>
<source>SQL scripts (*.sql);;All files (*)</source>
- <translation type="unfinished">SQL文件 (*.sql);;所有文件 (*)</translation>
+ <translation>SQL文件 (*.sql);;所有文件 (*)</translation>
</message>
<message>
<location filename="../sqleditor.cpp" line="1098"/>
@@ -5626,7 +5630,7 @@ find next</source>
<message>
<location filename="../sqleditor.cpp" line="1108"/>
<source>Could not open file &apos;%1&apos; for reading: %2</source>
- <translation type="unfinished"></translation>
+ <translation>无法以读模式打开文件 %1:%2</translation>
</message>
<message>
<location filename="../sqleditor.cpp" line="1313"/>
@@ -5671,7 +5675,7 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryitemdelegate.cpp" line="53"/>
<source>The row is marked for deletion.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">该行被标记为删除。</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryitemdelegate.cpp" line="53"/>
@@ -5680,7 +5684,7 @@ find next</source>
<location filename="../datagrid/sqlqueryitemdelegate.cpp" line="356"/>
<location filename="../datagrid/sqlqueryitemdelegate.cpp" line="376"/>
<source>Cannot edit this cell. Details: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法编辑此单元格。详情:%1</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryitemdelegate.cpp" line="65"/>
@@ -5705,7 +5709,7 @@ find next</source>
<location filename="../datagrid/sqlquerymodel.cpp" line="85"/>
<location filename="../datagrid/sqlquerymodel.cpp" line="494"/>
<source>Only one query can be executed simultaneously.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">只允许同时执行一条查询。</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="376"/>
@@ -5730,7 +5734,7 @@ find next</source>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="118"/>
<source>Uncommitted data</source>
- <translation type="unfinished"></translation>
+ <translation>未提交的数据</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="119"/>
@@ -5740,12 +5744,12 @@ find next</source>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="430"/>
<source>An error occurred while committing the transaction: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">在提交事务时发生错误:%1</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="676"/>
<source>An error occurred while committing the data: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">在提交数据时发生错误:%1</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="987"/>
@@ -5756,12 +5760,12 @@ find next</source>
<location filename="../datagrid/sqlquerymodel.cpp" line="1165"/>
<location filename="../datagrid/sqlquerymodel.cpp" line="1222"/>
<source>Error while executing SQL query on database &apos;%1&apos;: %2</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">在数据库“%1”执行 SQL 查询时发生错误:%2</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="1219"/>
<source>Error while loading query results: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">在加载查询结果时出错:%1</translation>
</message>
<message>
<location filename="../datagrid/sqlquerymodel.cpp" line="1671"/>
@@ -5814,7 +5818,7 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="163"/>
<source>Edit value in editor</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">在编辑器中编辑数值</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="97"/>
@@ -5824,7 +5828,7 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="90"/>
<source>Copy with headers</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">带表头复制</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="98"/>
@@ -5834,12 +5838,12 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="99"/>
<source>Commit selected cells</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">提交选中单元格</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="100"/>
<source>Rollback selected cells</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">回滚选中单元格</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="105"/>
@@ -5889,7 +5893,7 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="417"/>
<source>table &apos;%1&apos;</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">表“%1”</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="441"/>
@@ -5899,12 +5903,12 @@ find next</source>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="680"/>
<source>Trim pasted text?</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">移除粘贴文本两端的空格?</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="681"/>
<source>The pasted text contains leading or trailing white space. Trim it automatically?</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">粘贴的文本两端含有空格。自动移除?</translation>
</message>
<message>
<location filename="../datagrid/sqlqueryview.cpp" line="776"/>
@@ -5921,7 +5925,7 @@ find next</source>
<message>
<location filename="../datagrid/sqltablemodel.cpp" line="82"/>
<source>Error while committing new row: %1</source>
- <translation type="unfinished"></translation>
+ <translation>提交新行时发生了错误:%1</translation>
</message>
<message>
<location filename="../datagrid/sqltablemodel.cpp" line="140"/>
@@ -5934,72 +5938,72 @@ find next</source>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="63"/>
<source>Filter extensions</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">筛选扩展</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="107"/>
<source>Leave empty to use default function</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">保持空白将使用默认函数</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="128"/>
<source>Extension file</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">扩展文件</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="135"/>
<source>Initialization function</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">初始化函数</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="151"/>
<source>Databases</source>
- <translation type="unfinished">数据库</translation>
+ <translation>数据库</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="157"/>
<source>Register in all databases</source>
- <translation type="unfinished">在所有数据库中注册</translation>
+ <translation>在所有数据库中注册</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.ui" line="164"/>
<source>Register in following databases:</source>
- <translation type="unfinished">在下列数据库中注册:</translation>
+ <translation>在下列数据库中注册:</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="43"/>
<source>Extension manager window has uncommitted modifications.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">扩展管理窗口有未提交的更改。</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="64"/>
<source>Extension manager</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">扩展管理器</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="69"/>
<source>Commit all extension changes</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">提交所有扩展改变</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="70"/>
<source>Rollback all extension changes</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">回滚所有扩展改变</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="72"/>
<source>Add new extension</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加新的扩展</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="73"/>
<source>Remove selected extension</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">移除选中的扩展</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="75"/>
<source>Editing extensions manual</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">手动编辑扩展</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="235"/>
@@ -6009,7 +6013,7 @@ find next</source>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="241"/>
<source>Unable to load extension: %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法加载扩展:%1</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="355"/>
@@ -6019,7 +6023,7 @@ find next</source>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="424"/>
<source>Dynamic link libraries (*.dll);;All files (*)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">动态链接库 (*.dll);;所有文件 (*)</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="426"/>
@@ -6029,17 +6033,17 @@ find next</source>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="428"/>
<source>Dynamic libraries (*.dylib);;All files (*)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">动态库 (*.dylib);;所有文件 (*)</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="430"/>
<source>All files (*)</source>
- <translation type="unfinished">所有文件 (*)</translation>
+ <translation>所有文件 (*)</translation>
</message>
<message>
<location filename="../windows/sqliteextensioneditor.cpp" line="432"/>
<source>Open file</source>
- <translation type="unfinished">打开文件</translation>
+ <translation>打开文件</translation>
</message>
</context>
<context>
@@ -6086,33 +6090,34 @@ find next</source>
<message>
<location filename="../constraints/tableforeignkeypanel.ui" line="29"/>
<source>Foreign table:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">外部表:</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.ui" line="48"/>
<source>SQLite 2 does not support foreign keys officially,
but it&apos;s okay to use them anyway.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">SQLite 2 不正式支持外键,
+但总之,可以使用外键。</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.ui" line="62"/>
<source>Columns</source>
- <translation type="unfinished">字段</translation>
+ <translation>字段</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.ui" line="77"/>
<source>Local column</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">本地字段</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.ui" line="90"/>
<source>Foreign column</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">外部字段</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.ui" line="126"/>
<source>Reactions</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">响应</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.ui" line="165"/>
@@ -6127,33 +6132,33 @@ but it&apos;s okay to use them anyway.</source>
<message>
<location filename="../constraints/tableforeignkeypanel.ui" line="190"/>
<source>Constraint name</source>
- <translation type="unfinished">约束名称</translation>
+ <translation>约束名称</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.cpp" line="53"/>
<source>Pick the foreign column.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">选择一个外部字段。</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.cpp" line="65"/>
<source>Pick the foreign table.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">选择一个外部表。</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.cpp" line="66"/>
<source>Select at least one foreign column.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">请至少选择一个外部字段。</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.cpp" line="67"/>
<source>Enter a name of the constraint.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">输入一个约束的名称。</translation>
</message>
<message>
<location filename="../constraints/tableforeignkeypanel.cpp" line="210"/>
<source>Foreign column</source>
<comment>table constraints</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">外部字段</translation>
</message>
</context>
<context>
@@ -6171,7 +6176,7 @@ but it&apos;s okay to use them anyway.</source>
<message>
<location filename="../constraints/tablepkanduniquepanel.ui" line="84"/>
<source>Collation</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">排序规则</translation>
</message>
<message>
<location filename="../constraints/tablepkanduniquepanel.ui" line="109"/>
@@ -6186,7 +6191,7 @@ but it&apos;s okay to use them anyway.</source>
<message>
<location filename="../constraints/tablepkanduniquepanel.ui" line="145"/>
<source>Autoincrement</source>
- <translation>Autoincrement</translation>
+ <translation type="unfinished">Autoincrement</translation>
</message>
<message>
<location filename="../constraints/tablepkanduniquepanel.ui" line="167"/>
@@ -6196,18 +6201,18 @@ but it&apos;s okay to use them anyway.</source>
<message>
<location filename="../constraints/tablepkanduniquepanel.ui" line="174"/>
<source>Constraint name</source>
- <translation type="unfinished">约束名称</translation>
+ <translation>约束名称</translation>
</message>
<message>
<location filename="../constraints/tablepkanduniquepanel.ui" line="199"/>
<source>On conflict</source>
- <translation type="unfinished"></translation>
+ <translation>当冲突时</translation>
</message>
<message>
<location filename="../constraints/tablepkanduniquepanel.cpp" line="87"/>
<source>Collate</source>
<comment>table constraints</comment>
- <translation type="unfinished">排序规则</translation>
+ <translation>排序规则</translation>
</message>
<message>
<location filename="../constraints/tablepkanduniquepanel.cpp" line="94"/>
@@ -6223,7 +6228,7 @@ but it&apos;s okay to use them anyway.</source>
<message>
<location filename="../constraints/tablepkanduniquepanel.cpp" line="171"/>
<source>Enter a name of the constraint.</source>
- <translation type="unfinished"></translation>
+ <translation>输入一个约束的名称。</translation>
</message>
</context>
<context>
@@ -6232,33 +6237,33 @@ but it&apos;s okay to use them anyway.</source>
<location filename="../windows/tablestructuremodel.cpp" line="301"/>
<source>Name</source>
<comment>table structure columns</comment>
- <translation type="unfinished">名称</translation>
+ <translation>名称</translation>
</message>
<message>
<location filename="../windows/tablestructuremodel.cpp" line="303"/>
<source>Data type</source>
<comment>table structure columns</comment>
- <translation type="unfinished"></translation>
+ <translation>数据类型</translation>
</message>
<message>
<location filename="../windows/tablestructuremodel.cpp" line="305"/>
<source>Primary
Key</source>
<comment>table structure columns</comment>
- <translation type="unfinished"></translation>
+ <translation>主键</translation>
</message>
<message>
<location filename="../windows/tablestructuremodel.cpp" line="307"/>
<source>Foreign
Key</source>
<comment>table structure columns</comment>
- <translation type="unfinished"></translation>
+ <translation>外键</translation>
</message>
<message>
<location filename="../windows/tablestructuremodel.cpp" line="309"/>
<source>Unique</source>
<comment>table structure columns</comment>
- <translation type="unfinished">唯一</translation>
+ <translation>唯一</translation>
</message>
<message>
<location filename="../windows/tablestructuremodel.cpp" line="311"/>
@@ -6271,19 +6276,19 @@ Key</source>
<source>Not
NULL</source>
<comment>table structure columns</comment>
- <translation type="unfinished"></translation>
+ <translation>非 NULL</translation>
</message>
<message>
<location filename="../windows/tablestructuremodel.cpp" line="315"/>
<source>Collate</source>
<comment>table structure columns</comment>
- <translation type="unfinished">排序规则</translation>
+ <translation>排序规则</translation>
</message>
<message>
<location filename="../windows/tablestructuremodel.cpp" line="317"/>
<source>Default value</source>
<comment>table structure columns</comment>
- <translation type="unfinished"></translation>
+ <translation>默认值</translation>
</message>
</context>
<context>
@@ -6291,12 +6296,12 @@ NULL</source>
<message>
<location filename="../windows/tablewindow.ui" line="36"/>
<source>Structure</source>
- <translation type="unfinished">结构</translation>
+ <translation>结构</translation>
</message>
<message>
<location filename="../windows/tablewindow.ui" line="60"/>
<source>Table name:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">表名:</translation>
</message>
<message>
<location filename="../windows/tablewindow.ui" line="190"/>
@@ -6312,12 +6317,12 @@ NULL</source>
<message>
<location filename="../windows/tablewindow.ui" line="221"/>
<source>Indexes</source>
- <translation type="unfinished"></translation>
+ <translation>触发器</translation>
</message>
<message>
<location filename="../windows/tablewindow.ui" line="250"/>
<source>Triggers</source>
- <translation type="unfinished">触发器</translation>
+ <translation>触发器</translation>
</message>
<message>
<location filename="../windows/tablewindow.ui" line="282"/>
@@ -6328,13 +6333,13 @@ NULL</source>
<location filename="../windows/tablewindow.cpp" line="202"/>
<source>Export table</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">导出表</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="203"/>
<source>Import data to table</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">导入数据至表</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="204"/>
@@ -6346,50 +6351,50 @@ NULL</source>
<location filename="../windows/tablewindow.cpp" line="218"/>
<source>Refresh structure</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新结构</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="220"/>
<source>Commit structure changes</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">提交结构修改</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="221"/>
<source>Rollback structure changes</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">回滚结构改变</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="222"/>
<source>Add column</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation>添加字段</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="223"/>
<source>Edit column</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑字段</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="224"/>
<location filename="../windows/tablewindow.cpp" line="311"/>
<source>Delete column</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除字段</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="225"/>
<source>Move column up</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">向上移动字段</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="226"/>
<source>Move column down</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">向下移动字段</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="232"/>
@@ -6407,49 +6412,49 @@ NULL</source>
<location filename="../windows/tablewindow.cpp" line="236"/>
<source>Add table constraint</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加表约束条件</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="237"/>
<source>Edit table constraint</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑表约束</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="238"/>
<source>Delete table constraint</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除表约束</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="239"/>
<source>Move table constraint up</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">向上移动表约束</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="240"/>
<source>Move table constraint down</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">向下一移动表约束</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="242"/>
<source>Add table primary key</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加主键</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="243"/>
<source>Add table foreign key</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加外键</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="244"/>
<source>Add table unique constraint</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加表唯一约束</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="245"/>
@@ -6461,19 +6466,19 @@ NULL</source>
<location filename="../windows/tablewindow.cpp" line="263"/>
<source>Refresh index list</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新索引列表</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="265"/>
<source>Create index</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">创建索引</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="266"/>
<source>Edit index</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑索引</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="267"/>
@@ -6485,19 +6490,19 @@ NULL</source>
<location filename="../windows/tablewindow.cpp" line="273"/>
<source>Refresh trigger list</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新触发器列表</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="275"/>
<source>Create trigger</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">创建触发器</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="276"/>
<source>Edit trigger</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑触发器</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="277"/>
@@ -6509,7 +6514,7 @@ NULL</source>
<location filename="../windows/tablewindow.cpp" line="310"/>
<source>Are you sure you want to delete column &apos;%1&apos;?</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">您确定要删除字段“%1”吗?</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="338"/>
@@ -6527,12 +6532,12 @@ Would you like to proceed?</source>
<message>
<location filename="../windows/tablewindow.cpp" line="478"/>
<source>Could not load data for table %1. Error details: %2</source>
- <translation type="unfinished"></translation>
+ <translation>无法加载表 %1 的数据。错误详情:%2</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="597"/>
<source>Could not process the %1 table correctly. Unable to open a table window.</source>
- <translation type="unfinished"></translation>
+ <translation>无法正确处理表 %1。无法打开表窗口。</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="652"/>
@@ -6558,12 +6563,12 @@ Would you like to proceed?</source>
<location filename="../windows/tablewindow.cpp" line="699"/>
<location filename="../windows/tablewindow.cpp" line="701"/>
<source>New table %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">新表 %1</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="828"/>
<source>Committed changes for table &apos;%1&apos; successfully.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">成功提交表 &apos;%1&apos; 的修改。</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="832"/>
@@ -6573,12 +6578,12 @@ Would you like to proceed?</source>
<message>
<location filename="../windows/tablewindow.cpp" line="897"/>
<source>Autoincrement value for table &apos;%1&apos; has been reset successfully.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">表“%1”的auincrement重设成功。</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1270"/>
<source>Uncommitted changes</source>
- <translation type="unfinished"></translation>
+ <translation>未提交的更改</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1271"/>
@@ -6589,23 +6594,23 @@ Do you want to commit the structure, or do you want to go back to the structure
<message>
<location filename="../windows/tablewindow.cpp" line="1616"/>
<source>Table window &quot;%1&quot; has uncommitted structure modifications and data.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">表窗口“%1”有未提交的结构更改与数据。</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1618"/>
<source>Table window &quot;%1&quot; has uncommitted data.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">表窗口“%1”有未提交的数据。</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1620"/>
<source>Table window &quot;%1&quot; has uncommitted structure modifications.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">表窗口“%1”有未提交的结构更改。</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="866"/>
<source>Could not commit table structure. Error message: %1</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation>无法提交表结构。错误信息:%1</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="888"/>
@@ -6640,7 +6645,7 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../windows/tablewindow.cpp" line="986"/>
<source>Cannot create a table without at least one column.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法创建没有任何字段的表。</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1012"/>
@@ -6656,7 +6661,7 @@ Are you sure you want to create a table with blank name?</source>
<location filename="../windows/tablewindow.cpp" line="1169"/>
<source>Are you sure you want to delete table constraint &apos;%1&apos;?</source>
<comment>table window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">您确定要删除表约束“%1”吗?</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1170"/>
@@ -6681,24 +6686,24 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../windows/tablewindow.cpp" line="1274"/>
<source>Go back to structure tab</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">反汇结构选项卡</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1274"/>
<source>Commit modifications and browse data.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">提交修改并浏览数据。</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1455"/>
<source>Name</source>
<comment>table window indexes</comment>
- <translation type="unfinished">名称</translation>
+ <translation>名称</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1456"/>
<source>Unique</source>
<comment>table window indexes</comment>
- <translation type="unfinished">唯一</translation>
+ <translation>唯一</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1457"/>
@@ -6716,19 +6721,19 @@ Are you sure you want to create a table with blank name?</source>
<location filename="../windows/tablewindow.cpp" line="1512"/>
<source>Name</source>
<comment>table window triggers</comment>
- <translation type="unfinished">名称</translation>
+ <translation>名称</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1513"/>
<source>Event</source>
<comment>table window triggers</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">事件</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1514"/>
<source>Condition</source>
<comment>table window triggers</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">条件</translation>
</message>
<message>
<location filename="../windows/tablewindow.cpp" line="1515"/>
@@ -6752,12 +6757,12 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../dialogs/triggercolumnsdialog.ui" line="115"/>
<source>Select all</source>
- <translation type="unfinished">全选</translation>
+ <translation>全选</translation>
</message>
<message>
<location filename="../dialogs/triggercolumnsdialog.ui" line="128"/>
<source>Deselect all</source>
- <translation type="unfinished">全不选</translation>
+ <translation>全不选</translation>
</message>
</context>
<context>
@@ -6766,17 +6771,17 @@ Are you sure you want to create a table with blank name?</source>
<location filename="../dialogs/triggerdialog.ui" line="14"/>
<location filename="../dialogs/triggerdialog.ui" line="24"/>
<source>Trigger</source>
- <translation type="unfinished"></translation>
+ <translation>触发器</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="30"/>
<source>On table:</source>
- <translation type="unfinished"></translation>
+ <translation>在表:</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="40"/>
<source>Action:</source>
- <translation type="unfinished"></translation>
+ <translation>操作:</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="56"/>
@@ -6787,22 +6792,22 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../dialogs/triggerdialog.ui" line="59"/>
<source>Pre-condition:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">前提条件:</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="66"/>
<source>The scope is still not fully supported by the SQLite database.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">作用域仍没有被 SQLite 数据库完整支持。</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="73"/>
<source>Trigger name:</source>
- <translation type="unfinished"></translation>
+ <translation>触发器名称:</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="80"/>
<source>When:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">当:</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="87"/>
@@ -6812,12 +6817,12 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../dialogs/triggerdialog.ui" line="97"/>
<source>Scope:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">作用域:</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="104"/>
<source>Code:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">代码:</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.ui" line="111"/>
@@ -6827,12 +6832,12 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../dialogs/triggerdialog.ui" line="138"/>
<source>DDL</source>
- <translation type="unfinished">DDL</translation>
+ <translation>DDL</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.cpp" line="159"/>
<source>On view:</source>
- <translation type="unfinished"></translation>
+ <translation>在视图:</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.cpp" line="183"/>
@@ -6842,24 +6847,24 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../dialogs/triggerdialog.cpp" line="353"/>
<source>Enter a valid condition.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">输入一个合法的条件。</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.cpp" line="354"/>
<source>Enter a valid trigger code.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">输入合法的触发器代码。</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.cpp" line="428"/>
<source>Error</source>
<comment>trigger dialog</comment>
- <translation type="unfinished">错误</translation>
+ <translation>错误</translation>
</message>
<message>
<location filename="../dialogs/triggerdialog.cpp" line="428"/>
<source>An error occurred while executing SQL statements:
%1</source>
- <translation type="unfinished">在执行SQL语句“%1”时发生了错误。</translation>
+ <translation>在执行SQL语句“%1”时发生了错误</translation>
</message>
</context>
<context>
@@ -6895,12 +6900,12 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../windows/viewwindow.ui" line="60"/>
<source>View name:</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">视图名称:</translation>
</message>
<message>
<location filename="../windows/viewwindow.ui" line="113"/>
<source>Output column names</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">输出字段名称</translation>
</message>
<message>
<location filename="../windows/viewwindow.ui" line="160"/>
@@ -6916,7 +6921,7 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../windows/viewwindow.ui" line="202"/>
<source>DDL</source>
- <translation type="unfinished">DDL</translation>
+ <translation>DDL</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="108"/>
@@ -6932,36 +6937,36 @@ Are you sure you want to create a table with blank name?</source>
<message>
<location filename="../windows/viewwindow.cpp" line="127"/>
<source>Could not restore window &apos;%1&apos;, because database %2 could not be open.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法恢复窗口“%1”,因为数据库 %2 没有被打开。</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="136"/>
<source>Could not restore window &apos;%1&apos;, because the view %2 doesn&apos;t exist in the database %3.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法恢复窗口“%1”,因为视图 %2 不存在于数据库 %3 中。</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="162"/>
<location filename="../windows/viewwindow.cpp" line="164"/>
<source>New view %1</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">新视图 %1</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="320"/>
<source>Refresh the view</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新视图</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="322"/>
<source>Commit the view changes</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">提交视图更改</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="323"/>
<source>Rollback the view changes</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">回滚视图改变</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="327"/>
@@ -6977,75 +6982,75 @@ Are you sure you want to create a table with blank name?</source>
<location filename="../windows/viewwindow.cpp" line="334"/>
<source>Add column</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">添加字段</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="335"/>
<source>Edit column</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑字段</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="336"/>
<source>Delete column</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除字段</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="337"/>
<source>Move column up</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">向上移动字段</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="338"/>
<source>Move column down</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">向下移动字段</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="343"/>
<source>Refresh trigger list</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">刷新触发器列表</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="345"/>
<source>Create new trigger</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">创建新触发器</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="346"/>
<source>Edit selected trigger</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">编辑选中的触发器</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="347"/>
<source>Delete selected trigger</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">删除选中的触发器</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="368"/>
<source>View window &quot;%1&quot; has uncommitted structure modifications and data.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">视图“%1”有未提交的结构更改和数据。</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="370"/>
<source>View window &quot;%1&quot; has uncommitted data.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">视图“%1”有未提交的数据。</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="372"/>
<source>View window &quot;%1&quot; has uncommitted structure modifications.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">视图“%1”有未提交的结构更改。</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="581"/>
<source>Uncommitted changes</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">未提交的更改</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="582"/>
@@ -7056,7 +7061,7 @@ Do you want to commit the structure, or do you want to go back to the structure
<message>
<location filename="../windows/viewwindow.cpp" line="637"/>
<source>Committed changes for view &apos;%1&apos; successfully.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">成功提交视图“%1”的更改。</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="639"/>
@@ -7066,7 +7071,7 @@ Do you want to commit the structure, or do you want to go back to the structure
<message>
<location filename="../windows/viewwindow.cpp" line="569"/>
<source>Could not load data for view %1. Error details: %2</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法加载视图 %1 的数据。错误详情:%2</translation>
</message>
<message>
<source>Uncommited changes</source>
@@ -7075,18 +7080,18 @@ Do you want to commit the structure, or do you want to go back to the structure
<message>
<location filename="../windows/viewwindow.cpp" line="585"/>
<source>Go back to structure tab</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">回到结构选项卡</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="585"/>
<source>Commit modifications and browse data.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">提交更改并浏览数据。</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="650"/>
<source>Could not commit view changes. Error message: %1</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法提交视图更改。错误信息:%1</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="792"/>
@@ -7096,7 +7101,7 @@ Do you want to commit the structure, or do you want to go back to the structure
<message>
<location filename="../windows/viewwindow.cpp" line="792"/>
<source>Currently defined columns will be overriden. Do you want to continue?</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">当前定义的字段将会被覆写,您要继续吗?</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="815"/>
@@ -7119,18 +7124,18 @@ Do you want to commit the structure, or do you want to go back to the structure
<location filename="../windows/viewwindow.cpp" line="878"/>
<source>Condition</source>
<comment>view window triggers</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">条件</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="879"/>
<source>Details</source>
<comment>table window triggers</comment>
- <translation type="unfinished">详情</translation>
+ <translation>详情</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="919"/>
<source>Could not process the %1 view correctly. Unable to open a view window.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">无法正确处理视图 %1。无法打开视图窗口。</translation>
</message>
<message>
<location filename="../windows/viewwindow.cpp" line="966"/>
@@ -7170,7 +7175,7 @@ Would you like to proceed?</source>
<location filename="../windows/viewwindow.cpp" line="1027"/>
<source>View modification</source>
<comment>view window</comment>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">视图更改</translation>
</message>
</context>
<context>
@@ -7178,7 +7183,7 @@ Would you like to proceed?</source>
<message>
<location filename="../common/widgetcover.cpp" line="234"/>
<source>Interrupt</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">中断</translation>
</message>
</context>
</TS>
diff --git a/SQLiteStudio3/guiSQLiteStudio/uiconfig.h b/SQLiteStudio3/guiSQLiteStudio/uiconfig.h
index 0f2d17c..8f16a1b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/uiconfig.h
+++ b/SQLiteStudio3/guiSQLiteStudio/uiconfig.h
@@ -32,37 +32,6 @@ CFG_CATEGORIES(Ui,
CFG_ENTRY(QFont, StatusField, &Cfg::getDefaultItemViewFont)
)
- CFG_CATEGORY(Colors,
- CFG_ENTRY(QColor, SqlEditorParenthesisBg, Qt::green)
- CFG_ENTRY(QColor, SqlEditorCurrentLineBg, QColor(Qt::cyan).lighter(190))
- CFG_ENTRY(QColor, SqlEditorLineNumAreaBg, QColor(Qt::lightGray).lighter(120))
- CFG_ENTRY(QColor, SqlEditorValidObject, Qt::blue)
- CFG_ENTRY(QColor, SqlEditorForeground, Qt::black)
- CFG_ENTRY(QColor, SqlEditorStringFg, Qt::darkGreen)
- CFG_ENTRY(QColor, SqlEditorKeywordFg, Qt::black)
- CFG_ENTRY(QColor, SqlEditorBindParamFg, Qt::darkMagenta)
- CFG_ENTRY(QColor, SqlEditorBlobFg, Qt::darkCyan)
- CFG_ENTRY(QColor, SqlEditorCommentFg, Qt::darkGray)
- CFG_ENTRY(QColor, SqlEditorNumberFg, Qt::darkBlue)
- CFG_ENTRY(QColor, DataUncommittedError, Qt::red)
- CFG_ENTRY(QColor, DataUncommitted, Qt::blue)
- CFG_ENTRY(QColor, DataNullFg, Qt::gray)
- CFG_ENTRY(QColor, DataDeletedBg, Qt::gray)
- CFG_ENTRY(QColor, DbTreeLabelsFg, Qt::blue)
- CFG_ENTRY(QColor, StatusFieldInfoFg, Qt::darkBlue)
- CFG_ENTRY(QColor, StatusFieldWarnFg, Qt::black)
- CFG_ENTRY(QColor, StatusFieldErrorFg, Qt::red)
- CFG_ENTRY(QColor, JavaScriptFg, "#000000")
- CFG_ENTRY(QColor, JavaScriptComment, "#808080")
- CFG_ENTRY(QColor, JavaScriptNumber, "#008000")
- CFG_ENTRY(QColor, JavaScriptString, "#800000")
- CFG_ENTRY(QColor, JavaScriptOperator, "#808000")
- CFG_ENTRY(QColor, JavaScriptIdentifier, "#000020")
- CFG_ENTRY(QColor, JavaScriptKeyword, "#000080")
- CFG_ENTRY(QColor, JavaScriptBuiltIn, "#008080")
- CFG_ENTRY(QColor, JavaScriptMarker, "#ffff00")
- )
-
CFG_CATEGORY(DbList,
)
@@ -80,8 +49,10 @@ CFG_CATEGORIES(Ui,
CFG_ENTRY(bool, ShowRegularTableLabels, false)
CFG_ENTRY(bool, ShowVirtualTableLabels, true)
CFG_ENTRY(int, NumberOfRowsPerPage, 1000)
+ CFG_ENTRY(bool, LimitRowsForManyColumns, true)
CFG_ENTRY(QString, Style, &Cfg::getStyleDefaultValue)
CFG_ENTRY(Cfg::Session, Session, Cfg::Session())
+ CFG_ENTRY(bool, AllowMultipleSessions, false)
CFG_ENTRY(bool, RestoreSession, true)
CFG_ENTRY(bool, DontShowDdlPreview, false)
CFG_ENTRY(bool, OpenTablesOnData, false)
diff --git a/SQLiteStudio3/guiSQLiteStudio/uiutils.cpp b/SQLiteStudio3/guiSQLiteStudio/uiutils.cpp
index 72dde94..fbdc4b3 100644
--- a/SQLiteStudio3/guiSQLiteStudio/uiutils.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/uiutils.cpp
@@ -2,6 +2,7 @@
#include "services/config.h"
#include "common/widgetstateindicator.h"
#include "common/utils.h"
+#include "uiconfig.h"
#include <QObject>
#include <QCheckBox>
#include <QSpinBox>
@@ -14,6 +15,8 @@
#include <QPainter>
#include <QDesktopWidget>
#include <QApplication>
+#include <QStyle>
+#include <QScreen>
const QStringList pageSizes = {
"A4", "B5", "Letter", "Legal", "Executive", "A0", "A1", "A2", "A3", "A5", "A6", "A7", "A8", "A9", "B0", "B1",
@@ -29,9 +32,8 @@ QString getDbPath(bool newFileMode, const QString &startWith)
dir = CFG->get("dialogCache", "lastDbDir").toString();
QStringList filters;
- filters += QObject::tr("All SQLite databases")+" (*.db *.sdb *.sqlite *.db3 *.s3db *.sqlite3 *.sl3 *.db2 *.s2db *.sqlite2 *.sl2)";
+ filters += QObject::tr("All SQLite databases")+" (*.db *.sdb *.sqlite *.db3 *.s3db *.sqlite3 *.sl3)";
filters += "SQLite3 (*.db3 *.s3db *.sqlite3 *.sl3)";
- filters += "SQLite2 (*.db2 *.s2db *.sqlite2 *.sl2)";
filters += QObject::tr("All files")+" (*)";
QString filter = filters.join(";;");
@@ -87,7 +89,7 @@ QString convertPageSize(QPagedPaintDevice::PageSize size)
if (idx < 0 || idx >= pageSizesSize)
{
qDebug() << "Asked to convertPageSize() with page side enum value out of range:" << idx;
- return QString::null;
+ return QString();
}
return pageSizes[idx];
@@ -116,10 +118,31 @@ QPixmap addOpacity(const QPixmap& input, float opacity)
void limitDialogWidth(QDialog* dialog)
{
- dialog->setMaximumWidth(QApplication::desktop()->availableGeometry().width());
+ dialog->setMaximumWidth(QGuiApplication::primaryScreen()->availableGeometry().width());
}
void fixTextCursorSelectedText(QString& text)
{
text.replace("\u2029", "\n");
}
+
+QColor styleSyntaxStringColor()
+{
+ static const QColor stdAltColor = QColor(Qt::green);
+ if (QApplication::style()->standardPalette().text().color().lightness() >= 128)
+ return stdAltColor.lighter();
+ else
+ return stdAltColor.darker();
+}
+
+QBrush styleEditorLineColor()
+{
+ QPalette palette = QApplication::style()->standardPalette();
+ if (CFG_UI.General.Style.get().toLower() != "macintosh")
+ return palette.alternateBase();
+
+ if (palette.base().color().lightness() < 128)
+ return QBrush(palette.alternateBase().color().darker(300));
+
+ return palette.alternateBase();
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/uiutils.h b/SQLiteStudio3/guiSQLiteStudio/uiutils.h
index 455d97c..8163cd1 100644
--- a/SQLiteStudio3/guiSQLiteStudio/uiutils.h
+++ b/SQLiteStudio3/guiSQLiteStudio/uiutils.h
@@ -7,7 +7,7 @@
class QWidget;
-GUI_API_EXPORT QString getDbPath(bool newFileMode, const QString& startWith = QString::null);
+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);
@@ -19,6 +19,8 @@ GUI_API_EXPORT QPagedPaintDevice::PageSize convertPageSize(const QString& size);
GUI_API_EXPORT QPixmap addOpacity(const QPixmap& input, float opacity);
GUI_API_EXPORT void limitDialogWidth(QDialog* dialog);
GUI_API_EXPORT void fixTextCursorSelectedText(QString& text);
+GUI_API_EXPORT QColor styleSyntaxStringColor();
+GUI_API_EXPORT QBrush styleEditorLineColor();
#define UI_PROP_COLUMN "column_name"
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp
index 5d36683..5cf5be4 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp
@@ -1,6 +1,7 @@
#include "collationseditor.h"
#include "ui_collationseditor.h"
#include "common/unused.h"
+#include "common/compatibility.h"
#include "selectabledbmodel.h"
#include "dbtree/dbtree.h"
#include "dbtree/dbtreemodel.h"
@@ -163,9 +164,9 @@ void CollationsEditor::collationSelected(int row)
void CollationsEditor::clearEdits()
{
- ui->nameEdit->setText(QString::null);
- ui->codeEdit->setPlainText(QString::null);
- ui->langCombo->setCurrentText(QString::null);
+ ui->nameEdit->setText(QString());
+ ui->codeEdit->setPlainText(QString());
+ ui->langCombo->setCurrentText(QString());
ui->allDatabasesRadio->setChecked(true);
ui->langCombo->setCurrentIndex(-1);
}
@@ -350,7 +351,7 @@ void CollationsEditor::updateModified()
bool codeDiff = model->getCode(row) != ui->codeEdit->toPlainText();
bool langDiff = model->getLang(row) != ui->langCombo->currentText();
bool allDatabasesDiff = model->getAllDatabases(row) != ui->allDatabasesRadio->isChecked();
- bool dbDiff = getCurrentDatabases().toSet() != model->getDatabases(row).toSet(); // QSet to ignore order
+ bool dbDiff = toSet(getCurrentDatabases()) != toSet(model->getDatabases(row)); // QSet to ignore order
currentModified = (nameDiff || codeDiff || langDiff || allDatabasesDiff || dbDiff);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp
index 1144fda..becb060 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp
@@ -82,7 +82,7 @@ QVariant ConstraintTabModel::data(SqliteCreateTable::Constraint* constr, int col
case Columns::NAME:
{
if (role == Qt::DisplayRole)
- return stripObjName(constr->name, createTable->dialect);
+ return stripObjName(constr->name);
break;
}
@@ -124,7 +124,7 @@ QVariant ConstraintTabModel::data(SqliteCreateTable::Column::Constraint* constr,
case Columns::NAME:
{
if (role == Qt::DisplayRole)
- return stripObjName(constr->name, createTable->dialect);
+ return stripObjName(constr->name);
break;
}
@@ -186,9 +186,9 @@ QString ConstraintTabModel::getTypeLabel(SqliteCreateTable::Constraint::Type typ
case SqliteCreateTable::Constraint::FOREIGN_KEY:
return "FOREIGN KEY";
case SqliteCreateTable::Constraint::NAME_ONLY:
- return QString::null;
+ return QString();
}
- return QString::null;
+ return QString();
}
QString ConstraintTabModel::getTypeLabel(SqliteCreateTable::Column::Constraint::Type type) const
@@ -207,6 +207,8 @@ QString ConstraintTabModel::getTypeLabel(SqliteCreateTable::Column::Constraint::
return "DEFAULT";
case SqliteCreateTable::Column::Constraint::COLLATE:
return "COLLATE";
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return "GENERATED";
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return "FOREIGN KEY";
case SqliteCreateTable::Column::Constraint::NULL_:
@@ -214,7 +216,7 @@ QString ConstraintTabModel::getTypeLabel(SqliteCreateTable::Column::Constraint::
case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY:
break;
}
- return QString::null;
+ return QString();
}
QIcon ConstraintTabModel::getTypeIcon(SqliteCreateTable::Constraint::Type type) const
@@ -251,6 +253,8 @@ QIcon ConstraintTabModel::getTypeIcon(SqliteCreateTable::Column::Constraint::Typ
return ICONS.CONSTRAINT_DEFAULT;
case SqliteCreateTable::Column::Constraint::COLLATE:
return ICONS.CONSTRAINT_COLLATION;
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return ICONS.CONSTRAINT_GENERATED;
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return ICONS.CONSTRAINT_FOREIGN_KEY;
case SqliteCreateTable::Column::Constraint::NULL_:
@@ -274,9 +278,9 @@ QString ConstraintTabModel::getDetails(SqliteCreateTable::Constraint* constr) co
case SqliteCreateTable::Constraint::FOREIGN_KEY:
return getFkDetails(constr);
case SqliteCreateTable::Constraint::NAME_ONLY:
- return QString::null;
+ return QString();
}
- return QString::null;
+ return QString();
}
QString ConstraintTabModel::getDetails(SqliteCreateTable::Column::Constraint* constr) const
@@ -295,6 +299,8 @@ QString ConstraintTabModel::getDetails(SqliteCreateTable::Column::Constraint* co
return getDefaultDetails(constr);
case SqliteCreateTable::Column::Constraint::COLLATE:
return getCollateDetails(constr);
+ case SqliteCreateTable::Column::Constraint::GENERATED:
+ return getGeneratedDetails(constr);
case SqliteCreateTable::Column::Constraint::FOREIGN_KEY:
return getFkDetails(constr);
case SqliteCreateTable::Column::Constraint::NULL_:
@@ -302,7 +308,7 @@ QString ConstraintTabModel::getDetails(SqliteCreateTable::Column::Constraint* co
case SqliteCreateTable::Column::Constraint::DEFERRABLE_ONLY:
break;
}
- return QString::null;
+ return QString();
}
QString ConstraintTabModel::getPkDetails(SqliteCreateTable::Constraint* constr) const
@@ -365,6 +371,12 @@ QString ConstraintTabModel::getCollateDetails(SqliteCreateTable::Column::Constra
return getConstrDetails(constr, idx + 1);
}
+QString ConstraintTabModel::getGeneratedDetails(SqliteCreateTable::Column::Constraint* constr) const
+{
+ int idx = constr->tokens.indexOf(Token::KEYWORD, "GENERATED", Qt::CaseInsensitive);
+ return getConstrDetails(constr, idx + 1);
+}
+
QString ConstraintTabModel::getDefaultDetails(SqliteCreateTable::Column::Constraint* constr) const
{
int idx = constr->tokens.indexOf(Token::KEYWORD, "DEFAULT", Qt::CaseInsensitive);
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.h b/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.h
index f93415b..3292117 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.h
@@ -52,6 +52,7 @@ class GUI_API_EXPORT ConstraintTabModel : public QAbstractTableModel
QString getFkDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getNotNullDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getCollateDetails(SqliteCreateTable::Column::Constraint* constr) const;
+ QString getGeneratedDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getDefaultDetails(SqliteCreateTable::Column::Constraint* constr) const;
QString getConstrDetails(SqliteCreateTable::Constraint* constr, int tokenOffset) const;
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp
index cd3e135..f0f980d 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp
@@ -22,6 +22,7 @@
#include "themetuner.h"
#include "dialogs/bindparamsdialog.h"
#include "common/bindparam.h"
+#include "common/dbcombobox.h"
#include <QComboBox>
#include <QDebug>
#include <QStringListModel>
@@ -106,7 +107,7 @@ void EditorWindow::init()
Db* treeSelectedDb = DBTREE->getSelectedOpenDb();
if (treeSelectedDb)
- dbCombo->setCurrentIndex(dbComboModel->getIndexForDb(treeSelectedDb));
+ dbCombo->setCurrentDb(treeSelectedDb);
Db* currentDb = getCurrentDb();
resultsModel->setDb(currentDb);
@@ -230,11 +231,8 @@ QString EditorWindow::getQueryToExecute(bool doSelectCurrentQuery)
bool EditorWindow::setCurrentDb(Db *db)
{
- if (dbCombo->findText(db->getName()) == -1)
- return false;
-
- dbCombo->setCurrentText(db->getName());
- return true;
+ dbCombo->setCurrentDb(db);
+ return dbCombo->currentIndex() > -1;
}
void EditorWindow::setContents(const QString &sql)
@@ -319,7 +317,7 @@ void EditorWindow::changeEvent(QEvent *e)
Db* EditorWindow::getCurrentDb()
{
- return dbComboModel->getDb(dbCombo->currentIndex());
+ return dbCombo->currentDb();
}
void EditorWindow::updateResultsDisplayMode()
@@ -366,6 +364,8 @@ void EditorWindow::updateResultsDisplayMode()
void EditorWindow::createActions()
{
// SQL editor toolbar
+ actionMap[CURRENT_DB] = ui->toolBar->addWidget(dbCombo);
+ ui->toolBar->addSeparator();
createAction(EXEC_QUERY, ICONS.EXEC_QUERY, tr("Execute query"), this, SLOT(execQuery()), ui->toolBar, ui->sqlEdit);
createAction(EXPLAIN_QUERY, ICONS.EXPLAIN_QUERY, tr("Explain query"), this, SLOT(explainQuery()), ui->toolBar, ui->sqlEdit);
ui->toolBar->addSeparator();
@@ -383,8 +383,6 @@ void EditorWindow::createActions()
ui->toolBar->addAction(ui->sqlEdit->getAction(SqlEditor::FIND));
ui->toolBar->addAction(ui->sqlEdit->getAction(SqlEditor::REPLACE));
ui->toolBar->addSeparator();
- actionMap[CURRENT_DB] = ui->toolBar->addWidget(dbCombo);
- ui->toolBar->addSeparator();
ui->toolBar->addAction(staticActions[RESULTS_IN_TAB]);
ui->toolBar->addAction(staticActions[RESULTS_BELOW]);
createAction(PREV_DB, tr("Previous database"), this, SLOT(prevDb()), this);
@@ -404,10 +402,7 @@ void EditorWindow::createActions()
void EditorWindow::createDbCombo()
{
- dbCombo = new QComboBox(this);
- dbComboModel = new DbListModel(this);
- dbComboModel->setCombo(dbCombo);
- dbCombo->setModel(dbComboModel);
+ dbCombo = new DbComboBox(this);
dbCombo->setEditable(false);
dbCombo->setFixedWidth(100);
connect(dbCombo, SIGNAL(currentTextChanged(QString)), this, SLOT(dbChanged()));
@@ -424,17 +419,12 @@ void EditorWindow::setupDefShortcuts()
void EditorWindow::selectCurrentQuery(bool fallBackToPreviousIfNecessary)
{
- Dialect dialect = Dialect::Sqlite3;
- Db* db = getCurrentDb();
- if (db && db->isValid())
- dialect = db->getDialect();
-
QTextCursor cursor = ui->sqlEdit->textCursor();
int pos = cursor.position();
int queryStartPos;
QString contents = ui->sqlEdit->toPlainText();
QString query = getQueryWithPosition(contents, pos, &queryStartPos);
- TokenList tokens = Lexer::tokenize(query, dialect);
+ TokenList tokens = Lexer::tokenize(query);
tokens.trim();
tokens.trimRight(Token::OPERATOR, ";");
@@ -445,7 +435,7 @@ void EditorWindow::selectCurrentQuery(bool fallBackToPreviousIfNecessary)
if (pos > -1)
{
query = getQueryWithPosition(contents, pos, &queryStartPos);
- tokens = Lexer::tokenize(query, dialect);
+ tokens = Lexer::tokenize(query);
tokens.trim();
tokens.trimRight(Token::OPERATOR, ";");
}
@@ -504,14 +494,8 @@ void EditorWindow::explainQuery()
bool EditorWindow::processBindParams(QString& sql, QHash<QString, QVariant>& queryParams)
{
- // Determin dialect
- Dialect dialect = Dialect::Sqlite3;
- Db* db = getCurrentDb();
- if (db && db->isValid())
- dialect = db->getDialect();
-
// Get all bind parameters from the query
- TokenList tokens = Lexer::tokenize(sql, dialect);
+ TokenList tokens = Lexer::tokenize(sql);
TokenList bindTokens = tokens.filter(Token::BIND_PARAM);
// No bind tokens? Return fast.
@@ -522,18 +506,29 @@ bool EditorWindow::processBindParams(QString& sql, QHash<QString, QVariant>& que
static_qstring(paramTpl, ":arg%1");
QString arg;
QVector<BindParam*> bindParams;
+ QHash<QString, QString> namedBindParams;
BindParam* bindParam = nullptr;
+ bool isNamed = false;
+ bool nameAlreadyInList = false;
int i = 0;
for (const TokenPtr& token : bindTokens)
{
+ isNamed = (token->value != "?");
+ nameAlreadyInList = isNamed && namedBindParams.contains(token->value);
+
bindParam = new BindParam();
bindParam->position = i;
bindParam->originalName = token->value;
- bindParam->newName = paramTpl.arg(i);
- bindParams << bindParam;
- i++;
-
+ bindParam->newName = (isNamed && nameAlreadyInList) ? namedBindParams[token->value] : paramTpl.arg(i);
token->value = bindParam->newName;
+
+ if (!isNamed || !nameAlreadyInList)
+ bindParams << bindParam;
+
+ if (isNamed && !nameAlreadyInList)
+ namedBindParams[bindParam->originalName] = bindParam->newName;
+
+ i++;
}
// Show dialog to query user for values
@@ -719,7 +714,7 @@ void EditorWindow::exportResults()
}
QString query = lastSuccessfulQuery.isEmpty() ? getQueryToExecute() : lastSuccessfulQuery;
- QStringList queries = splitQueries(query, getCurrentDb()->getDialect(), false, true);
+ QStringList queries = splitQueries(query, false, true);
if (queries.size() == 0)
{
qWarning() << "No queries after split in EditorWindow::exportResults()";
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h
index 296a9e2..35a3b9b 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h
@@ -22,6 +22,7 @@ class IntValidator;
class FormView;
class SqlQueryItem;
class SqlEditor;
+class DbComboBox;
CFG_KEY_LIST(EditorWindow, QObject::tr("SQL editor window"),
CFG_KEY_ENTRY(EXEC_QUERY, Qt::Key_F9, QObject::tr("Execute query"))
@@ -128,8 +129,7 @@ class GUI_API_EXPORT EditorWindow : public MdiChild
Ui::EditorWindow *ui = nullptr;
SqlQueryModel* resultsModel = nullptr;
QHash<ActionGroup,QActionGroup*> actionGroups;
- QComboBox* dbCombo = nullptr;
- DbListModel* dbComboModel = nullptr;
+ DbComboBox* dbCombo = nullptr;
int sqlEditorNum = 1;
qint64 lastQueryHistoryId = 0;
QString lastSuccessfulQuery;
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp
index 9894098..3ac32ac 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp
@@ -2,6 +2,7 @@
#include "ui_functionseditor.h"
#include "common/unused.h"
#include "common/utils.h"
+#include "common/compatibility.h"
#include "uiutils.h"
#include "functionseditormodel.h"
#include "services/pluginmanager.h"
@@ -178,8 +179,8 @@ void FunctionsEditor::functionDeselected(int row)
}
else
{
- model->setInitCode(row, QString::null);
- model->setFinalCode(row, QString::null);
+ model->setInitCode(row, QString());
+ model->setFinalCode(row, QString());
}
if (!ui->undefArgsCheck->isChecked())
@@ -239,9 +240,9 @@ void FunctionsEditor::functionSelected(int row)
void FunctionsEditor::clearEdits()
{
- ui->nameEdit->setText(QString::null);
- ui->mainCodeEdit->setPlainText(QString::null);
- ui->langCombo->setCurrentText(QString::null);
+ ui->nameEdit->setText(QString());
+ ui->mainCodeEdit->setPlainText(QString());
+ ui->langCombo->setCurrentText(QString());
ui->undefArgsCheck->setChecked(true);
ui->argsList->clear();
ui->allDatabasesRadio->setChecked(true);
@@ -371,7 +372,7 @@ void FunctionsEditor::updateModified()
bool undefArgsDiff = model->getUndefinedArgs(row) != ui->undefArgsCheck->isChecked();
bool allDatabasesDiff = model->getAllDatabases(row) != ui->allDatabasesRadio->isChecked();
bool argDiff = getCurrentArgList() != model->getArguments(row);
- bool dbDiff = getCurrentDatabases().toSet() != model->getDatabases(row).toSet(); // QSet to ignore order
+ bool dbDiff = toSet(getCurrentDatabases()) != toSet(model->getDatabases(row)); // QSet to ignore order
bool typeDiff = model->getType(row) != getCurrentFunctionType();
currentModified = (nameDiff || codeDiff || typeDiff || langDiff || undefArgsDiff || allDatabasesDiff || argDiff || dbDiff ||
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp
index 623ebd8..8d6d87c 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp
@@ -87,7 +87,7 @@ void FunctionsEditorModel::setCode(int row, const QString& code)
QString FunctionsEditorModel::getCode(int row) const
{
- GETTER(functionList[row]->data.code, QString::null);
+ GETTER(functionList[row]->data.code, QString());
}
void FunctionsEditorModel::setFinalCode(int row, const QString& code)
@@ -97,7 +97,7 @@ void FunctionsEditorModel::setFinalCode(int row, const QString& code)
QString FunctionsEditorModel::getFinalCode(int row) const
{
- GETTER(functionList[row]->data.finalCode, QString::null);
+ GETTER(functionList[row]->data.finalCode, QString());
}
void FunctionsEditorModel::setInitCode(int row, const QString& code)
@@ -107,7 +107,7 @@ void FunctionsEditorModel::setInitCode(int row, const QString& code)
QString FunctionsEditorModel::getInitCode(int row) const
{
- GETTER(functionList[row]->data.initCode, QString::null);
+ GETTER(functionList[row]->data.initCode, QString());
}
void FunctionsEditorModel::setName(int row, const QString& newName)
@@ -117,7 +117,7 @@ void FunctionsEditorModel::setName(int row, const QString& newName)
QString FunctionsEditorModel::getName(int row) const
{
- GETTER(functionList[row]->data.name, QString::null);
+ GETTER(functionList[row]->data.name, QString());
}
void FunctionsEditorModel::setLang(int row, const QString& lang)
@@ -127,7 +127,7 @@ void FunctionsEditorModel::setLang(int row, const QString& lang)
QString FunctionsEditorModel::getLang(int row) const
{
- GETTER(functionList[row]->data.lang, QString::null);
+ GETTER(functionList[row]->data.lang, QString());
}
bool FunctionsEditorModel::getUndefinedArgs(int row) const
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp
index ca45eff..4351312 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp
@@ -11,6 +11,7 @@
#include "services/dbmanager.h"
#include "services/notifymanager.h"
#include "common/lazytrigger.h"
+#include "common/compatibility.h"
#include <QDesktopServices>
#include <QFileDialog>
#include <QSortFilterProxyModel>
@@ -173,8 +174,8 @@ void SqliteExtensionEditor::extensionSelected(int row)
void SqliteExtensionEditor::clearEdits()
{
- ui->fileEdit->setText(QString::null);
- ui->initEdit->setText(QString::null);
+ ui->fileEdit->setText(QString());
+ ui->initEdit->setText(QString());
ui->allDatabasesRadio->setChecked(true);
}
@@ -220,7 +221,7 @@ bool SqliteExtensionEditor::validateExtension(int row)
{
QString filePath = model->getFilePath(row);
QString initFunc = model->getInitFunction(row);
- return validateExtension(filePath, initFunc);
+ return validateExtension(filePath, initFunc, nullptr, nullptr, new QString);
}
bool SqliteExtensionEditor::validateExtension(const QString& filePath, const QString& initFunc, bool* fileOk, bool* initOk, QString* fileError)
@@ -388,7 +389,7 @@ void SqliteExtensionEditor::updateModified()
bool fileDiff = model->getFilePath(row) != ui->fileEdit->text();
bool initDiff = model->getInitFunction(row) != ui->initEdit->text();
bool allDatabasesDiff = model->getAllDatabases(row) != ui->allDatabasesRadio->isChecked();
- bool dbDiff = getCurrentDatabases().toSet() != model->getDatabases(row).toSet(); // QSet to ignore order
+ bool dbDiff = toSet(getCurrentDatabases()) != toSet(model->getDatabases(row)); // QSet to ignore order
currentModified = (fileDiff || initDiff || allDatabasesDiff || dbDiff);
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h
index c8ea3d0..5d81085 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h
@@ -61,9 +61,15 @@ class SqliteExtensionEditor : public MdiChild
void selectExtension(int row);
QStringList getCurrentDatabases() const;
bool tryToLoad(const QString& filePath, const QString& initFunc, QString* resultError);
- bool validateExtension(bool* fileOk = nullptr, bool* initOk = nullptr, QString* fileError = nullptr);
+ bool validateExtension(bool* fileOk = nullptr,
+ bool* initOk = nullptr,
+ QString* fileError = nullptr);
bool validateExtension(int row);
- bool validateExtension(const QString& filePath, const QString& initFunc, bool* fileOk = nullptr, bool* initOk = nullptr, QString* fileError = nullptr);
+ bool validateExtension(const QString& filePath,
+ const QString& initFunc,
+ bool* fileOk = nullptr,
+ bool* initOk = nullptr,
+ QString* fileError = nullptr);
void initStateForAll();
Ui::SqliteExtensionEditor *ui;
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp
index 0f95a98..74e7dd8 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp
@@ -46,7 +46,7 @@ QVariant TableConstraintsModel::data(const QModelIndex& index, int role) const
case Columns::NAME:
{
if (role == Qt::DisplayRole)
- return stripObjName(constr->name, createTable->dialect);
+ return stripObjName(constr->name);
break;
}
@@ -321,9 +321,9 @@ QString TableConstraintsModel::getTypeLabel(SqliteCreateTable::Constraint::Type
case SqliteCreateTable::Constraint::FOREIGN_KEY:
return "FOREIGN KEY";
case SqliteCreateTable::Constraint::NAME_ONLY:
- return QString::null;
+ return QString();
}
- return QString::null;
+ return QString();
}
QIcon TableConstraintsModel::getTypeIcon(SqliteCreateTable::Constraint::Type type) const
@@ -357,9 +357,9 @@ QString TableConstraintsModel::getDetails(SqliteCreateTable::Constraint* constr)
case SqliteCreateTable::Constraint::FOREIGN_KEY:
return getFkDetails(constr);
case SqliteCreateTable::Constraint::NAME_ONLY:
- return QString::null;
+ return QString();
}
- return QString::null;
+ return QString();
}
QString TableConstraintsModel::getPkDetails(SqliteCreateTable::Constraint* constr) const
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp
index 62b6613..41d6ed9 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp
@@ -1,10 +1,11 @@
#include "tablestructuremodel.h"
#include "iconmanager.h"
#include "common/unused.h"
-#include "uiconfig.h"
#include <QFont>
#include <QDebug>
#include <QMimeData>
+#include <QApplication>
+#include <QStyle>
TableStructureModel::TableStructureModel(QObject *parent) :
QAbstractTableModel(parent)
@@ -26,14 +27,7 @@ int TableStructureModel::columnCount(const QModelIndex& parent) const
if (createTable.isNull())
return 0;
- switch (createTable->dialect)
- {
- case Dialect::Sqlite3:
- return 9;
- case Dialect::Sqlite2:
- return 7;
- }
- return 0;
+ return 10;
}
QVariant TableStructureModel::data(const QModelIndex& index, int role) const
@@ -109,6 +103,13 @@ QVariant TableStructureModel::data(const QModelIndex& index, int role) const
return getColumnCollate(row);
}
+ case TableStructureModel::Columns::GENERATED:
+ {
+ if (role != Qt::DecorationRole)
+ break;
+
+ return getColumnGenerate(row);
+ }
case TableStructureModel::Columns::DEFAULT:
{
if (role == Qt::FontRole)
@@ -142,23 +143,12 @@ QVariant TableStructureModel::headerData(int section, Qt::Orientation orientatio
TableStructureModel::Columns TableStructureModel::getHeaderColumn(int colIdx) const
{
- if (!createTable.isNull() && createTable->dialect == Dialect::Sqlite2)
- {
- if (colIdx >= 3)
- colIdx++; // skip FK
-
- if (colIdx >= 7)
- colIdx++; // skip COLLATE
- }
return static_cast<Columns>(colIdx);
}
bool TableStructureModel::isValidColumnIdx(int colIdx) const
{
- if (!createTable.isNull() && createTable->dialect == Dialect::Sqlite2)
- return colIdx >= 0 && colIdx < 7;
-
- return colIdx >= 0 && colIdx < 9;
+ return colIdx >= 0 && colIdx < 10;
}
SqliteCreateTable::Column* TableStructureModel::getColumn(int colIdx) const
@@ -313,10 +303,12 @@ QString TableStructureModel::columnLabel(int column) const
return tr("Not\nNULL", "table structure columns");
case Columns::COLLATE:
return tr("Collate", "table structure columns");
+ case Columns::GENERATED:
+ return tr("Generated", "table structure columns");
case Columns::DEFAULT:
return tr("Default value", "table structure columns");
}
- return QString::null;
+ return QString();
}
QVariant TableStructureModel::getColumnName(int row) const
@@ -378,6 +370,23 @@ QVariant TableStructureModel::getColumnCollate(int row) const
return QVariant();
}
+QVariant TableStructureModel::getColumnGenerate(int row) const
+{
+ SqliteCreateTable::Column* column = getColumn(row);
+ SqliteCreateTable::Column::Constraint* constr = column->getConstraint(SqliteCreateTable::Column::Constraint::GENERATED);
+ if (!constr)
+ return QVariant();
+
+ switch (constr->generatedType) {
+ case SqliteCreateTable::Column::Constraint::GeneratedType::STORED:
+ return ICONS.CONSTRAINT_GENERATED_STORED;
+ case SqliteCreateTable::Column::Constraint::GeneratedType::VIRTUAL:
+ case SqliteCreateTable::Column::Constraint::GeneratedType::null:
+ break;
+ }
+ return ICONS.CONSTRAINT_GENERATED_VIRTUAL;
+}
+
QVariant TableStructureModel::getColumnDefaultValue(int row) const
{
QVariant value = getColumnDefault(row);
@@ -403,7 +412,7 @@ QVariant TableStructureModel::getColumnDefaultColor(int row) const
{
QVariant value = getColumnDefault(row);
if (value.isNull())
- return QColor(CFG_UI.Colors.DataNullFg);
+ return QApplication::style()->standardPalette().dark().color();
return QVariant();
}
@@ -494,6 +503,14 @@ bool TableStructureModel::isColumnCollate(SqliteCreateTable::Column* column) con
return false;
}
+bool TableStructureModel::isColumnGenerate(SqliteCreateTable::Column* column) const
+{
+ if (column->hasConstraint(SqliteCreateTable::Column::Constraint::GENERATED))
+ return true;
+
+ return false;
+}
+
void TableStructureModel::setCreateTable(SqliteCreateTable* value)
{
beginResetModel();
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.h b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.h
index e1cfa4e..088a964 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.h
@@ -47,6 +47,7 @@ class GUI_API_EXPORT TableStructureModel : public QAbstractTableModel
CHECK,
NOTNULL,
COLLATE,
+ GENERATED,
DEFAULT
};
@@ -54,7 +55,6 @@ class GUI_API_EXPORT TableStructureModel : public QAbstractTableModel
bool isValidColumnIdx(int colIdx) const;
bool doesColumnHasConstraint(SqliteCreateTable::Column* column, SqliteCreateTable::Column::Constraint::Type type);
QString columnLabel(int column) const;
- QString columnLabelForSqlite2(int column) const;
QVariant getColumnName(int row) const;
QVariant getColumnType(int row) const;
QVariant getColumnPk(int row) const;
@@ -63,6 +63,7 @@ class GUI_API_EXPORT TableStructureModel : public QAbstractTableModel
QVariant getColumnCheck(int row) const;
QVariant getColumnNotNull(int row) const;
QVariant getColumnCollate(int row) const;
+ QVariant getColumnGenerate(int row) const;
QVariant getColumnDefaultValue(int row) const;
QVariant getColumnDefaultFont(int row) const;
QVariant getColumnDefaultColor(int row) const;
@@ -73,6 +74,7 @@ class GUI_API_EXPORT TableStructureModel : public QAbstractTableModel
bool isColumnCheck(SqliteCreateTable::Column* column) const;
bool isColumnNotNull(SqliteCreateTable::Column* column) const;
bool isColumnCollate(SqliteCreateTable::Column* column) const;
+ bool isColumnGenerate(SqliteCreateTable::Column* column) const;
static const constexpr char* mimeType = "application/x-sqlitestudio-tablestructuremodel-row-index";
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
index 526ae1b..c9356d8 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
@@ -38,6 +38,7 @@
#include "dialogs/importdialog.h"
#include "dialogs/populatedialog.h"
#include "datagrid/sqlqueryitem.h"
+#include "common/dbcombobox.h"
#include <QMenu>
#include <QToolButton>
#include <QLabel>
@@ -164,6 +165,7 @@ void TableWindow::init()
initActions();
updateTabsOrder();
+ createDbCombo();
connect(dataModel, SIGNAL(executionSuccessful()), this, SLOT(executionSuccessful()));
connect(dataModel, SIGNAL(executionFailed(QString)), this, SLOT(executionFailed(QString)));
@@ -225,6 +227,9 @@ void TableWindow::createStructureActions()
createAction(MOVE_COLUMN_UP, ICONS.MOVE_UP, tr("Move column up", "table window"), this, SLOT(moveColumnUp()), ui->structureToolBar, ui->structureView);
createAction(MOVE_COLUMN_DOWN, ICONS.MOVE_DOWN, tr("Move column down", "table window"), this, SLOT(moveColumnDown()), ui->structureToolBar, ui->structureView);
ui->structureToolBar->addSeparator();
+ createAction(ADD_INDEX_STRUCT, ICONS.INDEX_ADD, tr("Create index", "table window"), this, SLOT(addIndex()), ui->structureToolBar, ui->structureView);
+ createAction(ADD_TRIGGER_STRUCT, ICONS.TRIGGER_ADD, tr("Create trigger", "table window"), this, SLOT(addTrigger()), ui->structureToolBar, ui->structureView);
+ ui->structureToolBar->addSeparator();
ui->structureToolBar->addAction(actionMap[IMPORT]);
ui->structureToolBar->addAction(actionMap[EXPORT]);
ui->structureToolBar->addAction(actionMap[POPULATE]);
@@ -289,12 +294,16 @@ void TableWindow::editColumn(const QModelIndex& idx)
SqliteCreateTable::Column* column = structureModel->getColumn(idx.row());
ColumnDialog columnDialog(db, this);
columnDialog.setColumn(column);
+ if (hasAnyPkDefined() && !column->hasConstraint(SqliteCreateTable::Column::Constraint::PRIMARY_KEY))
+ columnDialog.disableConstraint(ConstraintDialog::Constraint::PK);
+
if (columnDialog.exec() != QDialog::Accepted)
return;
SqliteCreateTable::Column* modifiedColumn = columnDialog.getModifiedColumn();
structureModel->replaceColumn(idx.row(), modifiedColumn);
resizeStructureViewColumns();
+ updateTableConstraintsToolbarState();
}
void TableWindow::delColumn(const QModelIndex& idx)
@@ -314,6 +323,7 @@ void TableWindow::delColumn(const QModelIndex& idx)
structureModel->delColumn(idx.row());
resizeStructureViewColumns();
+ updateTableConstraintsToolbarState();
}
void TableWindow::executeStructureChanges()
@@ -441,6 +451,7 @@ void TableWindow::updateTableConstraintsToolbarState()
actionMap[DEL_TABLE_CONSTRAINT]->setEnabled(anyColumn && validIdx);
actionMap[MOVE_CONSTRAINT_UP]->setEnabled(anyColumn && validIdx && !isFirst);
actionMap[MOVE_CONSTRAINT_DOWN]->setEnabled(anyColumn && validIdx && !isLast);
+ actionMap[ADD_TABLE_PK]->setEnabled(!hasAnyPkDefined());
}
void TableWindow::setupDefShortcuts()
@@ -480,21 +491,15 @@ void TableWindow::executionFailed(const QString& errorText)
void TableWindow::initDbAndTable()
{
- int totalConstrCols = 6;
- if (db->getVersion() == 2)
- {
- ui->withoutRowIdCheck->setVisible(false);
- totalConstrCols -= 2;
- }
-
- totalConstrCols += 2; // we start at 3rd column
- for (int colIdx = 2; colIdx < totalConstrCols; colIdx++)
+ for (int colIdx = 2; colIdx < 9; colIdx++)
ui->structureView->setItemDelegateForColumn(colIdx, constraintColumnsDelegate);
+ ui->dbCombo->setCurrentDb(db);
if (existingTable)
{
dataModel->setDb(db);
dataModel->setDatabaseAndTable(database, table);
+ ui->dbCombo->setDisabled(true);
}
ui->tableNameEdit->setText(table); // TODO no attached/temp db name support here
@@ -563,7 +568,6 @@ void TableWindow::initDbAndTable()
connect(ui->withoutRowIdCheck, SIGNAL(clicked()), this, SLOT(withOutRowIdChanged()));
- ui->ddlEdit->setSqliteVersion(db->getVersion());
parseDdl();
updateIndexes();
updateTriggers();
@@ -605,7 +609,6 @@ void TableWindow::parseDdl()
{
createTable = SqliteCreateTablePtr::create();
createTable->table = table;
- createTable->dialect = db->getDialect();
}
originalCreateTable = SqliteCreateTablePtr::create(*createTable);
structureModel->setCreateTable(createTable.data());
@@ -621,6 +624,13 @@ void TableWindow::parseDdl()
updateDdlTab();
}
+void TableWindow::createDbCombo()
+{
+ ui->dbCombo->setFixedWidth(100);
+ ui->dbCombo->setToolTip(tr("Database"));
+ connect(ui->dbCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(dbChanged()));
+}
+
void TableWindow::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
@@ -904,6 +914,9 @@ void TableWindow::addColumn()
ColumnDialog columnDialog(db, this);
columnDialog.setColumn(&column);
+ if (hasAnyPkDefined())
+ columnDialog.disableConstraint(ConstraintDialog::Constraint::PK);
+
if (columnDialog.exec() != QDialog::Accepted)
return;
@@ -913,6 +926,7 @@ void TableWindow::addColumn()
ui->structureView->setCurrentIndex(structureModel->index(structureModel->rowCount()-1, 0));
resizeStructureViewColumns();
+ updateTableConstraintsToolbarState();
}
void TableWindow::editColumn()
@@ -954,6 +968,9 @@ void TableWindow::moveColumnDown()
void TableWindow::addConstraint(ConstraintDialog::Constraint mode)
{
NewConstraintDialog dialog(mode, createTable.data(), db, this);
+ if (hasAnyPkDefined())
+ dialog.disableMode(ConstraintDialog::PK);
+
if (dialog.exec() != QDialog::Accepted)
return;
@@ -968,6 +985,7 @@ void TableWindow::addConstraint(ConstraintDialog::Constraint mode)
structureConstraintsModel->appendConstraint(tableConstr);
ui->tableConstraintsView->resizeColumnToContents(0);
ui->tableConstraintsView->resizeColumnToContents(1);
+ updateTableConstraintsToolbarState();
}
bool TableWindow::validate(bool skipWarning)
@@ -1060,7 +1078,7 @@ QString TableWindow::getCurrentIndex() const
int row = ui->indexList->currentRow();
QTableWidgetItem* item = ui->indexList->item(row, 0);
if (!item)
- return QString::null;
+ return QString();
return item->text();
}
@@ -1070,7 +1088,7 @@ QString TableWindow::getCurrentTrigger() const
int row = ui->triggerList->currentRow();
QTableWidgetItem* item = ui->triggerList->item(row, 0);
if (!item)
- return QString::null;
+ return QString();
return item->text();
}
@@ -1100,6 +1118,31 @@ int TableWindow::getStructureTabIdx() const
return ui->tabWidget->indexOf(ui->structureTab);
}
+bool TableWindow::hasAnyPkDefined() const
+{
+ if (structureConstraintsModel)
+ {
+ for (int i = 0, total = structureConstraintsModel->rowCount(); i < total; ++i)
+ {
+ SqliteCreateTable::Constraint* constraint = structureConstraintsModel->getConstraint(i);
+ if (constraint->type == SqliteCreateTable::Constraint::PRIMARY_KEY)
+ return true;
+ }
+ }
+
+ if (structureModel)
+ {
+ for (int i = 0, total = structureModel->rowCount(); i < total; ++i)
+ {
+ SqliteCreateTable::Column* column = structureModel->getColumn(i);
+ if (column->hasConstraint(SqliteCreateTable::Column::Constraint::PRIMARY_KEY))
+ return true;
+ }
+ }
+
+ return false;
+}
+
void TableWindow::updateDdlTab()
{
createTable->rebuildTokens();
@@ -1121,6 +1164,8 @@ void TableWindow::updateNewTableState()
actionMap[CREATE_SIMILAR]->setEnabled(existingTable);
actionMap[RESET_AUTOINCREMENT]->setEnabled(existingTable);
actionMap[REFRESH_STRUCTURE]->setEnabled(existingTable);
+ actionMap[ADD_INDEX_STRUCT]->setEnabled(existingTable);
+ actionMap[ADD_TRIGGER_STRUCT]->setEnabled(existingTable);
}
void TableWindow::addConstraint()
@@ -1173,6 +1218,7 @@ void TableWindow::delConstraint(const QModelIndex& idx)
structureConstraintsModel->delConstraint(idx.row());
ui->structureView->resizeColumnToContents(0);
+ updateTableConstraintsToolbarState();
}
void TableWindow::moveConstraintUp()
@@ -1309,7 +1355,7 @@ void TableWindow::withOutRowIdChanged()
if (!createTable)
return;
- createTable->withOutRowId = ui->withoutRowIdCheck->isChecked() ? QStringLiteral("ROWID") : QString::null;
+ createTable->withOutRowId = ui->withoutRowIdCheck->isChecked() ? QStringLiteral("ROWID") : QString();
updateDdlTab();
emit modifyStatusChanged();
}
@@ -1446,7 +1492,7 @@ void TableWindow::updateIndexes()
return;
SchemaResolver resolver(db);
- resolver.setIgnoreSystemObjects(true);
+ resolver.setIgnoreSystemObjects(false);
QList<SqliteCreateIndexPtr> indexes = resolver.getParsedIndexesForTable(database, table);
ui->indexList->setColumnCount(4);
@@ -1458,10 +1504,6 @@ void TableWindow::updateIndexes()
tr("Partial index condition", "table window indexes"),
});
- Dialect dialect= db->getDialect();
- if (dialect == Dialect::Sqlite2)
- ui->indexList->setColumnCount(3);
-
ui->indexList->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
QTableWidgetItem* item = nullptr;
@@ -1482,12 +1524,9 @@ void TableWindow::updateIndexes()
item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
ui->indexList->setItem(row, 2, item);
- if (dialect == Dialect::Sqlite3)
- {
- item = new QTableWidgetItem(index->where ? index->where->detokenize() : "");
- item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
- ui->indexList->setItem(row, 3, item);
- }
+ item = new QTableWidgetItem(index->where ? index->where->detokenize() : "");
+ item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
+ ui->indexList->setItem(row, 3, item);
row++;
}
@@ -1653,3 +1692,13 @@ void TableWindow::updateFont()
view->verticalHeader()->setDefaultSectionSize(fm.height() + 4);
}
}
+
+void TableWindow::dbChanged()
+{
+ disconnect(db, SIGNAL(dbObjectDeleted(QString,QString,DbObjectType)), this, SLOT(checkIfTableDeleted(QString,QString,DbObjectType)));
+
+ db = ui->dbCombo->currentDb();
+ dataModel->setDb(db);
+
+ connect(db, SIGNAL(dbObjectDeleted(QString,QString,DbObjectType)), this, SLOT(checkIfTableDeleted(QString,QString,DbObjectType)));
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
index f44af4f..fb4d67d 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
@@ -23,6 +23,7 @@ class WidgetCover;
class SqliteSyntaxHighlighter;
class CenteredIconItemDelegate;
class ConstraintTabModel;
+class DbComboBox;
namespace Ui {
class TableWindow;
@@ -76,6 +77,8 @@ class GUI_API_EXPORT TableWindow : public MdiChild
ADD_TABLE_CHECK,
MOVE_CONSTRAINT_UP,
MOVE_CONSTRAINT_DOWN,
+ ADD_INDEX_STRUCT,
+ ADD_TRIGGER_STRUCT,
EXPORT,
IMPORT,
POPULATE,
@@ -138,6 +141,7 @@ class GUI_API_EXPORT TableWindow : public MdiChild
void init();
void newTable();
void parseDdl();
+ void createDbCombo();
void initDbAndTable();
void setupCoverWidget();
void createStructureActions();
@@ -162,6 +166,7 @@ class GUI_API_EXPORT TableWindow : public MdiChild
void resizeStructureViewColumns();
int getDataTabIdx() const;
int getStructureTabIdx() const;
+ bool hasAnyPkDefined() const;
int newTableWindowNum = 1;
@@ -183,6 +188,7 @@ class GUI_API_EXPORT TableWindow : public MdiChild
bool modifyingThisTable = false;
CenteredIconItemDelegate* constraintColumnsDelegate = nullptr;
bool tabsMoving = false;
+ DbComboBox* dbCombo = nullptr;
private slots:
void executionSuccessful();
@@ -238,6 +244,7 @@ class GUI_API_EXPORT TableWindow : public MdiChild
void prevTab();
void updateTabsOrder();
void updateFont();
+ void dbChanged();
public slots:
void updateIndexes();
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui
index 14e278a..4ae8bdf 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui
@@ -55,6 +55,16 @@
<number>2</number>
</property>
<item>
+ <widget class="DbComboBox" name="dbCombo">
+ <property name="maximumSize">
+ <size>
+ <width>200</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="tableNameLabel">
<property name="text">
<string>Table name:</string>
@@ -317,6 +327,11 @@
<extends>QTableWidget</extends>
<header>common/exttablewidget.h</header>
</customwidget>
+ <customwidget>
+ <class>DbComboBox</class>
+ <extends>QComboBox</extends>
+ <header>common/dbcombobox.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
index c7ec7d8..2181934 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
@@ -45,8 +45,8 @@ ViewWindow::ViewWindow(Db* db, QWidget* parent) :
{
newView();
init();
+ ui->dbCombo->setCurrentDb(db);
applyInitialTab();
- updateDbRelatedUiElements();
}
ViewWindow::ViewWindow(const ViewWindow& win) :
@@ -59,7 +59,6 @@ ViewWindow::ViewWindow(const ViewWindow& win) :
init();
initView();
applyInitialTab();
- updateDbRelatedUiElements();
}
ViewWindow::ViewWindow(QWidget* parent, Db* db, const QString& database, const QString& view) :
@@ -72,7 +71,6 @@ ViewWindow::ViewWindow(QWidget* parent, Db* db, const QString& database, const Q
init();
initView();
applyInitialTab();
- updateDbRelatedUiElements();
}
ViewWindow::~ViewWindow()
@@ -94,6 +92,9 @@ void ViewWindow::changeEvent(QEvent *e)
QVariant ViewWindow::saveSession()
{
+ if (!db || DBLIST->isTemporary(db))
+ return QVariant();
+
QHash<QString,QVariant> sessionValue;
sessionValue["view"] = view;
sessionValue["db"] = db->getName();
@@ -139,7 +140,6 @@ bool ViewWindow::restoreSession(const QVariant& sessionValue)
initView();
applyInitialTab();
- updateDbRelatedUiElements();
return true;
}
@@ -192,7 +192,7 @@ void ViewWindow::setupDefShortcuts()
bool ViewWindow::restoreSessionNextTime()
{
- return existingView;
+ return existingView && db && !DBLIST->isTemporary(db);
}
QToolBar* ViewWindow::getToolBar(int toolbar) const
@@ -253,6 +253,7 @@ void ViewWindow::init()
updateOutputColumnsVisibility();
updateTabsOrder();
+ createDbCombo();
updateFont();
refreshTriggers();
@@ -268,6 +269,13 @@ void ViewWindow::updateAfterInit()
ui->tabWidget->setTabEnabled(ui->tabWidget->indexOf(tab), existingView);
}
+void ViewWindow::createDbCombo()
+{
+ ui->dbCombo->setFixedWidth(100);
+ ui->dbCombo->setToolTip(tr("Database"));
+ connect(ui->dbCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(dbChanged()));
+}
+
void ViewWindow::newView()
{
existingView = false;
@@ -283,14 +291,16 @@ void ViewWindow::initView()
if (!createView)
return; // error occured while parsing ddl, window will be closed
+ ui->dbCombo->setCurrentDb(db);
if (existingView)
{
dataModel->setDb(db);
dataModel->setQuery(originalCreateView->select->detokenize());
dataModel->setView(view);
+ ui->dbCombo->setDisabled(true);
}
-
ui->queryEdit->setDb(db);
+
ui->queryEdit->setPlainText(createView->select->detokenize());
if (createView->columns.size() > 0)
@@ -301,8 +311,6 @@ void ViewWindow::initView()
updateDdlTab();
- ui->ddlEdit->setSqliteVersion(db->getVersion());
-
refreshTriggers();
connect(db, SIGNAL(dbObjectDeleted(QString,QString,DbObjectType)), this, SLOT(checkIfViewDeleted(QString,QString,DbObjectType)));
@@ -454,7 +462,7 @@ QString ViewWindow::getCurrentTrigger() const
int row = ui->triggersList->currentRow();
QTableWidgetItem* item = ui->triggersList->item(row, 0);
if (!item)
- return QString::null;
+ return QString();
return item->text();
}
@@ -475,7 +483,7 @@ QString ViewWindow::getCurrentDdl() const
columnsStr = "(" + collectColumnNames().join(", ") + ")";
return ddlTpl.arg(
- wrapObjIfNeeded(ui->nameEdit->text(), db->getDialect()),
+ wrapObjIfNeeded(ui->nameEdit->text()),
columnsStr,
ui->queryEdit->toPlainText()
);
@@ -492,10 +500,9 @@ QStringList ViewWindow::indexedColumnsToNamesOnly(const QList<SqliteIndexedColum
QStringList ViewWindow::collectColumnNames() const
{
- Dialect dialect = db ? db->getDialect() : Dialect::Sqlite3;
QStringList cols;
for (int row = 0; row < ui->outputColumnsTable->count(); row++)
- cols << wrapObjIfNeeded(ui->outputColumnsTable->item(row)->text(), dialect);
+ cols << wrapObjIfNeeded(ui->outputColumnsTable->item(row)->text());
return cols;
}
@@ -627,17 +634,20 @@ void ViewWindow::changesSuccessfullyCommitted()
database = createView->database;
QString oldView = view;
view = createView->view;
+
+ if (!existingView)
+ notifyInfo(tr("View '%1' was committed successfully.").arg(view));
+ else if (oldView.compare(view, Qt::CaseInsensitive) == 0)
+ notifyInfo(tr("Committed changes for view '%1' successfully.").arg(view));
+ else
+ notifyInfo(tr("Committed changes for view '%1' (named before '%2') successfully.").arg(view, oldView));
+
existingView = true;
initView();
updateQueryToolbarStatus();
updateWindowTitle();
updateAfterInit();
- if (oldView.compare(view, Qt::CaseInsensitive) == 0)
- notifyInfo(tr("Committed changes for view '%1' successfully.").arg(view));
- else
- notifyInfo(tr("Committed changes for view '%1' (named before '%2') successfully.").arg(view, oldView));
-
DBTREE->refreshSchema(db);
}
@@ -675,6 +685,7 @@ void ViewWindow::prevTab()
void ViewWindow::dbClosedFinalCleanup()
{
+ db = nullptr;
dataModel->setDb(nullptr);
ui->queryEdit->setDb(nullptr);
structureExecutor->setDb(nullptr);
@@ -827,13 +838,6 @@ void ViewWindow::generateOutputColumns()
}
}
-void ViewWindow::updateDbRelatedUiElements()
-{
- bool enabled = db->getDialect() == Dialect::Sqlite3;
- outputColumnsCheck->setVisible(enabled);
- outputColumnsSeparator->setVisible(enabled);
-}
-
void ViewWindow::updateTabsOrder()
{
tabsMoving = true;
@@ -927,7 +931,6 @@ void ViewWindow::parseDdl()
{
createView = SqliteCreateViewPtr::create();
createView->view = view;
- createView->dialect = db->getDialect();
}
originalCreateView = SqliteCreateViewPtr::create(*createView);
@@ -972,7 +975,7 @@ bool ViewWindow::validate(bool skipWarnings)
// Rebuilding createView statement and validating it on the fly.
QString ddl = getCurrentDdl();
- Parser parser(db->getDialect());
+ Parser parser;
if (!parser.parse(ddl) || parser.getQueries().size() < 1)
{
notifyError(tr("The SELECT statement could not be parsed. Please correct the query and retry.\nDetails: %1").arg(parser.getErrorString()));
@@ -1005,7 +1008,7 @@ void ViewWindow::executeStructureChanges()
}
else
{
- Parser parser(db->getDialect());
+ Parser parser;
if (!parser.parse(theDdl))
{
qCritical() << "Could not re-parse the view for executing it:" << parser.getErrorString();
@@ -1069,3 +1072,14 @@ void ViewWindow::updateFont()
view->verticalHeader()->setDefaultSectionSize(fm.height() + 4);
}
}
+
+void ViewWindow::dbChanged()
+{
+ disconnect(db, SIGNAL(dbObjectDeleted(QString,QString,DbObjectType)), this, SLOT(checkIfViewDeleted(QString,QString,DbObjectType)));
+
+ db = ui->dbCombo->currentDb();
+ dataModel->setDb(db);
+ ui->queryEdit->setDb(db);
+
+ connect(db, SIGNAL(dbObjectDeleted(QString,QString,DbObjectType)), this, SLOT(checkIfViewDeleted(QString,QString,DbObjectType)));
+}
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h
index 1a8b5b3..a2ef4f7 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h
@@ -97,6 +97,7 @@ class GUI_API_EXPORT ViewWindow : public MdiChild
private:
void init();
void updateAfterInit();
+ void createDbCombo();
void newView();
void initView();
void setupCoverWidget();
@@ -163,10 +164,10 @@ class GUI_API_EXPORT ViewWindow : public MdiChild
void moveColumnDown();
void updateColumnButtons();
void generateOutputColumns();
- void updateDbRelatedUiElements();
void updateTabsOrder();
void triggerViewDoubleClicked(const QModelIndex& idx);
void updateFont();
+ void dbChanged();
public slots:
void refreshTriggers();
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui
index 8c17205..5f2acef 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui
@@ -55,6 +55,16 @@
<number>2</number>
</property>
<item>
+ <widget class="DbComboBox" name="dbCombo">
+ <property name="maximumSize">
+ <size>
+ <width>200</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="nameLabel">
<property name="text">
<string>View name:</string>
@@ -228,15 +238,20 @@
<container>1</container>
</customwidget>
<customwidget>
- <class>SqlEditor</class>
- <extends>QPlainTextEdit</extends>
- <header>sqleditor.h</header>
- </customwidget>
- <customwidget>
<class>ExtTableWidget</class>
<extends>QTableWidget</extends>
<header>common/exttablewidget.h</header>
</customwidget>
+ <customwidget>
+ <class>DbComboBox</class>
+ <extends>QComboBox</extends>
+ <header>common/dbcombobox.h</header>
+ </customwidget>
+ <customwidget>
+ <class>SqlEditor</class>
+ <extends>QPlainTextEdit</extends>
+ <header>sqleditor.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>