summaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/guiSQLiteStudio/windows
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2016-06-13 18:42:42 -0400
committerLibravatarUnit 193 <unit193@ubuntu.com>2016-06-13 18:42:42 -0400
commit5d9314f134ddd3dc4c853e398ac90ba247fb2e4f (patch)
tree5c457fc188036988d7abd29a3eb09931e406510f /SQLiteStudio3/guiSQLiteStudio/windows
parent8e640722c62692818ab840d50b3758f89a41a54e (diff)
Imported Upstream version 3.1.0upstream/3.1.0
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/windows')
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp26
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp145
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h14
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui18
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp311
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h30
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui92
7 files changed, 553 insertions, 83 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp
index 80c4567..1c817de 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp
@@ -128,14 +128,16 @@ QVariant TableStructureModel::data(const QModelIndex& index, int role) const
QVariant TableStructureModel::headerData(int section, Qt::Orientation orientation, int role) const
{
- if (role != Qt::DisplayRole)
- return QAbstractTableModel::headerData(section, orientation, role);
+ if (role == Qt::DisplayRole)
+ {
+ if (orientation == Qt::Vertical)
+ return section + 1;
- if (orientation == Qt::Vertical)
- return section + 1;
+ // Now it's horizontal orientation with DisplayRole
+ return columnLabel(section);
+ }
- // Now it's horizontal orientation with DisplayRole
- return columnLabel(section);
+ return QAbstractTableModel::headerData(section, orientation, role);
}
TableStructureModel::Columns TableStructureModel::getHeaderColumn(int colIdx) const
@@ -300,17 +302,17 @@ QString TableStructureModel::columnLabel(int column) const
case Columns::TYPE:
return tr("Data type", "table structure columns");
case Columns::PK:
- return "P";
+ return tr("Primary\nKey", "table structure columns");
case Columns::FK:
- return "F";
+ return tr("Foreign\nKey", "table structure columns");
case Columns::UNIQUE:
- return "U";
+ return tr("Unique", "table structure columns");
case Columns::CHECK:
- return "H";
+ return tr("Check", "table structure columns");
case Columns::NOTNULL:
- return "N";
+ return tr("Not\nNULL", "table structure columns");
case Columns::COLLATE:
- return "C";
+ return tr("Collate", "table structure columns");
case Columns::DEFAULT:
return tr("Default value", "table structure columns");
}
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
index cd1ba72..fd344e8 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp
@@ -33,9 +33,11 @@
#include "services/importmanager.h"
#include "dbobjectdialogs.h"
#include "dialogs/exportdialog.h"
+#include "common/centerediconitemdelegate.h"
#include "themetuner.h"
#include "dialogs/importdialog.h"
#include "dialogs/populatedialog.h"
+#include "datagrid/sqlqueryitem.h"
#include <QMenu>
#include <QToolButton>
#include <QLabel>
@@ -46,7 +48,6 @@
#include <QPushButton>
#include <QDebug>
#include <QStyleFactory>
-#include <datagrid/sqlqueryitem.h>
// TODO extend QTableView for columns and constraints, so they show full-row-width drop indicator,
// instead of single column drop indicator.
@@ -142,6 +143,9 @@ void TableWindow::init()
{
ui->setupUi(this);
ui->structureSplitter->setStretchFactor(0, 2);
+ ui->structureView->horizontalHeader()->setSectionsClickable(false);
+ ui->structureView->verticalHeader()->setSectionsClickable(false);
+ constraintColumnsDelegate = new CenteredIconItemDelegate(this);
#ifdef Q_OS_MACX
QStyle *fusion = QStyleFactory::create("Fusion");
@@ -159,6 +163,7 @@ void TableWindow::init()
ui->dataView->init(dataModel);
initActions();
+ updateTabsOrder();
connect(dataModel, SIGNAL(executionSuccessful()), this, SLOT(executionSuccessful()));
connect(dataModel, SIGNAL(executionFailed(QString)), this, SLOT(executionFailed(QString)));
@@ -168,6 +173,9 @@ void TableWindow::init()
connect(ui->tableNameEdit, SIGNAL(textChanged(QString)), this, SLOT(nameChanged()));
connect(ui->indexList, SIGNAL(itemSelectionChanged()), this, SLOT(updateIndexesState()));
connect(ui->triggerList, SIGNAL(itemSelectionChanged()), this, SLOT(updateTriggersState()));
+ connect(CFG_UI.General.DataTabAsFirstInTables, SIGNAL(changed(const QVariant&)), this, SLOT(updateTabsOrder()));
+ connect(ui->structureView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(structureViewDoubleClicked(const QModelIndex&)));
+ connect(ui->tableConstraintsView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(constraintsViewDoubleClicked(const QModelIndex&)));
structureExecutor = new ChainExecutor(this);
connect(structureExecutor, SIGNAL(success()), this, SLOT(changesSuccessfullyCommited()));
@@ -253,9 +261,9 @@ void TableWindow::createIndexActions()
createAction(REFRESH_INDEXES, ICONS.RELOAD, tr("Refresh index list", "table window"), this, SLOT(updateIndexes()), ui->indexToolBar, ui->indexList);
ui->indexToolBar->addSeparator();
createAction(ADD_INDEX, ICONS.INDEX_ADD, tr("Create index", "table window"), this, SLOT(addIndex()), ui->indexToolBar, ui->indexList);
- createAction(EDIT_INDEX, ICONS.INDEX_EDIT, tr("Edit index", "table window"), this, SLOT(editIndex()), ui->indexToolBar, ui->indexList);
+ createAction(EDIT_INDEX, ICONS.INDEX_EDIT, tr("Edit index", "table window"), this, SLOT(editCurrentIndex()), ui->indexToolBar, ui->indexList);
createAction(DEL_INDEX, ICONS.INDEX_DEL, tr("Delete index", "table window"), this, SLOT(delIndex()), ui->indexToolBar, ui->indexList);
- connect(ui->indexList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(editIndex()));
+ connect(ui->indexList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(indexViewDoubleClicked(QModelIndex)));
}
void TableWindow::createTriggerActions()
@@ -265,14 +273,14 @@ void TableWindow::createTriggerActions()
createAction(ADD_TRIGGER, ICONS.TRIGGER_ADD, tr("Create trigger", "table window"), this, SLOT(addTrigger()), ui->triggerToolBar, ui->triggerList);
createAction(EDIT_TRIGGER, ICONS.TRIGGER_EDIT, tr("Edit trigger", "table window"), this, SLOT(editTrigger()), ui->triggerToolBar, ui->triggerList);
createAction(DEL_TRIGGER, ICONS.TRIGGER_DEL, tr("Delete trigger", "table window"), this, SLOT(delTrigger()), ui->triggerToolBar, ui->triggerList);
- connect(ui->triggerList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(editTrigger()));
+ connect(ui->triggerList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(triggerViewDoubleClicked(QModelIndex)));
}
void TableWindow::editColumn(const QModelIndex& idx)
{
if (!idx.isValid())
{
- qWarning() << "Called TableWindow::editColumn() with invalid index.";
+ addColumn();
return;
}
@@ -352,6 +360,8 @@ void TableWindow::executeStructureChanges()
modifyingThisTable = true;
structureExecutor->setDb(db);
structureExecutor->setQueries(sqls);
+ structureExecutor->setDisableForeignKeys(true);
+ structureExecutor->setDisableObjectDropsDetection(true);
widgetCover->show();
structureExecutor->exec();
}
@@ -458,23 +468,27 @@ void TableWindow::setupDefShortcuts()
void TableWindow::executionSuccessful()
{
- modifyingThisTable = false;
dataLoaded = true;
}
void TableWindow::executionFailed(const QString& errorText)
{
- modifyingThisTable = false;
notifyError(tr("Could not load data for table %1. Error details: %2").arg(table).arg(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++)
+ ui->structureView->setItemDelegateForColumn(colIdx, constraintColumnsDelegate);
+
if (existingTable)
{
dataModel->setDb(db);
@@ -785,6 +799,8 @@ void TableWindow::commitStructure(bool skipWarning)
void TableWindow::changesSuccessfullyCommited()
{
+ modifyingThisTable = false;
+
QStringList sqls = structureExecutor->getQueries();
CFG->addDdlHistory(sqls.join("\n"), db->getName(), db->getPath());
@@ -804,6 +820,11 @@ void TableWindow::changesSuccessfullyCommited()
updateNewTableState();
updateWindowTitle();
+ if (oldTable.compare(table, Qt::CaseInsensitive) == 0 || oldTable.isEmpty())
+ notifyInfo(tr("Commited changes for table '%1' successfly.").arg(table));
+ else
+ notifyInfo(tr("Commited changes for table '%1' (named before '%2') successfly.").arg(table, oldTable));
+
DBTREE->refreshSchema(db);
if (tableModifier)
@@ -832,6 +853,7 @@ void TableWindow::changesFailedToCommit(int errorCode, const QString& errorText)
{
qDebug() << "TableWindow::changesFailedToCommit:" << errorCode << errorText;
+ modifyingThisTable = false;
widgetCover->hide();
notifyError(tr("Could not commit table structure. Error message: %1", "table window").arg(errorText));
}
@@ -1011,8 +1033,8 @@ TokenList TableWindow::indexColumnTokens(SqliteCreateIndexPtr index)
if (index->indexedColumns.size() == 0)
return TokenList();
- SqliteIndexedColumn* firstCol = index->indexedColumns.first();
- SqliteIndexedColumn* lastCol = index->indexedColumns.last();
+ SqliteOrderBy* firstCol = index->indexedColumns.first();
+ SqliteOrderBy* lastCol = index->indexedColumns.last();
if (firstCol->tokens.size() == 0)
return TokenList();
@@ -1048,9 +1070,9 @@ QString TableWindow::getCurrentTrigger() const
void TableWindow::applyInitialTab()
{
if (existingTable && !table.isNull() && CFG_UI.General.OpenTablesOnData.get())
- ui->tabWidget->setCurrentIndex(1);
+ ui->tabWidget->setCurrentIndex(getDataTabIdx());
else
- ui->tabWidget->setCurrentIndex(0);
+ ui->tabWidget->setCurrentIndex(getStructureTabIdx());
}
void TableWindow::resizeStructureViewColumns()
@@ -1060,6 +1082,16 @@ void TableWindow::resizeStructureViewColumns()
ui->structureView->resizeColumnToContents(c);
}
+int TableWindow::getDataTabIdx() const
+{
+ return ui->tabWidget->indexOf(ui->dataTab);
+}
+
+int TableWindow::getStructureTabIdx() const
+{
+ return ui->tabWidget->indexOf(ui->structureTab);
+}
+
void TableWindow::updateDdlTab()
{
createTable->rebuildTokens();
@@ -1103,7 +1135,10 @@ void TableWindow::delConstraint()
void TableWindow::editConstraint(const QModelIndex& idx)
{
if (!idx.isValid())
+ {
+ addConstraint();
return;
+ }
SqliteCreateTable::Constraint* constr = structureConstraintsModel->getConstraint(idx.row());
ConstraintDialog dialog(ConstraintDialog::EDIT, constr, createTable.data(), db, this);
@@ -1217,39 +1252,37 @@ void TableWindow::createSimilarTable()
void TableWindow::tabChanged(int newTab)
{
- switch (newTab)
+ if (tabsMoving)
+ return;
+
+ if (newTab == getDataTabIdx())
{
- case 1:
+ if (isModified())
{
- if (isModified())
- {
- int res = QMessageBox::question(this, tr("Uncommited changes"),
- tr("There are uncommited structure modifications. You cannot browse or edit data until you have "
- "table structure settled.\n"
- "Do you want to commit the structure, or do you want to go back to the structure tab?"),
- tr("Go back to structure tab"), tr("Commit modifications and browse data."));
-
- ui->tabWidget->setCurrentIndex(0);
- if (res == 1)
- commitStructure(true);
-
- break;
- }
+ int res = QMessageBox::question(this, tr("Uncommited changes"),
+ tr("There are uncommited structure modifications. You cannot browse or edit data until you have "
+ "table structure settled.\n"
+ "Do you want to commit the structure, or do you want to go back to the structure tab?"),
+ tr("Go back to structure tab"), tr("Commit modifications and browse data."));
- if (!dataLoaded)
- ui->dataView->refreshData();
+ ui->tabWidget->setCurrentIndex(0);
+ if (res == 1)
+ commitStructure(true);
- break;
+ return;
}
+
+ if (!dataLoaded)
+ ui->dataView->refreshData();
}
}
-void TableWindow::on_structureView_doubleClicked(const QModelIndex &index)
+void TableWindow::structureViewDoubleClicked(const QModelIndex &index)
{
editColumn(index);
}
-void TableWindow::on_tableConstraintsView_doubleClicked(const QModelIndex &index)
+void TableWindow::constraintsViewDoubleClicked(const QModelIndex &index)
{
editConstraint(index);
}
@@ -1280,7 +1313,7 @@ void TableWindow::addIndex()
updateIndexes();
}
-void TableWindow::editIndex()
+void TableWindow::editCurrentIndex()
{
QString index = getCurrentIndex();
if (index.isNull())
@@ -1291,6 +1324,22 @@ void TableWindow::editIndex()
updateIndexes();
}
+void TableWindow::indexViewDoubleClicked(const QModelIndex& idx)
+{
+ if (!idx.isValid())
+ {
+ addIndex();
+ return;
+ }
+
+ QString index = ui->indexList->item(idx.row(), 0)->text();
+
+ DbObjectDialogs dialogs(db, this);
+ dialogs.editIndex(index);
+ updateIndexes();
+}
+
+
void TableWindow::delIndex()
{
QString index = getCurrentIndex();
@@ -1313,7 +1362,25 @@ void TableWindow::editTrigger()
{
QString trigger = getCurrentTrigger();
if (trigger.isNull())
+ {
+ addTrigger();
+ return;
+ }
+
+ DbObjectDialogs dialogs(db, this);
+ dialogs.editTrigger(trigger);
+ updateTriggers();
+}
+
+void TableWindow::triggerViewDoubleClicked(const QModelIndex& idx)
+{
+ if (!idx.isValid())
+ {
+ addTrigger();
return;
+ }
+
+ QString trigger = ui->triggerList->item(idx.row(), 0)->text();
DbObjectDialogs dialogs(db, this);
dialogs.editTrigger(trigger);
@@ -1488,6 +1555,18 @@ void TableWindow::delColumn(const QString& columnName)
delColumn(colIdx);
}
+void TableWindow::updateTabsOrder()
+{
+ tabsMoving = true;
+ ui->tabWidget->removeTab(getDataTabIdx());
+ int idx = 1;
+ if (CFG_UI.General.DataTabAsFirstInTables.get())
+ idx = 0;
+
+ ui->tabWidget->insertTab(idx, ui->dataTab, tr("Data"));
+ tabsMoving = false;
+}
+
bool TableWindow::restoreSessionNextTime()
{
return existingTable && db && !DBLIST->isTemporary(db);
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
index 69f210b..d8738f1 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.h
@@ -21,6 +21,7 @@ class TableConstraintsModel;
class QProgressBar;
class WidgetCover;
class SqliteSyntaxHighlighter;
+class CenteredIconItemDelegate;
class ConstraintTabModel;
namespace Ui {
@@ -159,6 +160,8 @@ class GUI_API_EXPORT TableWindow : public MdiChild
QString getCurrentTrigger() const;
void applyInitialTab();
void resizeStructureViewColumns();
+ int getDataTabIdx() const;
+ int getStructureTabIdx() const;
int newTableWindowNum = 1;
@@ -178,6 +181,8 @@ class GUI_API_EXPORT TableWindow : public MdiChild
ChainExecutor* structureExecutor = nullptr;
TableModifier* tableModifier = nullptr;
bool modifyingThisTable = false;
+ CenteredIconItemDelegate* constraintColumnsDelegate = nullptr;
+ bool tabsMoving = false;
private slots:
void executionSuccessful();
@@ -215,12 +220,14 @@ class GUI_API_EXPORT TableWindow : public MdiChild
void updateTableConstraintsToolbarState();
void updateDdlTab();
void updateNewTableState();
- void on_structureView_doubleClicked(const QModelIndex &index);
- void on_tableConstraintsView_doubleClicked(const QModelIndex &index);
+ void structureViewDoubleClicked(const QModelIndex &index);
+ void constraintsViewDoubleClicked(const QModelIndex &index);
void nameChanged();
void withOutRowIdChanged();
void addIndex();
- void editIndex();
+ void editCurrentIndex();
+ void indexViewDoubleClicked(const QModelIndex& idx);
+ void triggerViewDoubleClicked(const QModelIndex& idx);
void delIndex();
void addTrigger();
void editTrigger();
@@ -229,6 +236,7 @@ class GUI_API_EXPORT TableWindow : public MdiChild
void updateTriggersState();
void nextTab();
void prevTab();
+ void updateTabsOrder();
public slots:
void updateIndexes();
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui
index 0dd7fe6..14e278a 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.ui
@@ -105,7 +105,7 @@
<property name="childrenCollapsible">
<bool>false</bool>
</property>
- <widget class="QTableView" name="structureView">
+ <widget class="ExtTableView" name="structureView">
<property name="dragEnabled">
<bool>true</bool>
</property>
@@ -152,7 +152,7 @@
<widget class="QToolBar" name="tableConstraintsToolbar"/>
</item>
<item>
- <widget class="QTableView" name="tableConstraintsView">
+ <widget class="ExtTableView" name="tableConstraintsView">
<property name="dragEnabled">
<bool>true</bool>
</property>
@@ -225,7 +225,7 @@
<widget class="QToolBar" name="indexToolBar"/>
</item>
<item>
- <widget class="QTableWidget" name="indexList">
+ <widget class="ExtTableWidget" name="indexList">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
@@ -254,7 +254,7 @@
<widget class="QToolBar" name="triggerToolBar"/>
</item>
<item>
- <widget class="QTableWidget" name="triggerList">
+ <widget class="ExtTableWidget" name="triggerList">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
@@ -307,6 +307,16 @@
<header>dataview.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>ExtTableView</class>
+ <extends>QTableView</extends>
+ <header>common/exttableview.h</header>
+ </customwidget>
+ <customwidget>
+ <class>ExtTableWidget</class>
+ <extends>QTableWidget</extends>
+ <header>common/exttablewidget.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
index cb3a11e..07c927c 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp
@@ -21,10 +21,12 @@
#include "services/config.h"
#include "services/codeformatter.h"
#include "themetuner.h"
+#include "datagrid/sqlviewmodel.h"
#include <QPushButton>
#include <QProgressBar>
#include <QDebug>
#include <QMessageBox>
+#include <QCheckBox>
CFG_KEYS_DEFINE(ViewWindow)
@@ -44,6 +46,7 @@ ViewWindow::ViewWindow(Db* db, QWidget* parent) :
newView();
init();
applyInitialTab();
+ updateDbRelatedUiElements();
}
ViewWindow::ViewWindow(const ViewWindow& win) :
@@ -56,6 +59,7 @@ ViewWindow::ViewWindow(const ViewWindow& win) :
init();
initView();
applyInitialTab();
+ updateDbRelatedUiElements();
}
ViewWindow::ViewWindow(QWidget* parent, Db* db, const QString& database, const QString& view) :
@@ -68,6 +72,7 @@ ViewWindow::ViewWindow(QWidget* parent, Db* db, const QString& database, const Q
init();
initView();
applyInitialTab();
+ updateDbRelatedUiElements();
}
ViewWindow::~ViewWindow()
@@ -134,6 +139,7 @@ bool ViewWindow::restoreSession(const QVariant& sessionValue)
initView();
applyInitialTab();
+ updateDbRelatedUiElements();
return true;
}
@@ -209,10 +215,10 @@ void ViewWindow::init()
ui->queryTab,
ui->dataTab,
ui->triggersTab,
- ui->ddl
+ ui->ddlTab
});
- dataModel = new SqlQueryModel(this);
+ dataModel = new SqlViewModel(this);
ui->dataView->init(dataModel);
ui->queryEdit->setVirtualSqlExpression("CREATE VIEW name AS %1");
@@ -225,6 +231,12 @@ void ViewWindow::init()
connect(ui->queryEdit, SIGNAL(textChanged()), this, SLOT(updateQueryToolbarStatus()));
connect(ui->queryEdit, SIGNAL(errorsChecked(bool)), this, SLOT(updateQueryToolbarStatus()));
connect(ui->triggersList, SIGNAL(itemSelectionChanged()), this, SLOT(updateTriggersState()));
+ connect(ui->triggersList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(triggerViewDoubleClicked(QModelIndex)));
+ connect(ui->outputColumnsTable, SIGNAL(currentRowChanged(int)), this, SLOT(updateColumnButtons()));
+ connect(ui->outputColumnsTable->model(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)), this, SLOT(updateColumnButtons()));
+ connect(ui->outputColumnsTable->model(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)), this, SLOT(updateQueryToolbarStatus()));
+ connect(ui->outputColumnsTable, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(updateQueryToolbarStatus()));
+ connect(CFG_UI.General.DataTabAsFirstInViews, SIGNAL(changed(const QVariant&)), this, SLOT(updateTabsOrder()));
structureExecutor = new ChainExecutor(this);
connect(structureExecutor, SIGNAL(success()), this, SLOT(changesSuccessfullyCommited()));
@@ -234,9 +246,17 @@ void ViewWindow::init()
initActions();
+ ui->splitter->setStretchFactor(0, 1);
+ ui->splitter->setStretchFactor(1, 3);
+
+ updateOutputColumnsVisibility();
+
+ updateTabsOrder();
+
refreshTriggers();
updateQueryToolbarStatus();
updateTriggersState();
+ updateColumnButtons();
}
void ViewWindow::newView()
@@ -258,10 +278,18 @@ void ViewWindow::initView()
{
dataModel->setDb(db);
dataModel->setQuery(originalCreateView->select->detokenize());
+ dataModel->setView(view);
}
ui->queryEdit->setDb(db);
ui->queryEdit->setPlainText(createView->select->detokenize());
+
+ if (createView->columns.size() > 0)
+ {
+ columnsFromViewToList();
+ outputColumnsCheck->setChecked(true);
+ }
+
updateDdlTab();
ui->ddlEdit->setSqliteVersion(db->getVersion());
@@ -286,6 +314,19 @@ void ViewWindow::createQueryTabActions()
createAction(ROLLBACK_QUERY, ICONS.ROLLBACK, tr("Rollback the view changes", "view window"), this, SLOT(rollbackView()), ui->queryToolbar);
ui->queryToolbar->addSeparator();
ui->queryToolbar->addAction(ui->queryEdit->getAction(SqlEditor::FORMAT_SQL));
+
+ outputColumnsCheck = new QAction(ICONS.COLUMNS, tr("Explicit column names"), this);
+ outputColumnsCheck->setCheckable(true);
+ connect(outputColumnsCheck, SIGNAL(toggled(bool)), this, SLOT(updateOutputColumnsVisibility()));
+
+ outputColumnsSeparator = ui->queryToolbar->addSeparator();
+ ui->queryToolbar->addAction(outputColumnsCheck);
+ createAction(GENERATE_OUTPUT_COLUMNS, ICONS.GENERATE_COLUMNS, tr("Generate output column names automatically basing on result columns of the view."), this, SLOT(generateOutputColumns()), ui->queryToolbar);
+ createAction(ADD_COLUMN, ICONS.TABLE_COLUMN_ADD, tr("Add column", "view window"), this, SLOT(addColumn()), ui->queryToolbar);
+ createAction(EDIT_COLUMN, ICONS.TABLE_COLUMN_EDIT, tr("Edit column", "view window"), this, SLOT(editColumn()), ui->queryToolbar);
+ createAction(DEL_COLUMN, ICONS.TABLE_COLUMN_DELETE, tr("Delete column", "view window"), this, SLOT(delColumn()), ui->queryToolbar);
+ createAction(MOVE_COLUMN_UP, ICONS.MOVE_UP, tr("Move column up", "view window"), this, SLOT(moveColumnUp()), ui->queryToolbar);
+ createAction(MOVE_COLUMN_DOWN, ICONS.MOVE_DOWN, tr("Move column down", "view window"), this, SLOT(moveColumnDown()), ui->queryToolbar);
}
void ViewWindow::createTriggersTabActions()
@@ -394,6 +435,7 @@ void ViewWindow::rollbackView()
ui->nameEdit->setText(createView->view);
ui->queryEdit->setPlainText(createView->select->detokenize());
+ columnsFromViewToList();
updateQueryToolbarStatus();
updateDdlTab();
}
@@ -411,15 +453,70 @@ QString ViewWindow::getCurrentTrigger() const
void ViewWindow::applyInitialTab()
{
if (existingView && !view.isNull() && CFG_UI.General.OpenViewsOnData.get())
- ui->tabWidget->setCurrentIndex(1);
+ ui->tabWidget->setCurrentIndex(getDataTabIdx());
else
- ui->tabWidget->setCurrentIndex(0);
+ ui->tabWidget->setCurrentIndex(getQueryTabIdx());
}
QString ViewWindow::getCurrentDdl() const
{
- static_qstring(ddlTpl, "CREATE VIEW %1 AS %2");
- return ddlTpl.arg(wrapObjIfNeeded(ui->nameEdit->text(), db->getDialect())).arg(ui->queryEdit->toPlainText());
+ static_qstring(ddlTpl, "CREATE VIEW %1%2 AS %3");
+ QString columnsStr = "";
+ if (outputColumnsCheck->isChecked() && ui->outputColumnsTable->count() > 0)
+ columnsStr = "(" + collectColumnNames().join(", ") + ")";
+
+ return ddlTpl.arg(
+ wrapObjIfNeeded(ui->nameEdit->text(), db->getDialect()),
+ columnsStr,
+ ui->queryEdit->toPlainText()
+ );
+}
+
+QStringList ViewWindow::indexedColumnsToNamesOnly(const QList<SqliteIndexedColumn*>& columns) const
+{
+ QStringList names;
+ for (SqliteIndexedColumn* col : columns)
+ names << col->name;
+
+ return names;
+}
+
+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);
+
+ return cols;
+}
+
+void ViewWindow::columnsFromViewToList()
+{
+ ui->outputColumnsTable->clear();
+ ui->outputColumnsTable->addItems(indexedColumnsToNamesOnly(createView->columns));
+
+ QListWidgetItem* item = nullptr;
+ for (int row = 0; row < ui->outputColumnsTable->count(); row++)
+ {
+ item = ui->outputColumnsTable->item(row);
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ }
+}
+
+int ViewWindow::getDataTabIdx() const
+{
+ return ui->tabWidget->indexOf(ui->dataTab);
+}
+
+int ViewWindow::getQueryTabIdx() const
+{
+ return ui->tabWidget->indexOf(ui->queryTab);
+}
+
+int ViewWindow::getDdlTabIdx() const
+{
+ return ui->tabWidget->indexOf(ui->ddlTab);
}
void ViewWindow::addTrigger()
@@ -465,10 +562,11 @@ void ViewWindow::executionFailed(const QString& errorMessage)
void ViewWindow::tabChanged(int tabIdx)
{
- switch (tabIdx)
+ if (tabsMoving)
+ return;
+
+ if (tabIdx == getDataTabIdx())
{
- case 1:
- {
if (isModified())
{
int res = QMessageBox::question(this, tr("Uncommited changes"),
@@ -481,19 +579,19 @@ void ViewWindow::tabChanged(int tabIdx)
if (res == 1)
commitView(true);
- break;
+ return;
}
if (!dataLoaded)
ui->dataView->refreshData();
- break;
- }
- case 3:
- {
- updateDdlTab();
- break;
- }
+ return;
+ }
+
+ if (tabIdx == getDdlTabIdx())
+ {
+ updateDdlTab();
+ return;
}
}
@@ -518,12 +616,18 @@ void ViewWindow::changesSuccessfullyCommited()
//QString oldView = view; // uncomment when implementing notify manager call
database = createView->database;
+ QString oldView = view;
view = createView->view;
existingView = true;
initView();
updateQueryToolbarStatus();
updateWindowTitle();
+ if (oldView.compare(view, Qt::CaseInsensitive) == 0)
+ notifyInfo(tr("Commited changes for view '%1' successfly.").arg(view));
+ else
+ notifyInfo(tr("Commited changes for view '%1' (named before '%2') successfly.").arg(view, oldView));
+
DBTREE->refreshSchema(db);
}
@@ -599,6 +703,154 @@ void ViewWindow::checkIfViewDeleted(const QString& database, const QString& obje
}
}
+void ViewWindow::updateOutputColumnsVisibility()
+{
+ bool enabled = outputColumnsCheck->isChecked();
+
+ ui->outputColumnsContainer->setVisible(enabled);
+ actionMap[Action::GENERATE_OUTPUT_COLUMNS]->setVisible(enabled);
+ actionMap[Action::ADD_COLUMN]->setVisible(enabled);
+ actionMap[Action::EDIT_COLUMN]->setVisible(enabled);
+ actionMap[Action::DEL_COLUMN]->setVisible(enabled);
+ actionMap[Action::MOVE_COLUMN_UP]->setVisible(enabled);
+ actionMap[Action::MOVE_COLUMN_DOWN]->setVisible(enabled);
+
+ updateQueryToolbarStatus();
+}
+
+void ViewWindow::addColumn()
+{
+ QListWidgetItem* item = new QListWidgetItem();
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ ui->outputColumnsTable->addItem(item);
+ ui->outputColumnsTable->editItem(item);
+ ui->outputColumnsTable->setCurrentItem(item);
+ updateColumnButtons();
+}
+
+void ViewWindow::editColumn()
+{
+ QListWidgetItem* item = ui->outputColumnsTable->currentItem();
+ ui->outputColumnsTable->editItem(item);
+ updateColumnButtons();
+}
+
+void ViewWindow::delColumn()
+{
+ QListWidgetItem* item = ui->outputColumnsTable->takeItem(ui->outputColumnsTable->currentRow());
+ delete item;
+ updateColumnButtons();
+}
+
+void ViewWindow::moveColumnUp()
+{
+ int row = ui->outputColumnsTable->currentRow();
+ if (row <= 0)
+ return;
+
+ QListWidgetItem* item = ui->outputColumnsTable->takeItem(row);
+ ui->outputColumnsTable->insertItem(--row, item);
+ ui->outputColumnsTable->setCurrentItem(item);
+}
+
+void ViewWindow::moveColumnDown()
+{
+ int row = ui->outputColumnsTable->currentRow();
+ if (row + 1 >= ui->outputColumnsTable->count())
+ return;
+
+ QListWidgetItem* item = ui->outputColumnsTable->takeItem(row);
+ ui->outputColumnsTable->insertItem(++row, item);
+ ui->outputColumnsTable->setCurrentItem(item);
+}
+
+void ViewWindow::updateColumnButtons()
+{
+ QListWidgetItem* item = ui->outputColumnsTable->currentItem();
+ int row = ui->outputColumnsTable->currentRow();
+
+ actionMap[MOVE_COLUMN_UP]->setEnabled(row > 0);
+ actionMap[MOVE_COLUMN_DOWN]->setEnabled(row + 1 < ui->outputColumnsTable->count());
+ actionMap[EDIT_COLUMN]->setEnabled(item != nullptr);
+ actionMap[DEL_COLUMN]->setEnabled(item != nullptr);
+}
+
+void ViewWindow::generateOutputColumns()
+{
+ if (ui->outputColumnsTable->count() > 0)
+ {
+ QMessageBox::StandardButton res = QMessageBox::question(this, tr("Override columns"), tr("Currently defined columns will be overriden. Do you want to continue?"));
+ if (res != QMessageBox::Yes)
+ return;
+ }
+
+ // Validate and generate fresh createView instance
+ bool validated = validate(true);
+ if (!validated)
+ return;
+
+ // Make copy of CREATE statement and remove columns
+ SqliteCreateView* stmt = dynamic_cast<SqliteCreateView*>(createView->clone());
+ for (SqliteIndexedColumn* col : stmt->columns)
+ delete col;
+
+ stmt->columns.clear();
+
+ // Indentify columns
+ SchemaResolver resolver(db);
+ QStringList columns = resolver.getColumnsUsingPragma(stmt);
+ delete stmt;
+ if (columns.isEmpty())
+ {
+ notifyWarn(tr("Could not determinate columns returned from the view. The query is problably incomplete or contains errors."));
+ return;
+ }
+
+ ui->outputColumnsTable->clear();
+ ui->outputColumnsTable->addItems(columns);
+
+ QListWidgetItem* item = nullptr;
+ for (int row = 0; row < columns.size(); row++)
+ {
+ item = ui->outputColumnsTable->item(row);
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ }
+}
+
+void ViewWindow::updateDbRelatedUiElements()
+{
+ bool enabled = db->getDialect() == Dialect::Sqlite3;
+ outputColumnsCheck->setVisible(enabled);
+ outputColumnsSeparator->setVisible(enabled);
+}
+
+void ViewWindow::updateTabsOrder()
+{
+ tabsMoving = true;
+ ui->tabWidget->removeTab(getDataTabIdx());
+ int idx = 1;
+ if (CFG_UI.General.DataTabAsFirstInViews.get())
+ idx = 0;
+
+ ui->tabWidget->insertTab(idx, ui->dataTab, tr("Data"));
+ tabsMoving = false;
+}
+
+void ViewWindow::triggerViewDoubleClicked(const QModelIndex& idx)
+{
+ if (!idx.isValid())
+ {
+ addTrigger();
+ return;
+ }
+
+ QString trigger = ui->triggersList->item(idx.row(), 0)->text();
+
+ DbObjectDialogs dialogs(db, this);
+ dialogs.editTrigger(trigger);
+ refreshTriggers();
+}
+
void ViewWindow::refreshTriggers()
{
if (!db || !db->isValid())
@@ -680,9 +932,21 @@ void ViewWindow::updateDdlTab()
bool ViewWindow::isModified() const
{
- return (originalCreateView && originalCreateView->view != ui->nameEdit->text()) ||
- ui->queryEdit->toPlainText() != originalQuery ||
- !existingView;
+ // Quick checks first
+ bool modified = !existingView || (originalCreateView && originalCreateView->view != ui->nameEdit->text()) ||
+ ui->queryEdit->toPlainText() != originalQuery;
+
+ if (modified)
+ return modified;
+
+ // And now a bit slower check
+ QStringList origCols = createView ? indexedColumnsToNamesOnly(createView->columns) : QStringList();
+ QStringList currentCols;
+ if (outputColumnsCheck->isChecked())
+ currentCols = collectColumnNames();
+
+ bool colsModified = origCols != currentCols;
+ return colsModified;
}
bool ViewWindow::validate(bool skipWarnings)
@@ -697,12 +961,9 @@ bool ViewWindow::validate(bool skipWarnings)
}
// Rebuilding createView statement and validating it on the fly.
- QString ddl = "CREATE VIEW %1 AS %2";
- QString viewName = wrapObjIfNeeded(ui->nameEdit->text(), db->getDialect());
- QString select = ui->queryEdit->toPlainText();
-
+ QString ddl = getCurrentDdl();
Parser parser(db->getDialect());
- if (!parser.parse(ddl.arg(viewName).arg(select)) || parser.getQueries().size() < 1)
+ 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()));
return false;
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h
index 62e1218..65c3260 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h
@@ -13,12 +13,12 @@ namespace Ui {
}
class SqliteSyntaxHighlighter;
-class SqlQueryModel;
class WidgetCover;
class QPushButton;
class QProgressBar;
class ChainExecutor;
class ViewModifier;
+class SqlViewModel;
CFG_KEY_LIST(ViewWindow, QObject::tr("A view window"),
CFG_KEY_ENTRY(REFRESH_TRIGGERS, Qt::Key_F5, QObject::tr("Refresh view trigger list"))
@@ -41,6 +41,12 @@ class GUI_API_EXPORT ViewWindow : public MdiChild
REFRESH_QUERY,
COMMIT_QUERY,
ROLLBACK_QUERY,
+ ADD_COLUMN,
+ EDIT_COLUMN,
+ DEL_COLUMN,
+ MOVE_COLUMN_UP,
+ MOVE_COLUMN_DOWN,
+ GENERATE_OUTPUT_COLUMNS,
// Triggers tab
REFRESH_TRIGGERS,
ADD_TRIGGER,
@@ -103,6 +109,12 @@ class GUI_API_EXPORT ViewWindow : public MdiChild
QString getCurrentTrigger() const;
void applyInitialTab();
QString getCurrentDdl() const;
+ QStringList indexedColumnsToNamesOnly(const QList<SqliteIndexedColumn*>& columns) const;
+ QStringList collectColumnNames() const;
+ void columnsFromViewToList();
+ int getDataTabIdx() const;
+ int getQueryTabIdx() const;
+ int getDdlTabIdx() const;
Db* db = nullptr;
QString database;
@@ -113,13 +125,16 @@ class GUI_API_EXPORT ViewWindow : public MdiChild
bool modified = false;
SqliteCreateViewPtr originalCreateView;
SqliteCreateViewPtr createView;
- SqlQueryModel* dataModel = nullptr;
+ SqlViewModel* dataModel = nullptr;
QString originalQuery;
WidgetCover* widgetCover = nullptr;
ChainExecutor* structureExecutor = nullptr;
ViewModifier* viewModifier = nullptr;
Ui::ViewWindow *ui = nullptr;
bool modifyingThisView = false;
+ QAction* outputColumnsCheck = nullptr;
+ QAction* outputColumnsSeparator = nullptr;
+ bool tabsMoving = false;
private slots:
void refreshView();
@@ -139,6 +154,17 @@ class GUI_API_EXPORT ViewWindow : public MdiChild
void prevTab();
void dbClosedFinalCleanup();
void checkIfViewDeleted(const QString& database, const QString& object, DbObjectType type);
+ void updateOutputColumnsVisibility();
+ void addColumn();
+ void editColumn();
+ void delColumn();
+ void moveColumnUp();
+ void moveColumnDown();
+ void updateColumnButtons();
+ void generateOutputColumns();
+ void updateDbRelatedUiElements();
+ void updateTabsOrder();
+ void triggerViewDoubleClicked(const QModelIndex& idx);
public slots:
void refreshTriggers();
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui
index 0fdccc3..9112280 100644
--- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui
+++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui
@@ -29,7 +29,7 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
- <number>0</number>
+ <number>2</number>
</property>
<widget class="QWidget" name="queryTab">
<attribute name="title">
@@ -68,7 +68,86 @@
</widget>
</item>
<item>
- <widget class="SqlEditor" name="queryEdit"/>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <widget class="QWidget" name="outputColumnsContainer" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>4</number>
+ </property>
+ <property name="topMargin">
+ <number>4</number>
+ </property>
+ <property name="rightMargin">
+ <number>4</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="outputColumnsGroup">
+ <property name="title">
+ <string>Output column names</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QListWidget" name="outputColumnsTable">
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::MoveAction</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="selectionRectVisible">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="SqlEditor" name="queryEdit"/>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</item>
</layout>
</widget>
@@ -91,7 +170,7 @@
<widget class="QToolBar" name="triggersToolbar"/>
</item>
<item>
- <widget class="QTableWidget" name="triggersList">
+ <widget class="ExtTableWidget" name="triggersList">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
@@ -114,7 +193,7 @@
</item>
</layout>
</widget>
- <widget class="QWidget" name="ddl">
+ <widget class="QWidget" name="ddlTab">
<attribute name="title">
<string>DDL</string>
</attribute>
@@ -149,6 +228,11 @@
<extends>QPlainTextEdit</extends>
<header>sqleditor.h</header>
</customwidget>
+ <customwidget>
+ <class>ExtTableWidget</class>
+ <extends>QTableWidget</extends>
+ <header>common/exttablewidget.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>