aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/guiSQLiteStudio/dbtree
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2018-07-27 23:54:15 -0400
committerLibravatarUnit 193 <unit193@ubuntu.com>2018-07-27 23:54:15 -0400
commit6d3d39356473078c6b47e03b8a7616e4b34de928 (patch)
treefe5be2e6a08e4cfc73207746aba4c9fccfecfa10 /SQLiteStudio3/guiSQLiteStudio/dbtree
parentf98e49169a40876bcf1df832de6e908d1b350193 (diff)
parentfeda8a7db8d1d7c5439aa8f8feef7cc0dd2b59a0 (diff)
Update upstream source from tag 'upstream/3.2.1+dfsg1'
Update to upstream version '3.2.1+dfsg1' with Debian dir 5ea0333565de4dc898c062cc0ff4ba1153e2c1e4
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/dbtree')
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp309
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h30
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp44
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h2
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp2
5 files changed, 312 insertions, 75 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
index 018eeb6..ba8ccc1 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
@@ -3,6 +3,7 @@
#include "ui_dbtree.h"
#include "actionentry.h"
#include "common/utils_sql.h"
+#include "common/utils.h"
#include "dbtreemodel.h"
#include "dialogs/dbdialog.h"
#include "services/dbmanager.h"
@@ -27,6 +28,8 @@
#include "themetuner.h"
#include "dialogs/dbconverterdialog.h"
#include "querygenerator.h"
+#include "dialogs/execfromfiledialog.h"
+#include "dialogs/fileexecerrorsdialog.h"
#include <QApplication>
#include <QClipboard>
#include <QAction>
@@ -38,6 +41,10 @@
#include <QKeyEvent>
#include <QMimeData>
#include <QDebug>
+#include <QDesktopServices>
+#include <QDir>
+#include <QFileDialog>
+#include <QtConcurrent/QtConcurrentRun>
CFG_KEYS_DEFINE(DbTree)
QHash<DbTreeItem::Type,QList<DbTreeItem::Type>> DbTree::allowedTypesInside;
@@ -70,10 +77,33 @@ void DbTree::init()
ui->nameFilter->setClearButtonEnabled(true);
- widgetCover = new WidgetCover(this);
- widgetCover->initWithInterruptContainer();
- widgetCover->hide();
- connect(widgetCover, SIGNAL(cancelClicked()), this, SLOT(interrupt()));
+ treeRefreshWidgetCover = new WidgetCover(this);
+ treeRefreshWidgetCover->initWithInterruptContainer();
+ treeRefreshWidgetCover->hide();
+ connect(treeRefreshWidgetCover, SIGNAL(cancelClicked()), this, SLOT(interrupt()));
+
+ fileExecWidgetCover = new WidgetCover(this);
+ fileExecWidgetCover->initWithInterruptContainer();
+ fileExecWidgetCover->displayProgress(100);
+ fileExecWidgetCover->hide();
+ connect(fileExecWidgetCover, &WidgetCover::cancelClicked, [this]()
+ {
+ if (!this->executingQueriesFromFile)
+ return;
+
+ this->executingQueriesFromFile = 0;
+
+ if (this->executingQueriesFromFileDb) // should always be there, but just in case
+ {
+ this->executingQueriesFromFileDb->interrupt();
+ this->executingQueriesFromFileDb->rollback();
+ this->executingQueriesFromFileDb = nullptr;
+ notifyWarn(tr("Execution from file cancelled. Any queries executed so far have been rolled back."));
+ }
+ });
+ 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);
treeModel = new DbTreeModel();
treeModel->setTreeView(ui->treeView);
@@ -107,45 +137,47 @@ void DbTree::createActions()
createAction(CREATE_GROUP, ICONS.DIRECTORY_ADD, tr("Create a group"), this, SLOT(createGroup()), this);
createAction(DELETE_GROUP, ICONS.DIRECTORY_DEL, tr("Delete the group"), this, SLOT(deleteGroup()), this);
createAction(RENAME_GROUP, ICONS.DIRECTORY_EDIT, tr("Rename the group"), this, SLOT(renameGroup()), this);
- createAction(ADD_DB, ICONS.DATABASE_ADD, tr("Add a database"), this, SLOT(addDb()), this);
- createAction(EDIT_DB, ICONS.DATABASE_EDIT, tr("Edit the database"), this, SLOT(editDb()), this);
- createAction(DELETE_DB, ICONS.DATABASE_DEL, tr("Remove the database"), this, SLOT(removeDb()), this);
- createAction(CONNECT_TO_DB, ICONS.DATABASE_CONNECT, tr("Connect to the database"), this, SLOT(connectToDb()), this);
- createAction(DISCONNECT_FROM_DB, ICONS.DATABASE_DISCONNECT, tr("Disconnect from the database"), this, SLOT(disconnectFromDb()), this);
+ createAction(ADD_DB, ICONS.DATABASE_ADD, tr("&Add a database"), this, SLOT(addDb()), this);
+ createAction(EDIT_DB, ICONS.DATABASE_EDIT, tr("&Edit the database"), this, SLOT(editDb()), this);
+ createAction(DELETE_DB, ICONS.DATABASE_DEL, tr("&Remove the database"), this, SLOT(removeDb()), this);
+ createAction(CONNECT_TO_DB, ICONS.DATABASE_CONNECT, tr("&Connect to the database"), this, SLOT(connectToDb()), this);
+ 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("Convert database type"), this, SLOT(convertDb()), this);
- createAction(VACUUM_DB, ICONS.VACUUM_DB, tr("Vacuum"), 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);
- createAction(EDIT_TABLE, ICONS.TABLE_EDIT, tr("Edit the table"), this, SLOT(editTable()), this);
- createAction(DEL_TABLE, ICONS.TABLE_DEL, tr("Delete the table"), this, SLOT(delTable()), 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);
+ createAction(EDIT_TABLE, ICONS.TABLE_EDIT, tr("Edit the t&able"), this, SLOT(editTable()), this);
+ createAction(DEL_TABLE, ICONS.TABLE_DEL, tr("Delete the ta&ble"), this, SLOT(delTable()), this);
createAction(EXPORT_TABLE, ICONS.TABLE_EXPORT, tr("Export the table"), this, SLOT(exportTable()), this);
createAction(IMPORT_TABLE, ICONS.TABLE_IMPORT, tr("Import into the table"), this, SLOT(importTable()), this);
createAction(POPULATE_TABLE, ICONS.TABLE_POPULATE, tr("Populate table"), this, SLOT(populateTable()), this);
createAction(CREATE_SIMILAR_TABLE, ICONS.TABLE_CREATE_SIMILAR, tr("Create similar table"), this, SLOT(createSimilarTable()), this);
createAction(RESET_AUTOINCREMENT, ICONS.RESET_AUTOINCREMENT, tr("Reset autoincrement sequence"), this, SLOT(resetAutoincrement()), this);
- createAction(ADD_INDEX, ICONS.INDEX_ADD, tr("Create an index"), this, SLOT(addIndex()), this);
- createAction(EDIT_INDEX, ICONS.INDEX_EDIT, tr("Edit the index"), this, SLOT(editIndex()), this);
- createAction(DEL_INDEX, ICONS.INDEX_DEL, tr("Delete the index"), this, SLOT(delIndex()), this);
- createAction(ADD_TRIGGER, ICONS.TRIGGER_ADD, tr("Create a trigger"), this, SLOT(addTrigger()), this);
- createAction(EDIT_TRIGGER, ICONS.TRIGGER_EDIT, tr("Edit the trigger"), this, SLOT(editTrigger()), this);
- createAction(DEL_TRIGGER, ICONS.TRIGGER_DEL, tr("Delete the trigger"), this, SLOT(delTrigger()), this);
- createAction(ADD_VIEW, ICONS.VIEW_ADD, tr("Create a view"), this, SLOT(addView()), this);
- createAction(EDIT_VIEW, ICONS.VIEW_EDIT, tr("Edit the view"), this, SLOT(editView()), this);
- createAction(DEL_VIEW, ICONS.VIEW_DEL, tr("Delete the view"), this, SLOT(delView()), this);
+ createAction(ADD_INDEX, ICONS.INDEX_ADD, tr("Create an &index"), this, SLOT(addIndex()), this);
+ createAction(EDIT_INDEX, ICONS.INDEX_EDIT, tr("Edit the i&ndex"), this, SLOT(editIndex()), this);
+ createAction(DEL_INDEX, ICONS.INDEX_DEL, tr("Delete the in&dex"), this, SLOT(delIndex()), this);
+ createAction(ADD_TRIGGER, ICONS.TRIGGER_ADD, tr("Create a trig&ger"), this, SLOT(addTrigger()), this);
+ createAction(EDIT_TRIGGER, ICONS.TRIGGER_EDIT, tr("Edit the trigg&er"), this, SLOT(editTrigger()), this);
+ createAction(DEL_TRIGGER, ICONS.TRIGGER_DEL, tr("Delete the trigge&r"), this, SLOT(delTrigger()), this);
+ createAction(ADD_VIEW, ICONS.VIEW_ADD, tr("Create a &view"), this, SLOT(addView()), this);
+ createAction(EDIT_VIEW, ICONS.VIEW_EDIT, tr("Edit the v&iew"), this, SLOT(editView()), this);
+ createAction(DEL_VIEW, ICONS.VIEW_DEL, tr("Delete the vi&ew"), this, SLOT(delView()), this);
createAction(ADD_COLUMN, ICONS.TABLE_COLUMN_ADD, tr("Add a column"), this, SLOT(addColumn()), this);
createAction(EDIT_COLUMN, ICONS.TABLE_COLUMN_EDIT, tr("Edit the column"), this, SLOT(editColumn()), this);
createAction(DEL_COLUMN, ICONS.TABLE_COLUMN_DELETE, tr("Delete the column"), this, SLOT(delColumn()), this);
createAction(DEL_SELECTED, ICONS.DELETE_SELECTED, tr("Delete selected items"), this, SLOT(deleteSelected()), this);
createAction(CLEAR_FILTER, tr("Clear filter"), ui->nameFilter, SLOT(clear()), this);
- createAction(REFRESH_SCHEMAS, ICONS.DATABASE_RELOAD, tr("Refresh all database schemas"), this, SLOT(refreshSchemas()), this);
- createAction(REFRESH_SCHEMA, ICONS.DATABASE_RELOAD, tr("Refresh selected database schema"), this, SLOT(refreshSchema()), this);
+ createAction(REFRESH_SCHEMAS, ICONS.DATABASE_RELOAD, tr("&Refresh all database schemas"), this, SLOT(refreshSchemas()), this);
+ createAction(REFRESH_SCHEMA, ICONS.DATABASE_RELOAD, tr("Re&fresh selected database schema"), this, SLOT(refreshSchema()), this);
createAction(ERASE_TABLE_DATA, ICONS.ERASE_TABLE_DATA, tr("Erase table data"), this, SLOT(eraseTableData()), this);
createAction(GENERATE_SELECT, "SELECT", this, SLOT(generateSelectForTable()), this);
createAction(GENERATE_INSERT, "INSERT", this, SLOT(generateInsertForTable()), this);
createAction(GENERATE_UPDATE, "UPDATE", this, SLOT(generateUpdateForTable()), this);
createAction(GENERATE_DELETE, "DELETE", this, SLOT(generateDeleteForTable()), this);
+ createAction(OPEN_DB_DIRECTORY, ICONS.DIRECTORY_OPEN_WITH_DB, tr("Open file's directory"), this, SLOT(openDbDirectory()), this);
+ createAction(EXEC_SQL_FROM_FILE, ICONS.EXEC_SQL_FROM_FILE, tr("Execute SQL from file"), this, SLOT(execSqlFromFile()), this);
}
void DbTree::updateActionStates(const QStandardItem *item)
@@ -161,7 +193,7 @@ void DbTree::updateActionStates(const QStandardItem *item)
// Add database should always be available, as well as a copy of an item
enabled << ADD_DB << COPY;
- if (isMimeDataValidForItem(QApplication::clipboard()->mimeData(), dbTreeItem))
+ if (isMimeDataValidForItem(QApplication::clipboard()->mimeData(), dbTreeItem, true))
enabled << PASTE;
enabled << CLEAR_FILTER;
@@ -181,6 +213,10 @@ void DbTree::updateActionStates(const QStandardItem *item)
}
else
enabled << CONNECT_TO_DB;
+
+ QUrl url = QUrl::fromLocalFile(dbTreeItem->getDb()->getPath());
+ if (url.isValid())
+ enabled << OPEN_DB_DIRECTORY;
}
if (isDbOpen)
@@ -193,7 +229,7 @@ void DbTree::updateActionStates(const QStandardItem *item)
// It's handled outside of "item with db", above
break;
case DbTreeItem::Type::DB:
- enabled << CREATE_GROUP << DELETE_DB << EDIT_DB;
+ enabled << CREATE_GROUP << DELETE_DB << EDIT_DB << EXEC_SQL_FROM_FILE;
break;
case DbTreeItem::Type::TABLES:
break;
@@ -308,7 +344,7 @@ void DbTree::updateActionStates(const QStandardItem *item)
enabled << REFRESH_SCHEMAS;
- foreach (int action, actionMap.keys())
+ for (int action : actionMap.keys())
setActionEnabled(action, enabled.contains(action));
}
@@ -380,6 +416,8 @@ void DbTree::setupActionsForMenu(DbTreeItem* currItem, QMenu* contextMenu)
actions += ActionEntry(CONVERT_DB);
actions += ActionEntry(VACUUM_DB);
actions += ActionEntry(INTEGRITY_CHECK);
+ actions += ActionEntry(EXEC_SQL_FROM_FILE);
+ actions += ActionEntry(OPEN_DB_DIRECTORY);
actions += ActionEntry(_separator);
}
else
@@ -559,7 +597,7 @@ void DbTree::setupActionsForMenu(DbTreeItem* currItem, QMenu* contextMenu)
actions += ActionEntry(REFRESH_SCHEMAS);
QMenu* subMenu = nullptr;
- foreach (ActionEntry actionEntry, actions)
+ for (ActionEntry actionEntry : actions)
{
switch (actionEntry.type)
{
@@ -576,7 +614,7 @@ void DbTree::setupActionsForMenu(DbTreeItem* currItem, QMenu* contextMenu)
case ActionEntry::Type::SUB_MENU:
{
subMenu = contextMenu->addMenu(actionEntry.subMenuIcon, actionEntry.subMenuLabel);
- foreach (Action action, actionEntry.actions)
+ for (Action action : actionEntry.actions)
{
if (action == DbTree::_separator)
{
@@ -624,10 +662,10 @@ DbTreeView*DbTree::getView() const
return ui->treeView;
}
-bool DbTree::isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item)
+bool DbTree::isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item, bool forPasting)
{
if (mimeData->formats().contains(DbTreeModel::MIMETYPE))
- return areDbTreeItemsValidForItem(getModel()->getDragItems(mimeData), item);
+ return areDbTreeItemsValidForItem(getModel()->getDragItems(mimeData), item, forPasting);
else if (mimeData->hasUrls())
return areUrlsValidForItem(mimeData->urls(), item);
@@ -639,7 +677,7 @@ bool DbTree::isItemDraggable(const DbTreeItem* item)
return item && draggableTypes.contains(item->getType());
}
-bool DbTree::areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTreeItem* dstItem)
+bool DbTree::areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTreeItem* dstItem, bool forPasting)
{
QSet<Db*> srcDbs;
QList<DbTreeItem::Type> srcTypes;
@@ -647,6 +685,9 @@ bool DbTree::areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTre
if (dstItem)
dstType = dstItem->getType();
+ if (dstType == DbTreeItem::Type::DB && !dstItem->getDb()->isOpen())
+ return false;
+
for (DbTreeItem* srcItem : srcItems)
{
if (!srcItem)
@@ -664,9 +705,6 @@ bool DbTree::areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTre
{
if (!allowedTypesInside[dstType].contains(srcType))
return false;
-
- if (dstType == DbTreeItem::Type::DB && !dstItem->getDb()->isOpen())
- return false;
}
// Support for d&d reordering of db objects
@@ -677,7 +715,8 @@ bool DbTree::areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTre
{DbTreeItem::Type::INDEX, DbTreeItem::Type::INDEXES}
};
- if (srcTypes.toSet().size() == 1 && srcDbs.size() == 1 && dstItem && *(srcDbs.begin()) == dstItem->getDb() && reorderingTypeToParent[srcTypes.first()] == dstType)
+ if (!forPasting && srcTypes.toSet().size() == 1 && srcDbs.size() == 1 && dstItem &&
+ *(srcDbs.begin()) == dstItem->getDb() && reorderingTypeToParent[srcTypes.first()] == dstType)
return true;
// No other d&d within same db
@@ -698,14 +737,14 @@ bool DbTree::areUrlsValidForItem(const QList<QUrl>& srcUrls, const DbTreeItem* d
return true;
}
-void DbTree::showWidgetCover()
+void DbTree::showRefreshWidgetCover()
{
- widgetCover->show();
+ treeRefreshWidgetCover->show();
}
-void DbTree::hideWidgetCover()
+void DbTree::hideRefreshWidgetCover()
{
- widgetCover->hide();
+ treeRefreshWidgetCover->hide();
}
void DbTree::setSelectedItem(DbTreeItem *item)
@@ -861,11 +900,10 @@ void DbTree::filterItemsWithParentInList(QList<DbTreeItem*>& items)
{
QMutableListIterator<DbTreeItem*> it(items);
DbTreeItem* item = nullptr;
- DbTreeItem* pathItem = nullptr;
while (it.hasNext())
{
item = it.next();
- foreach (pathItem, item->getPathToRoot().mid(1))
+ for (DbTreeItem* pathItem : item->getPathToRoot().mid(1))
{
if (items.contains(pathItem) && pathItem->getType() != DbTreeItem::Type::DIR)
{
@@ -1627,7 +1665,6 @@ QList<DbTreeItem*> DbTree::getSelectedItems(DbTree::ItemFilterFunc filterFunc)
return items;
}
-
void DbTree::deleteItems(const QList<DbTreeItem*>& itemsToDelete)
{
QList<DbTreeItem*> items = itemsToDelete;
@@ -1642,7 +1679,7 @@ void DbTree::deleteItems(const QList<DbTreeItem*>& itemsToDelete)
QStringList databasesToRemove;
QString itemStr;
int groupItems = 0;
- foreach (DbTreeItem* item, items)
+ for (DbTreeItem* item : items)
{
itemStr = itemTmp.arg(item->getIcon()->toUrl()).arg(item->text().left(ITEM_TEXT_LIMIT));
@@ -1694,7 +1731,7 @@ void DbTree::deleteItems(const QList<DbTreeItem*>& itemsToDelete)
void DbTree::refreshSchemas()
{
- foreach (Db* db, DBLIST->getDbList())
+ for (Db* db : DBLIST->getDbList())
treeModel->refreshSchema(db);
updateActionsForCurrent();
@@ -1716,6 +1753,22 @@ void DbTree::updateActionsForCurrent()
updateActionStates(ui->treeView->currentItem());
}
+void DbTree::setFileExecProgress(int newValue)
+{
+ fileExecWidgetCover->setProgress(newValue);
+}
+
+void DbTree::hideFileExecCover()
+{
+ fileExecWidgetCover->hide();
+}
+
+void DbTree::showFileExecErrors(const QList<QPair<QString, QString> >& errors, bool rolledBack)
+{
+ FileExecErrorsDialog dialog(errors, rolledBack, MAINWINDOW);
+ dialog.exec();
+}
+
void DbTree::dbConnected(Db* db)
{
updateActionsForCurrent();
@@ -1780,6 +1833,166 @@ void DbTree::generateDeleteForTable()
MAINWINDOW->openSqlEditor(db, sql);
}
+void DbTree::openDbDirectory()
+{
+ Db* db = getSelectedDb();
+ if (!db)
+ return;
+
+ QFileInfo fi(db->getPath());
+ if (!fi.exists())
+ return;
+
+ QUrl url = QUrl::fromLocalFile(fi.dir().path());
+ if (url.isValid())
+ QDesktopServices::openUrl(url);
+}
+
+void DbTree::execSqlFromFile()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isOpen())
+ return;
+
+ ExecFromFileDialog dialog(MAINWINDOW);
+ int res = dialog.exec();
+ if (res != QDialog::Accepted)
+ return;
+
+ if (executingQueriesFromFile)
+ return;
+
+ // Exec file
+ executingQueriesFromFile = 1;
+ executingQueriesFromFileDb = db;
+ fileExecWidgetCover->setProgress(0);
+ fileExecWidgetCover->show();
+ if (!db->begin())
+ {
+ notifyError(tr("Could not execute SQL, because application has failed to start transaction: %1").arg(db->getErrorText()));
+ fileExecWidgetCover->hide();
+ return;
+ }
+
+ QtConcurrent::run(this, &DbTree::execFromFileAsync, dialog.filePath(), db, dialog.ignoreErrors(), dialog.codec());
+}
+
+void DbTree::execFromFileAsync(const QString& path, Db* db, bool ignoreErrors, const QString& codec)
+{
+ // Open file
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ notifyError(tr("Could not open file '%1' for reading: %2").arg(path).arg(file.errorString()));
+ executingQueriesFromFile = 0;
+ emit fileExecCoverToBeClosed();
+ return;
+ }
+
+
+ QTextStream stream(&file);
+ stream.setCodec(codec.toLatin1().constData());
+
+ qint64 fileSize = file.size();
+ int attemptedExecutions = 0;
+ int executed = 0;
+ bool ok = true;
+
+ QTime timer;
+ timer.start();
+ QList<QPair<QString, QString>> errors = executeFileQueries(db, stream, executed, attemptedExecutions, ok, ignoreErrors, fileSize);
+ int millis = timer.elapsed();
+ if (executingQueriesFromFile.loadAcquire())
+ {
+ handleFileQueryExecution(db, executed, attemptedExecutions, ok, ignoreErrors, millis);
+ if (!errors.isEmpty())
+ emit fileExecErrors(errors, !ok && !ignoreErrors);
+ }
+
+ file.close();
+ emit fileExecCoverToBeClosed();
+ executingQueriesFromFile = 0;
+}
+
+QList<QPair<QString, QString>> DbTree::executeFileQueries(Db* db, QTextStream& stream, int& executed, int& attemptedExecutions, bool& ok, bool ignoreErrors, qint64 fileSize)
+{
+ QList<QPair<QString, QString>> errors;
+ qint64 pos = 0;
+ QChar c;
+ QString sql;
+ sql.reserve(10000);
+ SqlQueryPtr results;
+ while (!stream.atEnd() && executingQueriesFromFile.loadAcquire())
+ {
+ while (!db->isComplete(sql) && !stream.atEnd())
+ {
+ stream >> c;
+ sql.append(c);
+ while (c != ';' && !stream.atEnd())
+ {
+ stream >> c;
+ sql.append(c);
+ }
+ }
+
+ if (sql.trimmed().isEmpty())
+ continue;
+
+ results = db->exec(sql);
+ attemptedExecutions++;
+ if (results->isError())
+ {
+ ok = false;
+ errors << QPair<QString, QString>(sql, results->getErrorText());
+
+ if (!ignoreErrors)
+ break;
+ }
+ else
+ executed++;
+
+ sql.clear();
+ if (attemptedExecutions % 100 == 0)
+ {
+ pos = stream.device()->pos();
+ emit updateFileExecProgress(static_cast<int>(100 * pos / fileSize));
+ }
+ }
+ return errors;
+}
+
+void DbTree::handleFileQueryExecution(Db* db, int executed, int attemptedExecutions, bool ok, bool ignoreErrors, int millis)
+{
+ bool doCommit = ok ? true : ignoreErrors;
+ if (doCommit)
+ {
+ if (!db->commit())
+ {
+ db->rollback();
+ notifyError(tr("Could not execute SQL, because application has failed to commit the transaction: %1").arg(db->getErrorText()));
+ }
+ 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));
+ }
+ else
+ {
+ notifyInfo(tr("Finished executing %1 queries in %2 seconds.").arg(executed).arg(millis / 1000.0));
+ }
+ }
+ else
+ {
+ db->rollback();
+ notifyError(tr("Could not execute SQL due to error."));
+ }
+}
+
+bool DbTree::execQueryFromFile(Db* db, const QString& sql)
+{
+ return !db->exec(sql)->isError();
+}
+
void DbTree::setupDefShortcuts()
{
setShortcutContext({
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h
index f97e5eb..f72ebda 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.h
@@ -8,6 +8,7 @@
#include "guiSQLiteStudio_global.h"
#include <QDockWidget>
#include <QSet>
+#include <QAtomicInt>
class WidgetCover;
class QAction;
@@ -90,6 +91,8 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
GENERATE_UPDATE,
GENERATE_INSERT,
GENERATE_DELETE,
+ OPEN_DB_DIRECTORY,
+ EXEC_SQL_FROM_FILE,
_separator // Never use it directly, it's just for menu setup
};
@@ -109,10 +112,10 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
void restoreSession(const QVariant& sessionValue);
DbTreeModel* getModel() const;
DbTreeView* getView() const;
- void showWidgetCover();
- void hideWidgetCover();
+ void showRefreshWidgetCover();
+ void hideRefreshWidgetCover();
void setSelectedItem(DbTreeItem* item);
- bool isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item);
+ bool isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item, bool forPasting = false);
QToolBar* getToolBar(int toolbar) const;
Db* getSelectedDb();
Db* getSelectedOpenDb();
@@ -149,14 +152,21 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
QString getSelectedViewName() const;
QList<DbTreeItem*> getSelectedItems(DbTreeItem::Type itemType);
QList<DbTreeItem*> getSelectedItems(ItemFilterFunc filterFunc = nullptr);
+ void execFromFileAsync(const QString& path, Db* db, bool ignoreErrors, const QString& codec);
+ 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);
- static bool areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTreeItem* dstItem);
+ static bool areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTreeItem* dstItem, bool forPasting = false);
static bool areUrlsValidForItem(const QList<QUrl>& srcUrls, const DbTreeItem* dstItem);
static void initDndTypes();
Ui::DbTree *ui = nullptr;
DbTreeModel* treeModel = nullptr;
- WidgetCover* widgetCover = nullptr;
+ WidgetCover* treeRefreshWidgetCover = nullptr;
+ WidgetCover* fileExecWidgetCover = nullptr;
+ QAtomicInt executingQueriesFromFile = 0;
+ Db* executingQueriesFromFileDb = nullptr;
static QHash<DbTreeItem::Type,QList<DbTreeItem::Type>> allowedTypesInside;
static QSet<DbTreeItem::Type> draggableTypes;
@@ -221,6 +231,16 @@ class GUI_API_EXPORT DbTree : public QDockWidget, public ExtActionContainer
void generateInsertForTable();
void generateUpdateForTable();
void generateDeleteForTable();
+ void openDbDirectory();
+ void execSqlFromFile();
+ void setFileExecProgress(int newValue);
+ void hideFileExecCover();
+ void showFileExecErrors(const QList<QPair<QString, QString>>& errors, bool rolledBack);
+
+ signals:
+ void updateFileExecProgress(int value);
+ void fileExecCoverToBeClosed();
+ void fileExecErrors(const QList<QPair<QString, QString>>& errors, bool rolledBack);
};
int qHash(DbTree::Action action);
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
index 9fe88c2..123c4df 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.cpp
@@ -99,7 +99,7 @@ void DbTreeModel::deleteGroup(QStandardItem *groupItem)
if (!parentItem)
parentItem = root();
- foreach (QStandardItem* child, dynamic_cast<DbTreeItem*>(groupItem)->childs())
+ for (QStandardItem* child : dynamic_cast<DbTreeItem*>(groupItem)->childs())
move(child, parentItem);
parentItem->removeRow(groupItem->row());
@@ -163,12 +163,12 @@ void DbTreeModel::storeGroups()
void DbTreeModel::readGroups(QList<Db*> dbList)
{
QList<Config::DbGroupPtr> groups = CFG->getGroups();
- foreach (const Config::DbGroupPtr& group, groups)
+ for (const Config::DbGroupPtr& group : groups)
restoreGroup(group, &dbList);
// Add rest of databases, not mentioned in groups
Config::DbGroupPtr group;
- foreach (Db* db, dbList)
+ for (Db* db : dbList)
{
group = Config::DbGroupPtr::create();
group->referencedDbName = db->getName();
@@ -243,7 +243,7 @@ void DbTreeModel::restoreGroup(const Config::DbGroupPtr& group, QList<Db*>* dbLi
if (item->getType() == DbTreeItem::Type::DIR)
{
- foreach (const Config::DbGroupPtr& childGroup, group->childs)
+ for (const Config::DbGroupPtr& childGroup : group->childs)
restoreGroup(childGroup, dbList, item);
}
@@ -538,7 +538,7 @@ QList<QStandardItem *> DbTreeModel::refreshSchemaTables(const QStringList &table
sortedTables.sort(Qt::CaseInsensitive);
QList<QStandardItem *> items;
- foreach (const QString& table, sortedTables)
+ for (const QString& table : sortedTables)
{
if (virtualTables.contains(table))
items += DbTreeItemFactory::createVirtualTable(table, this);
@@ -605,7 +605,7 @@ QList<QStandardItem *> DbTreeModel::refreshSchemaViews(const QStringList &views,
sortedViews.sort(Qt::CaseInsensitive);
QList<QStandardItem *> items;
- foreach (const QString& view, sortedViews)
+ for (const QString& view : sortedViews)
items += DbTreeItemFactory::createView(view, this);
return items;
@@ -638,7 +638,7 @@ void DbTreeModel::refreshSchemaBuild(QStandardItem *dbItem,
DbTreeItem* columnsItem = nullptr;
DbTreeItem* indexesItem = nullptr;
DbTreeItem* triggersItem = nullptr;
- foreach (QStandardItem* tableItem, tables)
+ for (QStandardItem* tableItem : tables)
{
tablesItem->appendRow(tableItem);
@@ -650,22 +650,22 @@ void DbTreeModel::refreshSchemaBuild(QStandardItem *dbItem,
tableItem->appendRow(indexesItem);
tableItem->appendRow(triggersItem);
- foreach (QStandardItem* columnItem, allTableColumns[tableItem->text()])
+ for (QStandardItem* columnItem : allTableColumns[tableItem->text()])
columnsItem->appendRow(columnItem);
- foreach (QStandardItem* indexItem, indexes[tableItem->text()])
+ for (QStandardItem* indexItem : indexes[tableItem->text()])
indexesItem->appendRow(indexItem);
- foreach (QStandardItem* triggerItem, triggers[tableItem->text()])
+ for (QStandardItem* triggerItem : triggers[tableItem->text()])
triggersItem->appendRow(triggerItem);
}
- foreach (QStandardItem* viewItem, views)
+ for (QStandardItem* viewItem : views)
{
viewsItem->appendRow(viewItem);
triggersItem = DbTreeItemFactory::createTriggers(this);
viewItem->appendRow(triggersItem);
- foreach (QStandardItem* triggerItem, triggers[viewItem->text()])
+ for (QStandardItem* triggerItem : triggers[viewItem->text()])
triggersItem->appendRow(triggerItem);
}
}
@@ -677,7 +677,7 @@ void DbTreeModel::restoreExpandedState(const QHash<QString, bool>& expandedState
if (expandedState.contains(sig) && expandedState[sig])
treeView->expand(parentItem->index());
- foreach (QStandardItem* child, parentDbTreeItem->childs())
+ for (QStandardItem* child : parentDbTreeItem->childs())
restoreExpandedState(expandedState, child);
}
@@ -965,7 +965,7 @@ bool DbTreeModel::pasteData(const QMimeData* data, int row, int column, const QM
}
if (data->formats().contains(MIMETYPE))
- return dropDbTreeItem(getDragItems(data), dstItem, defaultAction, *invokeStdAction);
+ return dropDbTreeItem(getDragItems(data), dstItem, defaultAction, invokeStdAction);
else if (data->hasUrls())
return dropUrls(data->urls());
else
@@ -975,7 +975,7 @@ bool DbTreeModel::pasteData(const QMimeData* data, int row, int column, const QM
void DbTreeModel::interruptableStarted(Interruptable* obj)
{
if (interruptables.size() == 0)
- treeView->getDbTree()->showWidgetCover();
+ treeView->getDbTree()->showRefreshWidgetCover();
interruptables << obj;
}
@@ -984,7 +984,7 @@ void DbTreeModel::interruptableFinished(Interruptable* obj)
{
interruptables.removeOne(obj);
if (interruptables.size() == 0)
- treeView->getDbTree()->hideWidgetCover();
+ treeView->getDbTree()->hideRefreshWidgetCover();
}
QList<DbTreeItem*> DbTreeModel::getDragItems(const QMimeData* data)
@@ -1025,7 +1025,7 @@ void DbTreeModel::staticInit()
{
}
-bool DbTreeModel::dropDbTreeItem(const QList<DbTreeItem*>& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction, bool& invokeStdDropAction)
+bool DbTreeModel::dropDbTreeItem(const QList<DbTreeItem*>& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction, bool *invokeStdDropAction)
{
// The result means: do we want the old item to be removed from the tree?
if (srcItems.size() == 0)
@@ -1040,9 +1040,9 @@ bool DbTreeModel::dropDbTreeItem(const QList<DbTreeItem*>& srcItems, DbTreeItem*
if (!dstItem)
return false;
- if (srcItem->getDb() == dstItem->getDb())
+ if (srcItem->getDb() == dstItem->getDb() && invokeStdDropAction)
{
- invokeStdDropAction = true;
+ *invokeStdDropAction = true;
return true;
}
@@ -1050,8 +1050,12 @@ bool DbTreeModel::dropDbTreeItem(const QList<DbTreeItem*>& srcItems, DbTreeItem*
}
case DbTreeItem::Type::DB:
case DbTreeItem::Type::DIR:
- invokeStdDropAction = true;
+ {
+ if (invokeStdDropAction)
+ *invokeStdDropAction = true;
+
break;
+ }
case DbTreeItem::Type::COLUMN:
case DbTreeItem::Type::TABLES:
case DbTreeItem::Type::INDEXES:
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
index 50b080d..9ba0d82 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreemodel.h
@@ -81,7 +81,7 @@ class GUI_API_EXPORT DbTreeModel : public QStandardItemModel
QString getDbToolTip(DbTreeItem *item) const;
QString getTableToolTip(DbTreeItem *item) const;
QList<DbTreeItem*> getChildsAsFlatList(QStandardItem* item) const;
- bool dropDbTreeItem(const QList<DbTreeItem*>& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction, bool &invokeStdDropAction);
+ bool dropDbTreeItem(const QList<DbTreeItem*>& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction, bool* invokeStdDropAction);
bool dropDbObjectItem(const QList<DbTreeItem*>& srcItems, DbTreeItem* dstItem, Qt::DropAction defaultAction);
QCheckBox* createCopyOrMoveMenuCheckBox(QMenu* menu, const QString& label);
bool dropUrls(const QList<QUrl>& urls);
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp
index 7785b8f..9382d7c 100644
--- a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtreeview.cpp
@@ -54,7 +54,7 @@ QList<DbTreeItem *> DbTreeView::selectionItems()
{
QList<DbTreeItem*> items;
QModelIndexList selectedIndexes = selectionModel()->selectedIndexes();
- foreach (QModelIndex modIdx, selectedIndexes)
+ for (QModelIndex modIdx : selectedIndexes)
items += dynamic_cast<DbTreeItem*>(model()->itemFromIndex(modIdx));
return items;