diff options
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/windows')
27 files changed, 1232 insertions, 352 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.cpp deleted file mode 100644 index 7632c8f..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "bugreporthistorywindow.h" -#include "ui_bugreporthistorywindow.h" -#include "common/unused.h" -#include "services/config.h" -#include <QDebug> -#include <QLabel> - -CFG_KEYS_DEFINE(BugReportHistoryWindow) - -BugReportHistoryWindow::BugReportHistoryWindow(QWidget *parent) : - MdiChild(parent), - ui(new Ui::BugReportHistoryWindow) -{ - init(); -} - -BugReportHistoryWindow::~BugReportHistoryWindow() -{ - delete ui; -} - -bool BugReportHistoryWindow::restoreSessionNextTime() -{ - return false; -} - -QVariant BugReportHistoryWindow::saveSession() -{ - return QVariant(); -} - -bool BugReportHistoryWindow::restoreSession(const QVariant& sessionValue) -{ - UNUSED(sessionValue); - return false; -} - -Icon* BugReportHistoryWindow::getIconNameForMdiWindow() -{ - return ICONS.BUG_LIST; -} - -QString BugReportHistoryWindow::getTitleForMdiWindow() -{ - return tr("Reports history"); -} - -void BugReportHistoryWindow::createActions() -{ - createAction(CLEAR_HISTORY, ICONS.CLEAR_HISTORY, tr("Clear reports history"), this, SLOT(clearHistory()), ui->toolBar); - createAction(DELETE_SELECTED, ICONS.DELETE_ROW, tr("Delete selected entry"), this, SLOT(deleteSelected()), ui->toolBar); -} - -void BugReportHistoryWindow::setupDefShortcuts() -{ - setShortcutContext({ - DELETE_SELECTED - }, - Qt::WidgetWithChildrenShortcut); - - BIND_SHORTCUTS(BugReportHistoryWindow, Action); -} - -QToolBar* BugReportHistoryWindow::getToolBar(int toolbar) const -{ - UNUSED(toolbar); - return ui->toolBar; -} - -void BugReportHistoryWindow::init() -{ - ui->setupUi(this); - initActions(); - - reload(); - connect(ui->reportsList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateState())); - connect(CFG, SIGNAL(reportsHistoryRefreshNeeded()), this, SLOT(reload())); - - updateState(); -} - -void BugReportHistoryWindow::updateState() -{ - actionMap[DELETE_SELECTED]->setEnabled(ui->reportsList->selectedItems().size() > 0); -} - -void BugReportHistoryWindow::reload() -{ - static_qstring(urlTpl, "<a href=\"%1\">%2</a>"); - QString invalidUrlTpl = tr("Invalid response from server."); - - QList<Config::ReportHistoryEntryPtr> entries = CFG->getReportHistory(); - ui->reportsList->clear(); - ui->reportsList->setRowCount(entries.size()); - - QTableWidgetItem* item = nullptr; - QLabel* urlLabel = nullptr; - int row = 0; - for (const Config::ReportHistoryEntryPtr& entry : entries) - { - item = new QTableWidgetItem((entry->isFeatureRequest ? ICONS.FEATURE_REQUEST : ICONS.BUG), entry->title); - item->setData(ENTRY_ID, entry->id); - ui->reportsList->setItem(row, 0, item); - - item = new QTableWidgetItem(QDateTime::fromTime_t(entry->timestamp).toString("yyyy-MM-dd HH:mm:ss")); - ui->reportsList->setItem(row, 1, item); - - if (entry->url.startsWith("http://")) - urlLabel = new QLabel(urlTpl.arg(entry->url, entry->url)); - else - urlLabel = new QLabel(invalidUrlTpl); - - urlLabel->setOpenExternalLinks(true); - ui->reportsList->setCellWidget(row, 2, urlLabel); - - row++; - } - - ui->reportsList->setHorizontalHeaderLabels({tr("Title"), tr("Reported at"), tr("URL")}); - ui->reportsList->resizeColumnsToContents(); -} - -void BugReportHistoryWindow::clearHistory() -{ - CFG->clearReportHistory(); -} - -void BugReportHistoryWindow::deleteSelected() -{ - QList<QTableWidgetItem*> items = ui->reportsList->selectedItems(); - if (items.size() == 0) - { - qDebug() << "Called BugReportHistoryWindow::deleteSelected(), but there's no row selected."; - return; - } - - int id = items.first()->data(ENTRY_ID).toInt(); - if (id == 0) - { - qDebug() << "Called BugReportHistoryWindow::deleteSelected(), but there's no ID in selected row."; - return; - } - - CFG->deleteReport(id); -} - -bool BugReportHistoryWindow::isUncommitted() const -{ - return false; -} - -QString BugReportHistoryWindow::getQuitUncommittedConfirmMessage() const -{ - return QString(); -} diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.h deleted file mode 100644 index 42e518a..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef BUGREPORTHISTORYWINDOW_H -#define BUGREPORTHISTORYWINDOW_H - -#include "mdichild.h" -#include <QWidget> - -namespace Ui { - class BugReportHistoryWindow; -} - -CFG_KEY_LIST(BugReportHistoryWindow, QObject::tr("Reports history window"), - CFG_KEY_ENTRY(DELETE_SELECTED, Qt::Key_Delete, QObject::tr("Delete selected entry")) -) - -class GUI_API_EXPORT BugReportHistoryWindow : public MdiChild -{ - Q_OBJECT - Q_ENUMS(Action) - - public: - enum Action - { - DELETE_SELECTED, - CLEAR_HISTORY - }; - - enum ToolBar - { - TOOLBAR - }; - - explicit BugReportHistoryWindow(QWidget *parent = 0); - ~BugReportHistoryWindow(); - - bool restoreSessionNextTime(); - bool isUncommitted() const; - QString getQuitUncommittedConfirmMessage() const; - - protected: - QVariant saveSession(); - bool restoreSession(const QVariant &sessionValue); - Icon* getIconNameForMdiWindow(); - QString getTitleForMdiWindow(); - void createActions(); - void setupDefShortcuts(); - QToolBar* getToolBar(int toolbar) const; - - private: - enum UserRole - { - ENTRY_ID = Qt::UserRole + 1 - }; - - void init(); - - Ui::BugReportHistoryWindow *ui = nullptr; - - private slots: - void updateState(); - void reload(); - void clearHistory(); - void deleteSelected(); -}; - -#endif // BUGREPORTHISTORYWINDOW_H diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.ui deleted file mode 100644 index 2211ec2..0000000 --- a/SQLiteStudio3/guiSQLiteStudio/windows/bugreporthistorywindow.ui +++ /dev/null @@ -1,55 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>BugReportHistoryWindow</class> - <widget class="QWidget" name="BugReportHistoryWindow"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>300</height> - </rect> - </property> - <property name="windowTitle"> - <string notr="true">Form</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QToolBar" name="toolBar"/> - </item> - <item> - <widget class="QTableWidget" name="reportsList"> - <property name="selectionMode"> - <enum>QAbstractItemView::SingleSelection</enum> - </property> - <property name="selectionBehavior"> - <enum>QAbstractItemView::SelectRows</enum> - </property> - <property name="verticalScrollMode"> - <enum>QAbstractItemView::ScrollPerPixel</enum> - </property> - <attribute name="horizontalHeaderStretchLastSection"> - <bool>true</bool> - </attribute> - <column> - <property name="text"> - <string>Title</string> - </property> - </column> - <column> - <property name="text"> - <string>Reported at</string> - </property> - </column> - <column> - <property name="text"> - <string>URL</string> - </property> - </column> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp index 286924b..5d36683 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.cpp @@ -106,11 +106,11 @@ void CollationsEditor::init() connect(CFG_UI.Fonts.SqlEditor, SIGNAL(changed(QVariant)), this, SLOT(changeFont(QVariant))); // Language plugins - foreach (ScriptingPlugin* plugin, PLUGINS->getLoadedPlugins<ScriptingPlugin>()) + for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins<ScriptingPlugin>()) ui->langCombo->addItem(plugin->getLanguage()); // Syntax highlighting plugins - foreach (SyntaxHighlighterPlugin* plugin, PLUGINS->getLoadedPlugins<SyntaxHighlighterPlugin>()) + for (SyntaxHighlighterPlugin* plugin : PLUGINS->getLoadedPlugins<SyntaxHighlighterPlugin>()) highlighterPlugins[plugin->getLanguageName()] = plugin; updateState(); @@ -156,7 +156,7 @@ void CollationsEditor::collationSelected(int row) ui->selectedDatabasesRadio->setChecked(true); updatesForSelection = false; - currentModified = false; + currentModified = model->isModified(row); updateCurrentCollationState(); } @@ -190,7 +190,7 @@ void CollationsEditor::setFont(const QFont& font) void CollationsEditor::help() { - static const QString url = QStringLiteral("http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_collations"); + static const QString url = QStringLiteral("https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-collations"); QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode)); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h index a75e66b..7b2e469 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.h @@ -36,7 +36,7 @@ class GUI_API_EXPORT CollationsEditor : public MdiChild TOOLBAR }; - explicit CollationsEditor(QWidget *parent = 0); + explicit CollationsEditor(QWidget *parent = nullptr); ~CollationsEditor(); bool restoreSessionNextTime(); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui index 97c4e0a..454c12a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditor.ui @@ -167,7 +167,11 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_4"> <item> - <widget class="QPlainTextEdit" name="codeEdit"/> + <widget class="QPlainTextEdit" name="codeEdit"> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + </widget> </item> </layout> </widget> diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp index 05ca4e1..f04e023 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.cpp @@ -27,7 +27,7 @@ CollationsEditorModel::CollationsEditorModel(QObject *parent) : void CollationsEditorModel::clearModified() { beginResetModel(); - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) coll->modified = false; listModified = false; @@ -41,7 +41,7 @@ bool CollationsEditorModel::isModified() const if (collationList != originalCollationList) return true; - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) { if (coll->modified) return true; @@ -121,7 +121,7 @@ void CollationsEditorModel::setValid(int row, bool valid) bool CollationsEditorModel::isValid() const { - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) { if (!coll->valid) return false; @@ -133,13 +133,12 @@ void CollationsEditorModel::setData(const QList<CollationManager::CollationPtr>& { beginResetModel(); - Collation* collationPtr = nullptr; - foreach (collationPtr, collationList) + for (Collation* collationPtr : collationList) delete collationPtr; collationList.clear(); - foreach (const CollationManager::CollationPtr& coll, collations) + for (const CollationManager::CollationPtr& coll : collations) collationList << new Collation(coll); listModified = false; @@ -178,8 +177,7 @@ void CollationsEditorModel::deleteCollation(int row) QList<CollationManager::CollationPtr> CollationsEditorModel::getCollations() const { QList<CollationManager::CollationPtr> results; - - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) results << coll->data; return results; @@ -188,7 +186,7 @@ QList<CollationManager::CollationPtr> CollationsEditorModel::getCollations() con QStringList CollationsEditorModel::getCollationNames() const { QStringList names; - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) names << coll->data->name; return names; @@ -199,7 +197,7 @@ void CollationsEditorModel::validateNames() StrHash<QList<int>> counter; int row = 0; - foreach (Collation* coll, collationList) + for (Collation* coll : collationList) { coll->valid &= true; counter[coll->data->name] << row++; @@ -211,7 +209,7 @@ void CollationsEditorModel::validateNames() cntIt.next(); if (cntIt.value().size() > 1) { - foreach (int cntRow, cntIt.value()) + for (int cntRow : cntIt.value()) setValid(cntRow, false); } } @@ -265,7 +263,7 @@ QVariant CollationsEditorModel::data(const QModelIndex& index, int role) const void CollationsEditorModel::init() { - foreach (ScriptingPlugin* plugin, PLUGINS->getLoadedPlugins<ScriptingPlugin>()) + for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins<ScriptingPlugin>()) langToIcon[plugin->getLanguage()] = QIcon(plugin->getIconPath()); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h index 0c17c5b..46f7ab5 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h +++ b/SQLiteStudio3/guiSQLiteStudio/windows/collationseditormodel.h @@ -13,7 +13,7 @@ class GUI_API_EXPORT CollationsEditorModel : public QAbstractListModel public: using QAbstractItemModel::setData; - explicit CollationsEditorModel(QObject *parent = 0); + explicit CollationsEditorModel(QObject *parent = nullptr); void clearModified(); bool isModified() const; diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp index 2d8897b..1144fda 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/constrainttabmodel.cpp @@ -16,7 +16,7 @@ int ConstraintTabModel::rowCount(const QModelIndex& parent) const return 0; int cnt = 0; - foreach (SqliteCreateTable::Column* col, createTable->columns) + for (SqliteCreateTable::Column* col : createTable->columns) cnt += col->constraints.size(); cnt += createTable->constraints.size(); @@ -36,9 +36,9 @@ QVariant ConstraintTabModel::data(const QModelIndex& index, int role) const int constrIdx = index.row(); int currIdx = -1; - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) { - foreach (SqliteCreateTable::Column::Constraint* constr, column->constraints) + for (SqliteCreateTable::Column::Constraint* constr : column->constraints) { currIdx++; @@ -47,7 +47,7 @@ QVariant ConstraintTabModel::data(const QModelIndex& index, int role) const } } - foreach (SqliteCreateTable::Constraint* constr, createTable->constraints) + for (SqliteCreateTable::Constraint* constr : createTable->constraints) { currIdx++; diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/ddlhistorywindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/ddlhistorywindow.cpp index 15b49e5..795158a 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/ddlhistorywindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/ddlhistorywindow.cpp @@ -76,7 +76,7 @@ void DdlHistoryWindow::activated(const QModelIndex& current, const QModelIndex& QStringList contentEntries; QList<Config::DdlHistoryEntryPtr> entries = CFG->getDdlHistoryFor(dbName, dbFile, date); - foreach (Config::DdlHistoryEntryPtr entry, entries) + for (Config::DdlHistoryEntryPtr entry : entries) { contentEntries << templ.arg(entry->dbName).arg(entry->dbFile) .arg(entry->timestamp.toString("yyyy-MM-dd HH:mm:ss")) diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp index 56ab6fe..cd3e135 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.cpp @@ -19,12 +19,14 @@ #include "parser/parser.h" #include "dbobjectdialogs.h" #include "dialogs/exportdialog.h" +#include "themetuner.h" +#include "dialogs/bindparamsdialog.h" +#include "common/bindparam.h" #include <QComboBox> #include <QDebug> #include <QStringListModel> #include <QActionGroup> #include <QMessageBox> -#include <themetuner.h> CFG_KEYS_DEFINE(EditorWindow) EditorWindow::ResultsDisplayMode EditorWindow::resultsDisplayMode; @@ -100,6 +102,7 @@ void EditorWindow::init() createDbCombo(); initActions(); updateShortcutTips(); + setupSqlHistoryMenu(); Db* treeSelectedDb = DBTREE->getSelectedOpenDb(); if (treeSelectedDb) @@ -115,10 +118,12 @@ void EditorWindow::init() // SQL history list ui->historyList->setModel(CFG->getSqlHistoryModel()); + ui->historyList->hideColumn(0); ui->historyList->resizeColumnToContents(1); connect(ui->historyList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(historyEntrySelected(QModelIndex,QModelIndex))); connect(ui->historyList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(historyEntryActivated(QModelIndex))); + connect(ui->historyList, &QWidget::customContextMenuRequested, this, &EditorWindow::sqlHistoryContextMenuRequested); updateState(); } @@ -390,6 +395,7 @@ void EditorWindow::createActions() createAction(SHOW_PREV_TAB, tr("Show previous tab", "sql editor"), this, SLOT(showPrevTab()), this); createAction(FOCUS_RESULTS_BELOW, tr("Focus results below", "sql editor"), this, SLOT(focusResultsBelow()), this); createAction(FOCUS_EDITOR_ABOVE, tr("Focus SQL editor above", "sql editor"), this, SLOT(focusEditorAbove()), this); + createAction(DELETE_SINGLE_HISTORY_SQL, tr("Delete selected SQL history entries", "sql editor"), this, SLOT(deleteSelectedSqlHistory()), ui->historyList); // Static action triggers connect(staticActions[RESULTS_IN_TAB], SIGNAL(triggered()), this, SLOT(updateResultsDisplayMode())); @@ -470,9 +476,15 @@ void EditorWindow::updateShortcutTips() void EditorWindow::execQuery(bool explain) { QString sql = getQueryToExecute(true); + QHash<QString, QVariant> bindParams; + bool proceed = processBindParams(sql, bindParams); + if (!proceed) + return; + resultsModel->setDb(getCurrentDb()); resultsModel->setExplainMode(explain); resultsModel->setQuery(sql); + resultsModel->setParams(bindParams); resultsModel->setQueryCountLimitForSmartMode(queryLimitForSmartExecution); ui->dataView->refreshData(); updateState(); @@ -490,6 +502,61 @@ void EditorWindow::explainQuery() execQuery(true); } +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 bindTokens = tokens.filter(Token::BIND_PARAM); + + // No bind tokens? Return fast. + if (bindTokens.isEmpty()) + return true; + + // Process bind tokens, prepare list for a dialog. + static_qstring(paramTpl, ":arg%1"); + QString arg; + QVector<BindParam*> bindParams; + BindParam* bindParam = nullptr; + int i = 0; + for (const TokenPtr& token : bindTokens) + { + bindParam = new BindParam(); + bindParam->position = i; + bindParam->originalName = token->value; + bindParam->newName = paramTpl.arg(i); + bindParams << bindParam; + i++; + + token->value = bindParam->newName; + } + + // Show dialog to query user for values + BindParamsDialog dialog(MAINWINDOW); + dialog.setBindParams(bindParams); + bool accepted = (dialog.exec() == QDialog::Accepted); + + // Transfer values from dialog to arguments for query + if (accepted) + { + for (BindParam* bindParam : bindParams) + queryParams[bindParam->newName] = bindParam->value; + + sql = tokens.detokenize(); + } + + // Cleanup + for (BindParam* bindParam : bindParams) + delete bindParam; + + return accepted; +} + void EditorWindow::dbChanged() { Db* currentDb = getCurrentDb(); @@ -597,17 +664,29 @@ void EditorWindow::focusEditorAbove() void EditorWindow::historyEntrySelected(const QModelIndex& current, const QModelIndex& previous) { UNUSED(previous); - QString sql = ui->historyList->model()->index(current.row(), 4).data().toString(); + QString sql = ui->historyList->model()->index(current.row(), 5).data().toString(); ui->historyContents->setPlainText(sql); } void EditorWindow::historyEntryActivated(const QModelIndex& current) { - QString sql = ui->historyList->model()->index(current.row(), 4).data().toString(); + QString sql = ui->historyList->model()->index(current.row(), 5).data().toString(); ui->sqlEdit->setPlainText(sql); ui->tabWidget->setCurrentIndex(0); } +void EditorWindow::deleteSelectedSqlHistory() +{ + if (ui->historyList->selectionModel()->selectedIndexes().isEmpty()) + return; + + QList<qint64> ids; + for (const QModelIndex& idx : ui->historyList->selectionModel()->selectedRows(0)) + ids += idx.data().toLongLong(); + + CFG->deleteSqlHistory(ids); +} + void EditorWindow::clearHistory() { QMessageBox::StandardButton res = QMessageBox::question(this, tr("Clear execution history"), tr("Are you sure you want to erase the entire SQL execution history? " @@ -618,6 +697,19 @@ void EditorWindow::clearHistory() CFG->clearSqlHistory(); } +void EditorWindow::sqlHistoryContextMenuRequested(const QPoint &pos) +{ + actionMap[DELETE_SINGLE_HISTORY_SQL]->setEnabled(!ui->historyList->selectionModel()->selectedIndexes().isEmpty()); + + sqlHistoryMenu->popup(ui->historyList->mapToGlobal(pos)); +} + +void EditorWindow::setupSqlHistoryMenu() +{ + sqlHistoryMenu = new QMenu(this); + sqlHistoryMenu->addAction(actionMap[DELETE_SINGLE_HISTORY_SQL]); +} + void EditorWindow::exportResults() { if (!ExportManager::isAnyPluginAvailable()) diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h index 12486a8..296a9e2 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h +++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.h @@ -24,14 +24,15 @@ class SqlQueryItem; class SqlEditor; CFG_KEY_LIST(EditorWindow, QObject::tr("SQL editor window"), - CFG_KEY_ENTRY(EXEC_QUERY, Qt::Key_F9, QObject::tr("Execute query")) - CFG_KEY_ENTRY(EXPLAIN_QUERY, Qt::Key_F8, QObject::tr("Execute \"%1\" query").arg("EXPLAIN")) - CFG_KEY_ENTRY(PREV_DB, Qt::CTRL + Qt::Key_Up, QObject::tr("Switch current working database to previous on the list")) - CFG_KEY_ENTRY(NEXT_DB, Qt::CTRL + Qt::Key_Down, QObject::tr("Switch current working database to next on the list")) - CFG_KEY_ENTRY(SHOW_NEXT_TAB, Qt::ALT + Qt::Key_Right, QObject::tr("Go to next editor tab")) - CFG_KEY_ENTRY(SHOW_PREV_TAB, Qt::ALT + Qt::Key_Left, QObject::tr("Go to previous editor tab")) - CFG_KEY_ENTRY(FOCUS_RESULTS_BELOW, Qt::ALT + Qt::Key_PageDown, QObject::tr("Move keyboard input focus to the results view below")) - CFG_KEY_ENTRY(FOCUS_EDITOR_ABOVE, Qt::ALT + Qt::Key_PageUp, QObject::tr("Move keyboard input focus to the SQL editor above")) + CFG_KEY_ENTRY(EXEC_QUERY, Qt::Key_F9, QObject::tr("Execute query")) + CFG_KEY_ENTRY(EXPLAIN_QUERY, Qt::Key_F8, QObject::tr("Execute \"%1\" query").arg("EXPLAIN")) + CFG_KEY_ENTRY(PREV_DB, Qt::CTRL + Qt::Key_Up, QObject::tr("Switch current working database to previous on the list")) + CFG_KEY_ENTRY(NEXT_DB, Qt::CTRL + Qt::Key_Down, QObject::tr("Switch current working database to next on the list")) + CFG_KEY_ENTRY(SHOW_NEXT_TAB, Qt::ALT + Qt::Key_Right, QObject::tr("Go to next editor tab")) + CFG_KEY_ENTRY(SHOW_PREV_TAB, Qt::ALT + Qt::Key_Left, QObject::tr("Go to previous editor tab")) + CFG_KEY_ENTRY(FOCUS_RESULTS_BELOW, Qt::ALT + Qt::Key_PageDown, QObject::tr("Move keyboard input focus to the results view below")) + CFG_KEY_ENTRY(FOCUS_EDITOR_ABOVE, Qt::ALT + Qt::Key_PageUp, QObject::tr("Move keyboard input focus to the SQL editor above")) + CFG_KEY_ENTRY(DELETE_SINGLE_HISTORY_SQL, QKeySequence::Delete, QObject::tr("Delete selected SQL history entries")) ) class GUI_API_EXPORT EditorWindow : public MdiChild @@ -61,7 +62,8 @@ class GUI_API_EXPORT EditorWindow : public MdiChild FOCUS_EDITOR_ABOVE, CLEAR_HISTORY, EXPORT_RESULTS, - CREATE_VIEW_FROM_QUERY + CREATE_VIEW_FROM_QUERY, + DELETE_SINGLE_HISTORY_SQL }; enum ToolBar @@ -114,6 +116,8 @@ class GUI_API_EXPORT EditorWindow : public MdiChild void setupDefShortcuts(); void selectCurrentQuery(bool fallBackToPreviousIfNecessary = false); void updateShortcutTips(); + void setupSqlHistoryMenu(); + bool processBindParams(QString& sql, QHash<QString, QVariant>& queryParams); static const int queryLimitForSmartExecution = 100; @@ -129,6 +133,7 @@ class GUI_API_EXPORT EditorWindow : public MdiChild int sqlEditorNum = 1; qint64 lastQueryHistoryId = 0; QString lastSuccessfulQuery; + QMenu* sqlHistoryMenu = nullptr; private slots: void execQuery(bool explain = false); @@ -146,7 +151,9 @@ class GUI_API_EXPORT EditorWindow : public MdiChild void focusEditorAbove(); void historyEntrySelected(const QModelIndex& current, const QModelIndex& previous); void historyEntryActivated(const QModelIndex& current); + void deleteSelectedSqlHistory(); void clearHistory(); + void sqlHistoryContextMenuRequested(const QPoint &pos); void exportResults(); void createViewFromQuery(); void updateState(); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.ui index 924f895..f3f44e3 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.ui +++ b/SQLiteStudio3/guiSQLiteStudio/windows/editorwindow.ui @@ -51,6 +51,9 @@ <property name="contextMenuPolicy"> <enum>Qt::CustomContextMenu</enum> </property> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> </widget> <widget class="QWidget" name="resultsContainer" native="true"> <layout class="QVBoxLayout" name="verticalLayout_5"> @@ -118,11 +121,14 @@ <enum>Qt::Vertical</enum> </property> <widget class="QTableView" name="historyList"> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> <property name="alternatingRowColors"> <bool>true</bool> </property> <property name="selectionMode"> - <enum>QAbstractItemView::SingleSelection</enum> + <enum>QAbstractItemView::ExtendedSelection</enum> </property> <property name="selectionBehavior"> <enum>QAbstractItemView::SelectRows</enum> diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp index 1bfd1f7..9894098 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.cpp @@ -140,13 +140,13 @@ void FunctionsEditor::init() model->setData(FUNCTIONS->getAllScriptFunctions()); // Language plugins - foreach (ScriptingPlugin* plugin, PLUGINS->getLoadedPlugins<ScriptingPlugin>()) + for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins<ScriptingPlugin>()) scriptingPlugins[plugin->getLanguage()] = plugin; ui->langCombo->addItems(scriptingPlugins.keys()); // Syntax highlighting plugins - foreach (SyntaxHighlighterPlugin* plugin, PLUGINS->getLoadedPlugins<SyntaxHighlighterPlugin>()) + for (SyntaxHighlighterPlugin* plugin : PLUGINS->getLoadedPlugins<SyntaxHighlighterPlugin>()) highlighterPlugins[plugin->getLanguageName()] = plugin; updateState(); @@ -204,7 +204,7 @@ void FunctionsEditor::functionSelected(int row) // Arguments ui->argsList->clear(); QListWidgetItem* item = nullptr; - foreach (const QString& arg, model->getArguments(row)) + for (const QString& arg : model->getArguments(row)) { item = new QListWidgetItem(arg); item->setFlags(item->flags() | Qt::ItemIsEditable); @@ -232,7 +232,7 @@ void FunctionsEditor::functionSelected(int row) } updatesForSelection = false; - currentModified = false; + currentModified = model->isModified(row); updateCurrentFunctionState(); } @@ -606,7 +606,7 @@ void FunctionsEditor::applyFilter(const QString& value) void FunctionsEditor::help() { - static const QString url = QStringLiteral("http://wiki.sqlitestudio.pl/index.php/User_Manual#Custom_SQL_functions"); + static const QString url = QStringLiteral("https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#custom-sql-functions"); QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode)); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.ui b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.ui index b99efe1..17c3859 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.ui +++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditor.ui @@ -294,7 +294,11 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_4"> <item> - <widget class="QPlainTextEdit" name="initCodeEdit"/> + <widget class="QPlainTextEdit" name="initCodeEdit"> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + </widget> </item> </layout> </widget> @@ -310,7 +314,11 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_6"> <item> - <widget class="QPlainTextEdit" name="mainCodeEdit"/> + <widget class="QPlainTextEdit" name="mainCodeEdit"> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + </widget> </item> </layout> </widget> @@ -326,7 +334,11 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_7"> <item> - <widget class="QPlainTextEdit" name="finalCodeEdit"/> + <widget class="QPlainTextEdit" name="finalCodeEdit"> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + </widget> </item> </layout> </widget> diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp index cf7efdf..623ebd8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/functionseditormodel.cpp @@ -28,7 +28,7 @@ FunctionsEditorModel::FunctionsEditorModel(QObject *parent) : void FunctionsEditorModel::clearModified() { beginResetModel(); - foreach (Function* func, functionList) + for (Function* func : functionList) func->modified = false; listModified = false; @@ -42,7 +42,7 @@ bool FunctionsEditorModel::isModified() const if (functionList != originalFunctionList) return true; - foreach (Function* func, functionList) + for (Function* func : functionList) { if (func->modified) return true; @@ -62,7 +62,7 @@ void FunctionsEditorModel::setModified(int row, bool modified) bool FunctionsEditorModel::isValid() const { - foreach (Function* func, functionList) + for (Function* func : functionList) { if (!func->valid) return false; @@ -199,7 +199,7 @@ void FunctionsEditorModel::setData(const QList<FunctionManager::ScriptFunction*> functionList.clear(); - foreach (FunctionManager::ScriptFunction* func, functions) + for (FunctionManager::ScriptFunction* func : functions) functionList << new Function(func); listModified = false; @@ -239,7 +239,7 @@ QList<FunctionManager::ScriptFunction*> FunctionsEditorModel::generateFunctions( { QList<FunctionManager::ScriptFunction*> results; - foreach (Function* func, functionList) + for (Function* func : functionList) results << new FunctionManager::ScriptFunction(func->data); return results; @@ -248,7 +248,7 @@ QList<FunctionManager::ScriptFunction*> FunctionsEditorModel::generateFunctions( QStringList FunctionsEditorModel::getFunctionNames() const { QStringList names; - foreach (Function* func, functionList) + for (Function* func : functionList) names << func->data.name; return names; @@ -259,7 +259,7 @@ void FunctionsEditorModel::validateNames() StrHash<QList<int>> counter; int row = 0; - foreach (Function* func, functionList) + for (Function* func : functionList) { func->valid &= true; counter[func->data.name] << row++; @@ -271,7 +271,7 @@ void FunctionsEditorModel::validateNames() cntIt.next(); if (cntIt.value().size() > 1) { - foreach (int cntRow, cntIt.value()) + for (int cntRow : cntIt.value()) setValid(cntRow, false); } } @@ -322,7 +322,7 @@ QVariant FunctionsEditorModel::data(const QModelIndex& index, int role) const void FunctionsEditorModel::init() { - foreach (ScriptingPlugin* plugin, PLUGINS->getLoadedPlugins<ScriptingPlugin>()) + for (ScriptingPlugin* plugin : PLUGINS->getLoadedPlugins<ScriptingPlugin>()) langToIcon[plugin->getLanguage()] = QIcon(plugin->getIconPath()); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp new file mode 100644 index 0000000..ca45eff --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.cpp @@ -0,0 +1,439 @@ +#include "sqliteextensioneditor.h" +#include "sqliteextensioneditormodel.h" +#include "ui_sqliteextensioneditor.h" +#include "selectabledbmodel.h" +#include "dbtree/dbtree.h" +#include "dbtree/dbtreemodel.h" +#include "common/unused.h" +#include "uiutils.h" +#include "uiconfig.h" +#include "db/db.h" +#include "services/dbmanager.h" +#include "services/notifymanager.h" +#include "common/lazytrigger.h" +#include <QDesktopServices> +#include <QFileDialog> +#include <QSortFilterProxyModel> + +SqliteExtensionEditor::SqliteExtensionEditor(QWidget *parent) : + MdiChild(parent), + ui(new Ui::SqliteExtensionEditor) +{ + init(); +} + +SqliteExtensionEditor::~SqliteExtensionEditor() +{ + delete ui; + probingDb->closeQuiet(); +} + +bool SqliteExtensionEditor::restoreSessionNextTime() +{ + return false; +} + +bool SqliteExtensionEditor::isUncommitted() const +{ + return model->isModified(); +} + +QString SqliteExtensionEditor::getQuitUncommittedConfirmMessage() const +{ + return tr("Extension manager window has uncommitted modifications."); +} + +QVariant SqliteExtensionEditor::saveSession() +{ + return QVariant(); +} + +bool SqliteExtensionEditor::restoreSession(const QVariant& sessionValue) +{ + UNUSED(sessionValue); + return true; +} + +Icon*SqliteExtensionEditor::getIconNameForMdiWindow() +{ + return ICONS.EXTENSION; +} + +QString SqliteExtensionEditor::getTitleForMdiWindow() +{ + return tr("Extension manager"); +} + +void SqliteExtensionEditor::createActions() +{ + createAction(COMMIT, ICONS.COMMIT, tr("Commit all extension changes"), this, SLOT(commit()), ui->toolbar); + createAction(ROLLBACK, ICONS.ROLLBACK, tr("Rollback all extension changes"), this, SLOT(rollback()), ui->toolbar); + ui->toolbar->addSeparator(); + createAction(ADD, ICONS.EXTENSION_ADD, tr("Add new extension"), this, SLOT(newExtension()), ui->toolbar); + createAction(DELETE, ICONS.EXTENSION_DELETE, tr("Remove selected extension"), this, SLOT(deleteExtension()), ui->toolbar); + ui->toolbar->addSeparator(); + createAction(HELP, ICONS.HELP, tr("Editing extensions manual"), this, SLOT(help()), ui->toolbar); +} + +void SqliteExtensionEditor::setupDefShortcuts() +{ +} + +QToolBar* SqliteExtensionEditor::getToolBar(int toolbar) const +{ + UNUSED(toolbar); + return ui->toolbar; +} + +void SqliteExtensionEditor::init() +{ + ui->setupUi(this); + initActions(); + + statusUpdateTrigger = new LazyTrigger(500, this, SLOT(updateCurrentExtensionState())); + + model = new SqliteExtensionEditorModel(this); + extensionFilterModel = new QSortFilterProxyModel(this); + extensionFilterModel->setSourceModel(model); + ui->extensionList->setModel(extensionFilterModel); + + dbListModel = new SelectableDbModel(this); + dbListModel->setDisabledVersion(2); + dbListModel->setSourceModel(DBTREE->getModel()); + ui->databaseList->setModel(dbListModel); + ui->databaseList->expandAll(); + + model->setData(SQLITE_EXTENSIONS->getAllExtensions()); + + connect(ui->extensionList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(extensionSelected(QItemSelection,QItemSelection))); + connect(ui->extensionList->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateState())); + connect(ui->fileEdit, SIGNAL(textChanged(QString)), this, SLOT(updateModified())); + connect(ui->initEdit, SIGNAL(textChanged(QString)), this, SLOT(updateModified())); + connect(ui->allDatabasesRadio, SIGNAL(clicked()), this, SLOT(updateModified())); + connect(ui->selectedDatabasesRadio, SIGNAL(clicked()), this, SLOT(updateModified())); + connect(ui->fileBrowse, SIGNAL(clicked()), this, SLOT(browseForFile())); + connect(ui->fileEdit, SIGNAL(textChanged(QString)), statusUpdateTrigger, SLOT(schedule())); + connect(ui->fileEdit, SIGNAL(textChanged(QString)), this, SLOT(generateName())); + connect(ui->initEdit, SIGNAL(textChanged(QString)), statusUpdateTrigger, SLOT(schedule())); + connect(dbListModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateModified())); + + probingDb = DBLIST->createInMemDb(true); + if (!probingDb->openQuiet()) + qWarning() << "Could not open in-memory dtabase for Extension manager window. Probing files will be impossible."; + + initStateForAll(); + updateState(); + updateCurrentExtensionState(); +} + +int SqliteExtensionEditor::getCurrentExtensionRow() const +{ + QModelIndexList idxList = ui->extensionList->selectionModel()->selectedIndexes(); + if (idxList.size() == 0) + return -1; + + return idxList.first().row(); +} + +void SqliteExtensionEditor::extensionDeselected(int row) +{ + statusUpdateTrigger->cancel(); + + model->setFilePath(row, ui->fileEdit->text()); + model->setInitFunction(row, ui->initEdit->text()); + model->setAllDatabases(row, ui->allDatabasesRadio->isChecked()); + model->setModified(row, currentModified); + + if (ui->selectedDatabasesRadio->isChecked()) + model->setDatabases(row, getCurrentDatabases()); + + model->setValid(row, validateExtension(row)); +} + +void SqliteExtensionEditor::extensionSelected(int row) +{ + updatesForSelection = true; + ui->fileEdit->setText(model->getFilePath(row)); + ui->initEdit->setText(model->getInitFunction(row)); + + // Databases + dbListModel->setDatabases(model->getDatabases(row)); + ui->databaseList->expandAll(); + + if (model->getAllDatabases(row)) + ui->allDatabasesRadio->setChecked(true); + else + ui->selectedDatabasesRadio->setChecked(true); + + updatesForSelection = false; + currentModified = model->isModified(row); + + updateCurrentExtensionState(); +} + +void SqliteExtensionEditor::clearEdits() +{ + ui->fileEdit->setText(QString::null); + ui->initEdit->setText(QString::null); + ui->allDatabasesRadio->setChecked(true); +} + +void SqliteExtensionEditor::selectExtension(int row) +{ + if (!model->isValidRowIndex(row)) + return; + + ui->extensionList->selectionModel()->setCurrentIndex(model->index(row), QItemSelectionModel::Clear|QItemSelectionModel::SelectCurrent); +} + +QStringList SqliteExtensionEditor::getCurrentDatabases() const +{ + return dbListModel->getDatabases(); +} + +bool SqliteExtensionEditor::tryToLoad(const QString& filePath, const QString& initFunc, QString* resultError) +{ + if (!probingDb->isOpen()) + { + qWarning() << "Probing database is closed. Cannot evaluate if file" << filePath << "is loadable."; + return true; + } + + bool loadedOk = probingDb->loadExtension(filePath, initFunc.isEmpty() ? QString() : initFunc); + if (!loadedOk && resultError) + *resultError = probingDb->getErrorText(); + + probingDb->closeQuiet(); + probingDb->openQuiet(); + + return loadedOk; +} + +bool SqliteExtensionEditor::validateExtension(bool* fileOk, bool* initOk, QString* fileError) +{ + QString filePath = ui->fileEdit->text(); + QString initFunc = ui->initEdit->text(); + return validateExtension(filePath, initFunc, fileOk, initOk, fileError); +} + +bool SqliteExtensionEditor::validateExtension(int row) +{ + QString filePath = model->getFilePath(row); + QString initFunc = model->getInitFunction(row); + return validateExtension(filePath, initFunc); +} + +bool SqliteExtensionEditor::validateExtension(const QString& filePath, const QString& initFunc, bool* fileOk, bool* initOk, QString* fileError) +{ + bool localFileOk = true; + bool localInitOk = true; + + QFileInfo fileInfo(filePath); + if (!fileInfo.exists() || !fileInfo.isReadable()) + { + localFileOk = false; + *fileError = tr("File with given path does not exist or is not readable."); + } + else + localFileOk = tryToLoad(filePath, initFunc, fileError); + + if (!localFileOk && fileError && fileError->isEmpty()) + *fileError = tr("Unable to load extension: %1").arg(filePath); + + static const QRegularExpression initFuncRegExp("^[a-zA-Z0-9_]*$"); + localInitOk = initFuncRegExp.match(initFunc).hasMatch(); + + if (fileOk) + *fileOk = localFileOk; + + if (initOk) + *initOk = localInitOk; + + return localFileOk && localInitOk; +} + +void SqliteExtensionEditor::initStateForAll() +{ + for (int i = 0, total = model->rowCount(); i < total; ++i) + { + model->setName(i, QFileInfo(model->getFilePath(i)).baseName()); + model->setValid(i, validateExtension(i)); + } +} + +void SqliteExtensionEditor::help() +{ + static const QString url = QStringLiteral("https://github.com/pawelsalawa/sqlitestudio/wiki/User_Manual#sqlite-extensions"); + QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode)); +} + +void SqliteExtensionEditor::commit() +{ + int row = getCurrentExtensionRow(); + if (model->isValidRowIndex(row)) + extensionDeselected(row); + + QList<SqliteExtensionManager::ExtensionPtr> extensions = model->getExtensions(); + + SQLITE_EXTENSIONS->setExtensions(extensions); + model->clearModified(); + currentModified = false; + + if (model->isValidRowIndex(row)) + selectExtension(row); + + updateState(); +} + +void SqliteExtensionEditor::rollback() +{ + int selectedBefore = getCurrentExtensionRow(); + + model->setData(SQLITE_EXTENSIONS->getAllExtensions()); + currentModified = false; + clearEdits(); + + if (model->isValidRowIndex(selectedBefore)) + selectExtension(selectedBefore); + + updateState(); +} + +void SqliteExtensionEditor::newExtension() +{ + model->addExtension(SqliteExtensionManager::ExtensionPtr::create()); + selectExtension(model->rowCount() - 1); +} + +void SqliteExtensionEditor::deleteExtension() +{ + nameGenerationActive = false; + int row = getCurrentExtensionRow(); + model->deleteExtension(row); + clearEdits(); + + row = getCurrentExtensionRow(); + if (model->isValidRowIndex(row)) + extensionSelected(row); + else + updateCurrentExtensionState(); + + nameGenerationActive = true; + updateState(); +} + +void SqliteExtensionEditor::updateState() +{ + bool modified = model->isModified() || currentModified; + bool valid = model->isValid(); + + actionMap[COMMIT]->setEnabled(modified && valid); + actionMap[ROLLBACK]->setEnabled(modified); + actionMap[DELETE]->setEnabled(ui->extensionList->selectionModel()->selectedIndexes().size() > 0); + ui->databaseList->setEnabled(ui->selectedDatabasesRadio->isChecked()); +} + +void SqliteExtensionEditor::updateCurrentExtensionState() +{ + int row = getCurrentExtensionRow(); + bool validRow = model->isValidRowIndex(row); + ui->rightWidget->setEnabled(validRow); + if (!validRow) + { + setValidState(ui->fileEdit, true); + setValidState(ui->initEdit, true); + return; + } + + bool fileOk = true; + bool initOk = true; + QString fileError; + bool allOk = validateExtension(&fileOk, &initOk, &fileError); + + // Display results + setValidState(ui->fileEdit, fileOk, fileError); + setValidState(ui->initEdit, initOk, tr("Invalid initialization function name. Function name can contain only alpha-numeric characters and underscore.")); + ui->databasesGroup->setEnabled(allOk); + model->setValid(row, allOk); + + updateState(); +} + +void SqliteExtensionEditor::extensionSelected(const QItemSelection& selected, const QItemSelection& deselected) +{ + int deselCnt = deselected.indexes().size(); + int selCnt = selected.indexes().size(); + + if (deselCnt > 0) + extensionDeselected(deselected.indexes().first().row()); + + if (selCnt > 0) + extensionSelected(selected.indexes().first().row()); + + if (deselCnt > 0 && selCnt == 0) + { + currentModified = false; + clearEdits(); + } +} + +void SqliteExtensionEditor::updateModified() +{ + if (updatesForSelection) + return; + + int row = getCurrentExtensionRow(); + if (model->isValidRowIndex(row)) + { + 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 + + currentModified = (fileDiff || initDiff || allDatabasesDiff || dbDiff); + } + + statusUpdateTrigger->schedule(); +} + +void SqliteExtensionEditor::generateName() +{ + if (!nameGenerationActive) + return; + + int row = getCurrentExtensionRow(); + if (model->isValidRowIndex(row)) + model->setName(row, QFileInfo(ui->fileEdit->text()).baseName()); +} + +void SqliteExtensionEditor::applyFilter(const QString& value) +{ + int row = getCurrentExtensionRow(); + ui->extensionList->selectionModel()->clearSelection(); + + extensionFilterModel->setFilterFixedString(value); + + selectExtension(row); +} + +void SqliteExtensionEditor::browseForFile() +{ + QString dir = getFileDialogInitPath(); + QString filter = +#if defined(Q_OS_WIN) + tr("Dynamic link libraries (*.dll);;All files (*)"); +#elif defined(Q_OS_LINUX) + tr("Shared objects (*.so);;All files (*)"); +#elif defined(Q_OS_OSX) + tr("Dynamic libraries (*.dylib);;All files (*)"); +#else + tr("All files (*)"); +#endif + QString filePath = QFileDialog::getOpenFileName(this, tr("Open file"), dir, filter); + if (filePath.isNull()) + return; + + setFileDialogInitPathByFile(filePath); + + ui->fileEdit->setText(filePath); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h new file mode 100644 index 0000000..c8ea3d0 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.h @@ -0,0 +1,94 @@ +#ifndef SQLITEEXTENSIONEDITOR_H +#define SQLITEEXTENSIONEDITOR_H + +#include "icon.h" +#include "mdichild.h" +#include <QItemSelection> +#include <QWidget> + +namespace Ui { + class SqliteExtensionEditor; +} + +class QToolBar; +class SqliteExtensionEditorModel; +class QSortFilterProxyModel; +class SelectableDbModel; +class Db; +class LazyTrigger; + +class SqliteExtensionEditor : public MdiChild +{ + Q_OBJECT + + public: + enum Action + { + COMMIT, + ROLLBACK, + ADD, + DELETE, + HELP + }; + + enum ToolBar + { + TOOLBAR + }; + + explicit SqliteExtensionEditor(QWidget *parent = nullptr); + ~SqliteExtensionEditor(); + + bool restoreSessionNextTime(); + bool isUncommitted() const; + QString getQuitUncommittedConfirmMessage() const; + + protected: + QVariant saveSession(); + bool restoreSession(const QVariant &sessionValue); + Icon* getIconNameForMdiWindow(); + QString getTitleForMdiWindow(); + void createActions(); + void setupDefShortcuts(); + QToolBar* getToolBar(int toolbar) const; + + private: + void init(); + int getCurrentExtensionRow() const; + void extensionDeselected(int row); + void extensionSelected(int row); + void clearEdits(); + 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(int row); + bool validateExtension(const QString& filePath, const QString& initFunc, bool* fileOk = nullptr, bool* initOk = nullptr, QString* fileError = nullptr); + void initStateForAll(); + + Ui::SqliteExtensionEditor *ui; + SqliteExtensionEditorModel* model = nullptr; + QSortFilterProxyModel* extensionFilterModel = nullptr; + SelectableDbModel* dbListModel = nullptr; + bool currentModified = false; + bool updatesForSelection = false; + Db* probingDb = nullptr; + LazyTrigger* statusUpdateTrigger = nullptr; + bool nameGenerationActive = true; + + private slots: + void help(); + void commit(); + void rollback(); + void newExtension(); + void deleteExtension(); + void updateState(); + void updateCurrentExtensionState(); + void extensionSelected(const QItemSelection& selected, const QItemSelection& deselected); + void updateModified(); + void generateName(); + void applyFilter(const QString& value); + void browseForFile(); +}; + +#endif // SQLITEEXTENSIONEDITOR_H diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.ui b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.ui new file mode 100644 index 0000000..747aa7f --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditor.ui @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SqliteExtensionEditor</class> + <widget class="QWidget" name="SqliteExtensionEditor"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>980</width> + <height>659</height> + </rect> + </property> + <property name="windowTitle"> + <string notr="true">Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QToolBar" name="toolbar"/> + </item> + <item> + <widget class="QWidget" name="mainWidgt" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <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::Horizontal</enum> + </property> + <widget class="QWidget" name="leftWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <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="QLineEdit" name="lineEdit"> + <property name="placeholderText"> + <string>Filter extensions</string> + </property> + </widget> + </item> + <item> + <widget class="QListView" name="extensionList"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="rightWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>4</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <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="QWidget" name="widget" native="true"> + <layout class="QGridLayout" name="gridLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="3" column="0"> + <widget class="QLineEdit" name="initEdit"> + <property name="placeholderText"> + <string>Leave empty to use default function</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLineEdit" name="fileEdit"/> + </item> + <item row="1" column="1"> + <widget class="QToolButton" name="fileBrowse"> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../icons.qrc"> + <normaloff>:/icons/img/directory_open.png</normaloff>:/icons/img/directory_open.png</iconset> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="fileLabel"> + <property name="text"> + <string>Extension file</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="initLabel"> + <property name="text"> + <string>Initialization function</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="databasesGroup"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Databases</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QRadioButton" name="allDatabasesRadio"> + <property name="text"> + <string>Register in all databases</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="selectedDatabasesRadio"> + <property name="text"> + <string>Register in following databases:</string> + </property> + </widget> + </item> + <item> + <widget class="QTreeView" name="databaseList"> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../icons.qrc"/> + </resources> + <connections/> +</ui> diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.cpp new file mode 100644 index 0000000..6e94a64 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.cpp @@ -0,0 +1,234 @@ +#include "sqliteextensioneditormodel.h" +#include "iconmanager.h" +#include "common/unused.h" + +#include <QFileInfo> + +#define SETTER(X, Y) \ + if (!isValidRowIndex(row) || X == Y) \ + return; \ + \ + X = Y; \ + emitDataChanged(row); + +#define GETTER(X, Y) \ + if (!isValidRowIndex(row)) \ + return Y; \ + \ + return X; + +SqliteExtensionEditorModel::SqliteExtensionEditorModel(QObject* parent) : + QAbstractListModel(parent) +{ +} + +void SqliteExtensionEditorModel::clearModified() +{ + beginResetModel(); + for (Extension* ext : extensionList) + ext->modified = false; + + listModified = false; + originalExtensionList = extensionList; + endResetModel(); +} + +bool SqliteExtensionEditorModel::isModified() const +{ + if (extensionList != originalExtensionList) + return true; + + for (Extension* ext : extensionList) + { + if (ext->modified) + return true; + } + return false; +} + +bool SqliteExtensionEditorModel::isModified(int row) const +{ + GETTER(extensionList[row]->modified, false); +} + +void SqliteExtensionEditorModel::setModified(int row, bool modified) +{ + SETTER(extensionList[row]->modified, modified); +} + +QString SqliteExtensionEditorModel::getName(int row) const +{ + GETTER(extensionList[row]->name, QString()); +} + +void SqliteExtensionEditorModel::setName(int row, const QString& name) +{ + SETTER(extensionList[row]->name, name); + + QModelIndex idx = index(0); + emit dataChanged(idx, idx, {Qt::DisplayRole}); +} + +void SqliteExtensionEditorModel::setFilePath(int row, const QString& filePath) +{ + SETTER(extensionList[row]->data->filePath, filePath); +} + +QString SqliteExtensionEditorModel::getFilePath(int row) const +{ + GETTER(extensionList[row]->data->filePath, QString()); +} + +void SqliteExtensionEditorModel::setInitFunction(int row, const QString& initFunc) +{ + SETTER(extensionList[row]->data->initFunc, initFunc); +} + +QString SqliteExtensionEditorModel::getInitFunction(int row) const +{ + GETTER(extensionList[row]->data->initFunc, QString()); +} + +void SqliteExtensionEditorModel::setAllDatabases(int row, bool allDatabases) +{ + SETTER(extensionList[row]->data->allDatabases, allDatabases); +} + +bool SqliteExtensionEditorModel::getAllDatabases(int row) const +{ + GETTER(extensionList[row]->data->allDatabases, true); +} + +void SqliteExtensionEditorModel::setDatabases(int row, const QStringList& databases) +{ + SETTER(extensionList[row]->data->databases, databases); +} + +QStringList SqliteExtensionEditorModel::getDatabases(int row) +{ + GETTER(extensionList[row]->data->databases, QStringList()); +} + +bool SqliteExtensionEditorModel::isValid(int row) const +{ + GETTER(extensionList[row]->valid, true); +} + +void SqliteExtensionEditorModel::setValid(int row, bool valid) +{ + SETTER(extensionList[row]->valid, valid); + + QModelIndex idx = index(0); + emit dataChanged(idx, idx, {Qt::DecorationRole}); +} + +bool SqliteExtensionEditorModel::isValid() const +{ + for (Extension* ext : extensionList) + { + if (!ext->valid) + return false; + } + return true; +} + +void SqliteExtensionEditorModel::setData(const QList<SqliteExtensionManager::ExtensionPtr>& extensions) +{ + beginResetModel(); + + for (Extension* extPtr : extensionList) + delete extPtr; + + extensionList.clear(); + + for (const SqliteExtensionManager::ExtensionPtr& ext : extensions) + extensionList << new Extension(ext); + + listModified = false; + originalExtensionList = extensionList; + + endResetModel(); +} + +void SqliteExtensionEditorModel::addExtension(const SqliteExtensionManager::ExtensionPtr& extension) +{ + int row = extensionList.size(); + + beginInsertRows(QModelIndex(), row, row); + + extensionList << new Extension(extension); + listModified = true; + + endInsertRows(); +} + +void SqliteExtensionEditorModel::deleteExtension(int row) +{ + if (!isValidRowIndex(row)) + return; + + beginRemoveRows(QModelIndex(), row, row); + + delete extensionList[row]; + extensionList.removeAt(row); + + listModified = true; + + endRemoveRows(); +} + +QList<SqliteExtensionManager::ExtensionPtr> SqliteExtensionEditorModel::getExtensions() const +{ + QList<SqliteExtensionManager::ExtensionPtr> results; + for (Extension* ext : extensionList) + results << ext->data; + + return results; +} + +bool SqliteExtensionEditorModel::isValidRowIndex(int row) const +{ + return (row >= 0 && row < extensionList.size()); +} + +int SqliteExtensionEditorModel::rowCount(const QModelIndex& parent) const +{ + UNUSED(parent); + return extensionList.size(); +} + +QVariant SqliteExtensionEditorModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid() || !isValidRowIndex(index.row())) + return QVariant(); + + if (role == Qt::DisplayRole) + return getName(index.row()); + + if (role == Qt::DecorationRole) + { + QIcon icon = ICONS.EXTENSION; + if (!isValid(index.row())) + icon = Icon::merge(icon, Icon::ERROR); + + return icon; + } + + return QVariant(); +} + +void SqliteExtensionEditorModel::emitDataChanged(int row) +{ + QModelIndex idx = index(row); + emit dataChanged(idx, idx); +} + +SqliteExtensionEditorModel::Extension::Extension() +{ + data = SqliteExtensionManager::ExtensionPtr::create(); +} + +SqliteExtensionEditorModel::Extension::Extension(const SqliteExtensionManager::ExtensionPtr& other) +{ + data = SqliteExtensionManager::ExtensionPtr::create(*other); +} diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.h b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.h new file mode 100644 index 0000000..085edd9 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/windows/sqliteextensioneditormodel.h @@ -0,0 +1,65 @@ +#ifndef SQLITEEXTENSIONEDITORMODEL_H +#define SQLITEEXTENSIONEDITORMODEL_H + +#include "guiSQLiteStudio_global.h" +#include "services/sqliteextensionmanager.h" +#include <QIcon> +#include <QHash> +#include <QAbstractListModel> + +class GUI_API_EXPORT SqliteExtensionEditorModel : public QAbstractListModel +{ + Q_OBJECT + + public: + using QAbstractItemModel::setData; + + explicit SqliteExtensionEditorModel(QObject* parent = nullptr); + + void clearModified(); + bool isModified() const; + bool isModified(int row) const; + void setModified(int row, bool modified); + QString getName(int row) const; + void setName(int row, const QString& name); + void setFilePath(int row, const QString& filePath); + QString getFilePath(int row) const; + void setInitFunction(int row, const QString& initFunc); + QString getInitFunction(int row) const; + void setAllDatabases(int row, bool allDatabases); + bool getAllDatabases(int row) const; + void setDatabases(int row, const QStringList& databases); + QStringList getDatabases(int row); + bool isValid(int row) const; + void setValid(int row, bool valid); + bool isValid() const; + void setData(const QList<SqliteExtensionManager::ExtensionPtr>& extensions); + void addExtension(const SqliteExtensionManager::ExtensionPtr& extension); + void deleteExtension(int row); + QList<SqliteExtensionManager::ExtensionPtr> getExtensions() const; + bool isValidRowIndex(int row) const; + + int rowCount(const QModelIndex& parent = QModelIndex()) const; + QVariant data(const QModelIndex& index, int role) const; + + private: + struct Extension + { + Extension(); + Extension(const SqliteExtensionManager::ExtensionPtr& other); + + SqliteExtensionManager::ExtensionPtr data; + QString name; + bool modified = false; + bool valid = true; + }; + + void emitDataChanged(int row); + + QList<Extension*> extensionList; + QList<Extension*> originalExtensionList; + QHash<QString, QIcon> langToIcon; + bool listModified = false; +}; + +#endif // SQLITEEXTENSIONEDITORMODEL_H diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp index 850d8a7..0f95a98 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/tableconstraintsmodel.cpp @@ -395,7 +395,7 @@ QString TableConstraintsModel::getConstrDetails(SqliteCreateTable::Constraint* c void TableConstraintsModel::columnRenamed(SqliteCreateTable::Constraint* constr, const QString& oldColumn, const QString& newColumn) { - foreach (SqliteIndexedColumn* idxCol, constr->indexedColumns) + for (SqliteIndexedColumn* idxCol : constr->indexedColumns) { if (idxCol->name.compare(oldColumn, Qt::CaseInsensitive) == 0) { @@ -444,7 +444,7 @@ void TableConstraintsModel::columnModified(const QString& oldColumn, SqliteCreat return; int idx = 0; - foreach (SqliteCreateTable::Constraint* constr, createTable->constraints) + for (SqliteCreateTable::Constraint* constr : createTable->constraints) { if (constr->doesAffectColumn(oldColumn)) { @@ -461,7 +461,7 @@ void TableConstraintsModel::columnDeleted(const QString& column) { QList<int> toDelete; int idx = 0; - foreach (SqliteCreateTable::Constraint* constr, createTable->constraints) + for (SqliteCreateTable::Constraint* constr : createTable->constraints) { if (constr->doesAffectColumn(column)) { @@ -477,6 +477,6 @@ void TableConstraintsModel::columnDeleted(const QString& column) idx++; } - foreach (int idx, toDelete) + for (int idx : toDelete) delConstraint(idx); } diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp index 1c817de..62b6613 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablestructuremodel.cpp @@ -283,7 +283,7 @@ void TableStructureModel::moveColumnTo(int colIdx, int newIdx) QModelIndex TableStructureModel::findColumn(const QString& columnName, Qt::CaseSensitivity cs) const { int row = 0; - foreach (SqliteCreateTable::Column* col, createTable->columns) + for (SqliteCreateTable::Column* col : createTable->columns) { if (col->name.compare(columnName, cs) == 0) return createIndex(row, 0); @@ -432,7 +432,7 @@ bool TableStructureModel::isColumnPk(SqliteCreateTable::Column* column) const return true; QList<SqliteCreateTable::Constraint*> constraints = createTable->getConstraints(SqliteCreateTable::Constraint::PRIMARY_KEY); - foreach (SqliteCreateTable::Constraint* constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) if (constr->doesAffectColumn(column->name)) return true; @@ -445,7 +445,7 @@ bool TableStructureModel::isColumnFk(SqliteCreateTable::Column* column) const return true; QList<SqliteCreateTable::Constraint*> constraints = createTable->getConstraints(SqliteCreateTable::Constraint::FOREIGN_KEY); - foreach (SqliteCreateTable::Constraint* constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) if (constr->doesAffectColumn(column->name)) return true; @@ -458,7 +458,7 @@ bool TableStructureModel::isColumnUnique(SqliteCreateTable::Column* column) cons return true; QList<SqliteCreateTable::Constraint*> constraints = createTable->getConstraints(SqliteCreateTable::Constraint::UNIQUE); - foreach (SqliteCreateTable::Constraint* constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) if (constr->doesAffectColumn(column->name)) return true; @@ -471,7 +471,7 @@ bool TableStructureModel::isColumnCheck(SqliteCreateTable::Column* column) const return true; QList<SqliteCreateTable::Constraint*> constraints = createTable->getConstraints(SqliteCreateTable::Constraint::CHECK); - foreach (SqliteCreateTable::Constraint* constr, constraints) + for (SqliteCreateTable::Constraint* constr : constraints) if (constr->expr->getContextColumns(false).contains(column->name, Qt::CaseInsensitive)) return true; diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp index 286aad7..526ae1b 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/tablewindow.cpp @@ -338,10 +338,10 @@ void TableWindow::executeStructureChanges() MessageListDialog dialog(tr("Following problems will take place while modifying the table.\n" "Would you like to proceed?", "table window")); dialog.setWindowTitle(tr("Table modification", "table window")); - foreach (const QString& error, tableModifier->getErrors()) + for (const QString& error : tableModifier->getErrors()) dialog.addError(error); - foreach (const QString& warn, tableModifier->getWarnings()) + for (const QString& warn : tableModifier->getWarnings()) dialog.addWarning(warn); if (dialog.exec() != QDialog::Accepted) @@ -844,9 +844,9 @@ void TableWindow::changesSuccessfullyCommitted() tableModifier->getModifiedTriggers(), tableModifier->getModifiedViews() }; - foreach (const QStringList& objList, modifiedObjects) + for (const QStringList& objList : modifiedObjects) { - foreach (const QString& obj, objList) + for (const QString& obj : objList) { if (obj.compare(oldTable, Qt::CaseInsensitive) == 0) continue; @@ -996,7 +996,7 @@ bool TableWindow::validate(bool skipWarning) hasPk = true; SqliteCreateTable::Column::Constraint* colConstraint = nullptr; - foreach (SqliteCreateTable::Column* column, createTable->columns) + for (SqliteCreateTable::Column* column : createTable->columns) { colConstraint = column->getConstraint(SqliteCreateTable::Column::Constraint::PRIMARY_KEY); if (colConstraint) @@ -1112,8 +1112,8 @@ void TableWindow::updateDdlTab() void TableWindow::updateNewTableState() { - for (int i = 1; i < 5; i++) - ui->tabWidget->setTabEnabled(i, existingTable); + for (QWidget* tab : {ui->dataTab, ui->constraintsTab, ui->indexesTab, ui->triggersTab}) + ui->tabWidget->setTabEnabled(ui->tabWidget->indexOf(tab), existingTable); actionMap[EXPORT]->setEnabled(existingTable); actionMap[IMPORT]->setEnabled(existingTable); @@ -1466,7 +1466,7 @@ void TableWindow::updateIndexes() QTableWidgetItem* item = nullptr; int row = 0; - foreach (SqliteCreateIndexPtr index, indexes) + for (SqliteCreateIndexPtr index : indexes) { item = new QTableWidgetItem(index->index); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); @@ -1518,7 +1518,7 @@ void TableWindow::updateTriggers() QTableWidgetItem* item = nullptr; QString timeAndEvent; int row = 0; - foreach (SqliteCreateTriggerPtr trig, triggers) + for (SqliteCreateTriggerPtr trig : triggers) { item = new QTableWidgetItem(trig->trigger); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp index be805af..c7ec7d8 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp +++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.cpp @@ -259,6 +259,13 @@ void ViewWindow::init() updateQueryToolbarStatus(); updateTriggersState(); updateColumnButtons(); + updateAfterInit(); +} + +void ViewWindow::updateAfterInit() +{ + for (QWidget* tab : {ui->dataTab, ui->triggersTab}) + ui->tabWidget->setTabEnabled(ui->tabWidget->indexOf(tab), existingView); } void ViewWindow::newView() @@ -624,6 +631,7 @@ void ViewWindow::changesSuccessfullyCommitted() initView(); updateQueryToolbarStatus(); updateWindowTitle(); + updateAfterInit(); if (oldView.compare(view, Qt::CaseInsensitive) == 0) notifyInfo(tr("Committed changes for view '%1' successfully.").arg(view)); @@ -874,7 +882,7 @@ void ViewWindow::refreshTriggers() QTableWidgetItem* item = nullptr; QString event; int row = 0; - foreach (SqliteCreateTriggerPtr trig, triggers) + for (SqliteCreateTriggerPtr trig : triggers) { item = new QTableWidgetItem(trig->trigger); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); @@ -1017,10 +1025,10 @@ void ViewWindow::executeStructureChanges() MessageListDialog dialog(tr("Following problems will take place while modifying the view.\n" "Would you like to proceed?", "view window")); dialog.setWindowTitle(tr("View modification", "view window")); - foreach (const QString& error, viewModifier->getErrors()) + for (const QString& error : viewModifier->getErrors()) dialog.addError(error); - foreach (const QString& warn, viewModifier->getWarnings()) + for (const QString& warn : viewModifier->getWarnings()) dialog.addWarning(warn); if (dialog.exec() != QDialog::Accepted) diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h index 6144ad8..1a8b5b3 100644 --- a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h +++ b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.h @@ -96,6 +96,7 @@ class GUI_API_EXPORT ViewWindow : public MdiChild private: void init(); + void updateAfterInit(); void newView(); void initView(); void setupCoverWidget(); diff --git a/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui b/SQLiteStudio3/guiSQLiteStudio/windows/viewwindow.ui index 9112280..8c17205 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>2</number> + <number>0</number> </property> <widget class="QWidget" name="queryTab"> <attribute name="title"> @@ -143,7 +143,11 @@ </item> </layout> </widget> - <widget class="SqlEditor" name="queryEdit"/> + <widget class="SqlEditor" name="queryEdit"> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + </widget> </widget> </item> </layout> |
