aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp')
-rw-r--r--SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp1557
1 files changed, 1557 insertions, 0 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
new file mode 100644
index 0000000..98baaa9
--- /dev/null
+++ b/SQLiteStudio3/guiSQLiteStudio/dbtree/dbtree.cpp
@@ -0,0 +1,1557 @@
+#include "dbtree.h"
+#include "dbtreeitem.h"
+#include "ui_dbtree.h"
+#include "actionentry.h"
+#include "common/utils_sql.h"
+#include "dbtreemodel.h"
+#include "dialogs/dbdialog.h"
+#include "services/dbmanager.h"
+#include "iconmanager.h"
+#include "common/global.h"
+#include "services/notifymanager.h"
+#include "mainwindow.h"
+#include "mdiarea.h"
+#include "common/unused.h"
+#include "dbobjectdialogs.h"
+#include "common/userinputfilter.h"
+#include "common/widgetcover.h"
+#include "windows/tablewindow.h"
+#include "dialogs/indexdialog.h"
+#include "dialogs/triggerdialog.h"
+#include "dialogs/exportdialog.h"
+#include "dialogs/importdialog.h"
+#include "dialogs/populatedialog.h"
+#include "services/importmanager.h"
+#include "windows/editorwindow.h"
+#include "uiconfig.h"
+#include <QApplication>
+#include <QClipboard>
+#include <QAction>
+#include <QMenu>
+#include <QInputDialog>
+#include <QMessageBox>
+#include <QTimer>
+#include <QDebug>
+#include <QKeyEvent>
+#include <QMimeData>
+#include <dialogs/dbconverterdialog.h>
+
+CFG_KEYS_DEFINE(DbTree)
+QHash<DbTreeItem::Type,QList<DbTreeItem::Type>> DbTree::allowedTypesInside;
+QSet<DbTreeItem::Type> DbTree::draggableTypes;
+
+DbTree::DbTree(QWidget *parent) :
+ QDockWidget(parent),
+ ui(new Ui::DbTree)
+{
+ init();
+}
+
+DbTree::~DbTree()
+{
+ delete ui;
+ delete treeModel;
+}
+
+void DbTree::staticInit()
+{
+ initDndTypes();
+}
+
+void DbTree::init()
+{
+ ui->setupUi(this);
+ initDndTypes();
+
+ ui->nameFilter->setClearButtonEnabled(true);
+
+ widgetCover = new WidgetCover(this);
+ widgetCover->initWithInterruptContainer();
+ widgetCover->hide();
+ connect(widgetCover, SIGNAL(cancelClicked()), this, SLOT(interrupt()));
+
+ treeModel = new DbTreeModel();
+ treeModel->setTreeView(ui->treeView);
+
+ new UserInputFilter(ui->nameFilter, treeModel, SLOT(applyFilter(QString)));
+
+ ui->treeView->setDbTree(this);
+ ui->treeView->setModel(treeModel);
+
+ initActions();
+
+ if (DBLIST->getDbList().size() > 0)
+ treeModel->loadDbList();
+
+ connect(DBLIST, SIGNAL(dbListLoaded()), treeModel, SLOT(loadDbList()));
+ connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &DbTree::currentChanged);
+ connect(DBLIST, SIGNAL(dbConnected(Db*)), this, SLOT(dbConnected(Db*)));
+ connect(DBLIST, SIGNAL(dbDisconnected(Db*)), this, SLOT(dbDisconnected(Db*)));
+ connect(IMPORT_MANAGER, SIGNAL(schemaModified(Db*)), this, SLOT(refreshSchema(Db*)));
+
+ connect(CFG_UI.Fonts.DbTree, SIGNAL(changed(QVariant)), this, SLOT(refreshFont()));
+
+ updateActionsForCurrent();
+}
+
+void DbTree::createActions()
+{
+ createAction(COPY, ICONS.ACT_COPY, tr("Copy"), this, SLOT(copy()), this);
+ createAction(PASTE, ICONS.ACT_PASTE, tr("Paste"), this, SLOT(paste()), this);
+ createAction(SELECT_ALL, ICONS.ACT_SELECT_ALL, tr("Select all"), this, SLOT(selectAll()), this);
+ 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(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("Drop the table"), 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(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("Drop 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("Drop 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("Drop the view"), 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);
+}
+
+void DbTree::updateActionStates(const QStandardItem *item)
+{
+ QList<int> enabled;
+ const DbTreeItem* dbTreeItem = dynamic_cast<const DbTreeItem*>(item);
+ if (item != nullptr)
+ {
+ bool isDbOpen = false;
+ DbTreeItem* parentItem = dbTreeItem->parentDbTreeItem();
+ DbTreeItem* grandParentItem = parentItem ? parentItem->parentDbTreeItem() : nullptr;
+
+ // Add database should always be available, as well as a copy of an item
+ enabled << ADD_DB << COPY;
+
+ if (isMimeDataValidForItem(QApplication::clipboard()->mimeData(), dbTreeItem))
+ enabled << PASTE;
+
+ enabled << CLEAR_FILTER;
+
+ // Group actions
+ if (dbTreeItem->getType() == DbTreeItem::Type::DIR)
+ enabled << CREATE_GROUP << RENAME_GROUP << DELETE_GROUP << ADD_DB;
+
+ if (dbTreeItem->getDb())
+ {
+ enabled << DELETE_DB << EDIT_DB;
+ if (dbTreeItem->getDb()->isOpen())
+ {
+ enabled << DISCONNECT_FROM_DB << ADD_TABLE << ADD_VIEW << IMPORT_INTO_DB << EXPORT_DB << REFRESH_SCHEMA << CONVERT_DB
+ << VACUUM_DB << INTEGRITY_CHECK;
+ isDbOpen = true;
+ }
+ else
+ enabled << CONNECT_TO_DB;
+ }
+
+ if (isDbOpen)
+ {
+ switch (dbTreeItem->getType())
+ {
+ case DbTreeItem::Type::ITEM_PROTOTYPE:
+ break;
+ case DbTreeItem::Type::DIR:
+ // It's handled outside of "item with db", above
+ break;
+ case DbTreeItem::Type::DB:
+ enabled << CREATE_GROUP << DELETE_DB << EDIT_DB;
+ break;
+ case DbTreeItem::Type::TABLES:
+ break;
+ case DbTreeItem::Type::TABLE:
+ enabled << EDIT_TABLE << DEL_TABLE << EXPORT_TABLE << IMPORT_TABLE << POPULATE_TABLE << ADD_COLUMN << CREATE_SIMILAR_TABLE;
+ enabled << ADD_INDEX << ADD_TRIGGER;
+ break;
+ case DbTreeItem::Type::VIRTUAL_TABLE:
+ // TODO change below when virtual tables can be edited
+// enabled << EDIT_TABLE << DEL_TABLE;
+ enabled << DEL_TABLE;
+ break;
+ case DbTreeItem::Type::INDEXES:
+ enabled << EDIT_TABLE << DEL_TABLE;
+ enabled << ADD_INDEX << ADD_TRIGGER;
+ break;
+ case DbTreeItem::Type::INDEX:
+ enabled << EDIT_TABLE << DEL_TABLE;
+ enabled << EDIT_INDEX << DEL_INDEX;
+ enabled << ADD_INDEX << ADD_TRIGGER;
+ break;
+ case DbTreeItem::Type::TRIGGERS:
+ {
+ if (parentItem->getType() == DbTreeItem::Type::TABLE)
+ {
+ enabled << EDIT_TABLE << DEL_TABLE;
+ enabled << ADD_INDEX << ADD_TRIGGER;
+ }
+ else
+ {
+ enabled << EDIT_VIEW << DEL_VIEW;
+ enabled << ADD_TRIGGER;
+ }
+
+ enabled << ADD_TRIGGER;
+ break;
+ }
+ case DbTreeItem::Type::TRIGGER:
+ {
+ if (grandParentItem->getType() == DbTreeItem::Type::TABLE)
+ {
+ enabled << EDIT_TABLE << DEL_TABLE;
+ enabled << ADD_INDEX << ADD_TRIGGER;
+ }
+ else
+ {
+ enabled << EDIT_VIEW << DEL_VIEW;
+ enabled << ADD_TRIGGER;
+ }
+
+ enabled << EDIT_TRIGGER << DEL_TRIGGER;
+ break;
+ }
+ case DbTreeItem::Type::VIEWS:
+ break;
+ case DbTreeItem::Type::VIEW:
+ enabled << EDIT_VIEW << DEL_VIEW;
+ enabled << ADD_TRIGGER;
+ break;
+ case DbTreeItem::Type::COLUMNS:
+ enabled << EDIT_TABLE << DEL_TABLE << EXPORT_TABLE << IMPORT_TABLE << POPULATE_TABLE << ADD_COLUMN;
+ enabled << ADD_INDEX << ADD_TRIGGER;
+ break;
+ case DbTreeItem::Type::COLUMN:
+ enabled << EDIT_TABLE << DEL_TABLE << EXPORT_TABLE << IMPORT_TABLE << POPULATE_TABLE << ADD_COLUMN << DEL_COLUMN;
+ enabled << EDIT_COLUMN;
+ enabled << ADD_INDEX << ADD_TRIGGER;
+ break;
+ }
+ }
+
+ // Do we have any deletable object selected? If yes, enable "Del" action.
+ bool enableDel = false;
+ for (DbTreeItem* selItem : getModel()->getItemsForIndexes(getView()->getSelectedIndexes()))
+ {
+ switch (selItem->getType())
+ {
+ case DbTreeItem::Type::COLUMN:
+ case DbTreeItem::Type::DB:
+ case DbTreeItem::Type::DIR:
+ case DbTreeItem::Type::INDEX:
+ case DbTreeItem::Type::TABLE:
+ case DbTreeItem::Type::TRIGGER:
+ case DbTreeItem::Type::VIEW:
+ case DbTreeItem::Type::VIRTUAL_TABLE:
+ enableDel = true;
+ break;
+ case DbTreeItem::Type::COLUMNS:
+ case DbTreeItem::Type::INDEXES:
+ case DbTreeItem::Type::ITEM_PROTOTYPE:
+ case DbTreeItem::Type::TABLES:
+ case DbTreeItem::Type::TRIGGERS:
+ case DbTreeItem::Type::VIEWS:
+ break;
+ }
+
+ if (enableDel)
+ {
+ enabled << DEL_SELECTED;
+ break;
+ }
+ }
+ }
+ else
+ {
+ enabled << CREATE_GROUP << ADD_DB;
+ }
+
+ if (treeModel->rowCount() > 0)
+ enabled << SELECT_ALL; // if there's at least 1 item, enable this
+
+ enabled << REFRESH_SCHEMAS;
+
+ foreach (int action, actionMap.keys())
+ setActionEnabled(action, enabled.contains(action));
+}
+
+void DbTree::setupActionsForMenu(DbTreeItem* currItem, QMenu* contextMenu)
+{
+ QList<ActionEntry> actions;
+
+ ActionEntry dbEntry(ICONS.DATABASE, tr("Datatabase"));
+ dbEntry += ADD_DB;
+ dbEntry += EDIT_DB;
+ dbEntry += DELETE_DB;
+
+ ActionEntry dbEntryExt(ICONS.DATABASE, tr("Datatabase"));
+ dbEntryExt += CONNECT_TO_DB;
+ dbEntryExt += DISCONNECT_FROM_DB;
+ dbEntryExt += _separator;
+ dbEntryExt += REFRESH_SCHEMA;
+ dbEntryExt += _separator;
+ dbEntryExt += ADD_DB;
+ dbEntryExt += EDIT_DB;
+ dbEntryExt += DELETE_DB;
+
+ ActionEntry groupEntry(ICONS.DIRECTORY, tr("Grouping"));
+ groupEntry += CREATE_GROUP;
+ groupEntry += RENAME_GROUP;
+ groupEntry += DELETE_GROUP;
+
+ if (currItem)
+ {
+ DbTreeItem* parentItem = currItem->parentDbTreeItem();
+ DbTreeItem* grandParentItem = parentItem ? parentItem->parentDbTreeItem() : nullptr;
+ DbTreeItem::Type itemType = currItem->getType();
+ switch (itemType)
+ {
+ case DbTreeItem::Type::DIR:
+ {
+ actions += ActionEntry(CREATE_GROUP);
+ actions += ActionEntry(RENAME_GROUP);
+ actions += ActionEntry(DELETE_GROUP);
+ actions += ActionEntry(_separator);
+ actions += dbEntry;
+ break;
+ }
+ case DbTreeItem::Type::DB:
+ {
+ if (currItem->getDb()->isValid())
+ {
+ actions += ActionEntry(CONNECT_TO_DB);
+ actions += ActionEntry(DISCONNECT_FROM_DB);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_DB);
+ actions += ActionEntry(EDIT_DB);
+ actions += ActionEntry(DELETE_DB);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(ADD_INDEX);
+ actions += ActionEntry(ADD_TRIGGER);
+ actions += ActionEntry(ADD_VIEW);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(REFRESH_SCHEMA);
+ actions += ActionEntry(IMPORT_INTO_DB);
+ actions += ActionEntry(EXPORT_DB);
+ actions += ActionEntry(CONVERT_DB);
+ actions += ActionEntry(VACUUM_DB);
+ actions += ActionEntry(INTEGRITY_CHECK);
+ actions += ActionEntry(_separator);
+ }
+ else
+ {
+ actions += ActionEntry(ADD_DB);
+ actions += ActionEntry(EDIT_DB);
+ actions += ActionEntry(DELETE_DB);
+ actions += ActionEntry(_separator);
+ }
+ break;
+ }
+ case DbTreeItem::Type::TABLES:
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::TABLE:
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(EDIT_TABLE);
+ actions += ActionEntry(DEL_TABLE);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_COLUMN);
+ actions += ActionEntry(ADD_INDEX);
+ actions += ActionEntry(ADD_TRIGGER);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(IMPORT_TABLE);
+ actions += ActionEntry(EXPORT_TABLE);
+ actions += ActionEntry(POPULATE_TABLE);
+ actions += ActionEntry(CREATE_SIMILAR_TABLE);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::VIRTUAL_TABLE:
+ actions += ActionEntry(ADD_TABLE);
+ //actions += ActionEntry(EDIT_TABLE); // TODO uncomment when virtual tables have their own edition window
+ actions += ActionEntry(DEL_TABLE);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::INDEXES:
+ actions += ActionEntry(ADD_INDEX);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(EDIT_TABLE);
+ actions += ActionEntry(DEL_TABLE);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::INDEX:
+ actions += ActionEntry(ADD_INDEX);
+ actions += ActionEntry(EDIT_INDEX);
+ actions += ActionEntry(DEL_INDEX);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(EDIT_TABLE);
+ actions += ActionEntry(DEL_TABLE);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::TRIGGERS:
+ {
+ actions += ActionEntry(ADD_TRIGGER);
+ actions += ActionEntry(_separator);
+ if (parentItem->getType() == DbTreeItem::Type::TABLE)
+ {
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(EDIT_TABLE);
+ actions += ActionEntry(DEL_TABLE);
+ }
+ else
+ {
+ actions += ActionEntry(ADD_VIEW);
+ actions += ActionEntry(EDIT_VIEW);
+ actions += ActionEntry(DEL_VIEW);
+ }
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ }
+ case DbTreeItem::Type::TRIGGER:
+ {
+ actions += ActionEntry(ADD_TRIGGER);
+ actions += ActionEntry(EDIT_TRIGGER);
+ actions += ActionEntry(DEL_TRIGGER);
+ actions += ActionEntry(_separator);
+ if (grandParentItem->getType() == DbTreeItem::Type::TABLE)
+ {
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(EDIT_TABLE);
+ actions += ActionEntry(DEL_TABLE);
+ }
+ else
+ {
+ actions += ActionEntry(ADD_VIEW);
+ actions += ActionEntry(EDIT_VIEW);
+ actions += ActionEntry(DEL_VIEW);
+ }
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ }
+ case DbTreeItem::Type::VIEWS:
+ actions += ActionEntry(ADD_VIEW);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::VIEW:
+ actions += ActionEntry(ADD_VIEW);
+ actions += ActionEntry(EDIT_VIEW);
+ actions += ActionEntry(DEL_VIEW);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_TRIGGER);
+ actions += ActionEntry(EDIT_TRIGGER);
+ actions += ActionEntry(DEL_TRIGGER);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::COLUMNS:
+ actions += ActionEntry(ADD_COLUMN);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(EDIT_TABLE);
+ actions += ActionEntry(DEL_TABLE);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_INDEX);
+ actions += ActionEntry(ADD_TRIGGER);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(IMPORT_TABLE);
+ actions += ActionEntry(EXPORT_TABLE);
+ actions += ActionEntry(POPULATE_TABLE);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::COLUMN:
+ actions += ActionEntry(ADD_COLUMN);
+ actions += ActionEntry(EDIT_COLUMN);
+ actions += ActionEntry(DEL_COLUMN);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_TABLE);
+ actions += ActionEntry(EDIT_TABLE);
+ actions += ActionEntry(DEL_TABLE);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(ADD_INDEX);
+ actions += ActionEntry(ADD_TRIGGER);
+ actions += ActionEntry(_separator);
+ actions += ActionEntry(IMPORT_TABLE);
+ actions += ActionEntry(EXPORT_TABLE);
+ actions += ActionEntry(POPULATE_TABLE);
+ actions += ActionEntry(_separator);
+ actions += dbEntryExt;
+ break;
+ case DbTreeItem::Type::ITEM_PROTOTYPE:
+ break;
+ }
+
+ actions += ActionEntry(_separator);
+
+ if (itemType == DbTreeItem::Type::DB)
+ actions += groupEntry;
+ }
+ else
+ {
+ actions += dbEntry;
+ actions += ActionEntry(_separator);
+ actions += groupEntry;
+ }
+
+ actions += COPY;
+ actions += PASTE;
+ actions += _separator;
+ actions += DEL_SELECTED;
+ actions += _separator;
+ actions += SELECT_ALL;
+ actions += ActionEntry(REFRESH_SCHEMAS);
+
+ QMenu* subMenu = nullptr;
+ foreach (ActionEntry actionEntry, actions)
+ {
+ switch (actionEntry.type)
+ {
+ case ActionEntry::Type::SINGLE:
+ {
+ if (actionEntry.action == DbTree::_separator)
+ {
+ contextMenu->addSeparator();
+ break;
+ }
+ contextMenu->addAction(actionMap[actionEntry.action]);
+ break;
+ }
+ case ActionEntry::Type::SUB_MENU:
+ {
+ subMenu = contextMenu->addMenu(actionEntry.subMenuIcon, actionEntry.subMenuLabel);
+ foreach (Action action, actionEntry.actions)
+ {
+ if (action == DbTree::_separator)
+ {
+ subMenu->addSeparator();
+ continue;
+ }
+ subMenu->addAction(actionMap[action]);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void DbTree::initDndTypes()
+{
+ draggableTypes << DbTreeItem::Type::TABLE << DbTreeItem::Type::VIEW << DbTreeItem::Type::DIR << DbTreeItem::Type::DB;
+
+ allowedTypesInside[DbTreeItem::Type::DIR] << DbTreeItem::Type::DB << DbTreeItem::Type::DIR;
+ allowedTypesInside[DbTreeItem::Type::DB] << DbTreeItem::Type::TABLE << DbTreeItem::Type::VIEW;
+ allowedTypesInside[DbTreeItem::Type::TABLES] << DbTreeItem::Type::TABLE << DbTreeItem::Type::VIEW;
+ allowedTypesInside[DbTreeItem::Type::TABLE] << DbTreeItem::Type::TABLE << DbTreeItem::Type::VIEW;
+ allowedTypesInside[DbTreeItem::Type::VIEWS] << DbTreeItem::Type::TABLE << DbTreeItem::Type::VIEW;
+ allowedTypesInside[DbTreeItem::Type::VIEW] << DbTreeItem::Type::TABLE << DbTreeItem::Type::VIEW;
+}
+
+QVariant DbTree::saveSession()
+{
+ treeModel->storeGroups();
+ return QVariant();
+}
+
+void DbTree::restoreSession(const QVariant& sessionValue)
+{
+ UNUSED(sessionValue);
+}
+
+DbTreeModel* DbTree::getModel() const
+{
+ return treeModel;
+}
+
+DbTreeView*DbTree::getView() const
+{
+ return ui->treeView;
+}
+
+bool DbTree::isMimeDataValidForItem(const QMimeData* mimeData, const DbTreeItem* item)
+{
+ if (mimeData->formats().contains(DbTreeModel::MIMETYPE))
+ return areDbTreeItemsValidForItem(getModel()->getDragItems(mimeData), item);
+ else if (mimeData->hasUrls())
+ return areUrlsValidForItem(mimeData->urls(), item);
+
+ return false;
+}
+
+bool DbTree::isItemDraggable(const DbTreeItem* item)
+{
+ return item && draggableTypes.contains(item->getType());
+}
+
+bool DbTree::areDbTreeItemsValidForItem(QList<DbTreeItem*> srcItems, const DbTreeItem* dstItem)
+{
+ QSet<Db*> srcDbs;
+ QList<DbTreeItem::Type> srcTypes;
+ DbTreeItem::Type dstType = DbTreeItem::Type::DIR; // the empty space is treated as group
+ if (dstItem)
+ dstType = dstItem->getType();
+
+ for (DbTreeItem* srcItem : srcItems)
+ {
+ if (srcItem)
+ srcTypes << srcItem->getType();
+ else
+ srcTypes << DbTreeItem::Type::ITEM_PROTOTYPE;
+
+ if (srcItem->getDb())
+ srcDbs << srcItem->getDb();
+ }
+
+ for (DbTreeItem::Type srcType : srcTypes)
+ {
+ if (!allowedTypesInside[dstType].contains(srcType))
+ return false;
+
+ if (dstType == DbTreeItem::Type::DB && !dstItem->getDb()->isOpen())
+ return false;
+ }
+
+ if (dstItem && dstItem->getDb() && srcDbs.contains(dstItem->getDb()))
+ return false;
+
+ return true;
+}
+
+bool DbTree::areUrlsValidForItem(const QList<QUrl>& srcUrls, const DbTreeItem* dstItem)
+{
+ UNUSED(dstItem);
+ for (const QUrl& srcUrl : srcUrls)
+ {
+ if (!srcUrl.isLocalFile())
+ return false;
+ }
+ return true;
+}
+
+void DbTree::showWidgetCover()
+{
+ widgetCover->show();
+}
+
+void DbTree::hideWidgetCover()
+{
+ widgetCover->hide();
+}
+
+void DbTree::setSelectedItem(DbTreeItem *item)
+{
+ ui->treeView->setCurrentIndex(item->index());
+ ui->treeView->selectionModel()->select(item->index(), QItemSelectionModel::Clear|QItemSelectionModel::SelectCurrent);
+}
+
+QToolBar* DbTree::getToolBar(int toolbar) const
+{
+ UNUSED(toolbar);
+ return nullptr;
+}
+
+void DbTree::setActionEnabled(int action, bool enabled)
+{
+ actionMap[action]->setEnabled(enabled);
+}
+
+Db* DbTree::getSelectedDb()
+{
+ DbTreeItem* item = ui->treeView->currentItem();
+ if (!item)
+ return nullptr;
+
+ return item->getDb();
+}
+
+Db* DbTree::getSelectedOpenDb()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isOpen())
+ return nullptr;
+
+ return db;
+}
+
+TableWindow* DbTree::openTable(DbTreeItem* item)
+{
+ QString database = QString::null; // TODO implement this when named databases (attached) are handled by dbtree.
+ Db* db = item->getDb();
+ return openTable(db, database, item->text());
+}
+
+TableWindow* DbTree::openTable(Db* db, const QString& database, const QString& table)
+{
+ DbObjectDialogs dialogs(db);
+ return dialogs.editTable(database, table);
+}
+
+void DbTree::editIndex(DbTreeItem* item)
+{
+ //QString database = QString::null; // TODO implement this when named databases (attached) are handled by dbtree.
+ Db* db = item->getDb();
+
+ DbObjectDialogs dialogs(db);
+ dialogs.editIndex(item->text());
+}
+
+ViewWindow* DbTree::openView(DbTreeItem* item)
+{
+ QString database = QString::null; // TODO implement this when named databases (attached) are handled by dbtree.
+ Db* db = item->getDb();
+ return openView(db, database, item->text());
+}
+
+ViewWindow* DbTree::openView(Db* db, const QString& database, const QString& view)
+{
+ DbObjectDialogs dialogs(db);
+ return dialogs.editView(database, view);
+}
+
+TableWindow* DbTree::newTable(DbTreeItem* item)
+{
+ Db* db = item->getDb();
+
+ DbObjectDialogs dialogs(db);
+ return dialogs.addTable();
+}
+
+ViewWindow* DbTree::newView(DbTreeItem* item)
+{
+ Db* db = item->getDb();
+
+ DbObjectDialogs dialogs(db);
+ return dialogs.addView();
+}
+
+void DbTree::editTrigger(DbTreeItem* item)
+{
+ //QString database = QString::null; // TODO implement this when named databases (attached) are handled by dbtree.
+ Db* db = item->getDb();
+
+ DbObjectDialogs dialogs(db);
+ dialogs.editTrigger(item->text());
+}
+
+void DbTree::delSelectedObject()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db)
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ if (!item)
+ return;
+
+ DbObjectDialogs dialogs(db);
+ dialogs.dropObject(item->text()); // TODO add database prefix when supported
+}
+
+void DbTree::filterUndeletableItems(QList<DbTreeItem*>& items)
+{
+ QMutableListIterator<DbTreeItem*> it(items);
+ DbTreeItem::Type type;
+ while (it.hasNext())
+ {
+ type = it.next()->getType();
+ switch (type)
+ {
+ case DbTreeItem::Type::TABLES:
+ case DbTreeItem::Type::INDEXES:
+ case DbTreeItem::Type::TRIGGERS:
+ case DbTreeItem::Type::VIEWS:
+ case DbTreeItem::Type::COLUMNS:
+ case DbTreeItem::Type::ITEM_PROTOTYPE:
+ it.remove();
+ break;
+ case DbTreeItem::Type::DIR:
+ case DbTreeItem::Type::DB:
+ case DbTreeItem::Type::TABLE:
+ case DbTreeItem::Type::VIRTUAL_TABLE:
+ case DbTreeItem::Type::INDEX:
+ case DbTreeItem::Type::TRIGGER:
+ case DbTreeItem::Type::VIEW:
+ case DbTreeItem::Type::COLUMN:
+ break;
+ }
+ }
+}
+
+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))
+ {
+ if (items.contains(pathItem) && pathItem->getType() != DbTreeItem::Type::DIR)
+ {
+ it.remove();
+ break;
+ }
+ }
+ }
+}
+
+void DbTree::deleteItem(DbTreeItem* item)
+{
+ switch (item->getType())
+ {
+ case DbTreeItem::Type::DIR:
+ treeModel->deleteGroup(item);
+ break;
+ case DbTreeItem::Type::DB:
+ DBLIST->removeDb(item->getDb());
+ break;
+ case DbTreeItem::Type::TABLE:
+ case DbTreeItem::Type::VIRTUAL_TABLE:
+ case DbTreeItem::Type::INDEX:
+ case DbTreeItem::Type::TRIGGER:
+ case DbTreeItem::Type::VIEW:
+ {
+ Db* db = item->getDb();
+ DbObjectDialogs dialogs(db);
+ dialogs.setNoConfirmation(true); // confirmation is done in deleteSelected()
+ dialogs.setNoSchemaRefreshing(true); // we will refresh after all items are deleted
+ dialogs.dropObject(item->text()); // TODO database name when supported
+ break;
+ }
+ case DbTreeItem::Type::TABLES:
+ case DbTreeItem::Type::INDEXES:
+ case DbTreeItem::Type::TRIGGERS:
+ case DbTreeItem::Type::VIEWS:
+ case DbTreeItem::Type::COLUMNS:
+ case DbTreeItem::Type::COLUMN:
+ case DbTreeItem::Type::ITEM_PROTOTYPE:
+ break;
+ }
+}
+
+
+void DbTree::refreshSchema(Db* db)
+{
+ if (!db)
+ return;
+
+ if (!db->isOpen())
+ return;
+
+ treeModel->refreshSchema(db);
+}
+
+void DbTree::copy()
+{
+ QMimeData* mimeData = treeModel->mimeData(ui->treeView->getSelectedIndexes());
+ QApplication::clipboard()->setMimeData(mimeData);
+}
+
+void DbTree::paste()
+{
+ DbTreeItem* currItem = ui->treeView->currentItem();
+ QModelIndex idx;
+ if (currItem)
+ idx = currItem->index();
+
+ treeModel->pasteData(QApplication::clipboard()->mimeData(), -1, -1, idx, Qt::CopyAction);
+}
+
+void DbTree::selectAll()
+{
+ ui->treeView->selectAll();
+}
+
+void DbTree::createGroup()
+{
+ QStringList existingItems;
+ QStandardItem* currItem = ui->treeView->getItemForAction(true);
+ DbTreeItem* itemToMove = nullptr;
+ if (currItem)
+ {
+ // Look for any directory in the path to the root, starting with the current item
+ do
+ {
+ if (dynamic_cast<DbTreeItem*>(currItem)->getType() == DbTreeItem::Type::DIR)
+ {
+ existingItems = dynamic_cast<DbTreeItem*>(currItem)->childNames();
+ break;
+ }
+ else
+ {
+ itemToMove = dynamic_cast<DbTreeItem*>(currItem);
+ }
+ }
+ while ((currItem = currItem->parent()) != nullptr);
+ }
+
+ // No luck? Use root.
+ if (!currItem)
+ currItem = treeModel->root();
+
+ QString name = "";
+ while (existingItems.contains(name = QInputDialog::getText(this, tr("Create group"), tr("Group name"))) ||
+ (name.isEmpty() && !name.isNull()))
+ {
+ QMessageBox::information(this, tr("Create directory"), tr("Entry with name %1 already exists in directory %2.")
+ .arg(name).arg(currItem->text()), QMessageBox::Ok);
+ }
+
+ if (name.isNull())
+ return;
+
+ DbTreeItem* newDir = treeModel->createGroup(name, currItem);
+ if (itemToMove)
+ treeModel->move(itemToMove, newDir);
+}
+
+void DbTree::deleteGroup()
+{
+ DbTreeItem* item = ui->treeView->getItemForAction();
+ if (!item)
+ return;
+
+ QMessageBox::StandardButton resp = QMessageBox::question(this, tr("Delete group"),
+ tr("Are you sure you want to delete group %1?\nAll objects from this group will be moved to parent group.").arg(item->text().left(ITEM_TEXT_LIMIT)));
+
+ if (resp != QMessageBox::Yes)
+ return;
+
+ treeModel->deleteGroup(item);
+}
+
+void DbTree::renameGroup()
+{
+ DbTreeItem* item = ui->treeView->getItemForAction();
+ if (!item)
+ return;
+
+ ui->treeView->edit(item->index());
+}
+
+void DbTree::addDb()
+{
+ DbTreeItem* currItem = ui->treeView->getItemForAction();
+
+ DbDialog dialog(DbDialog::ADD, this);
+ if (!dialog.exec())
+ return;
+
+ QString name = dialog.getName();
+
+ // If we created db in some group, move it there
+ if (currItem && currItem->getType() == DbTreeItem::Type::DIR)
+ {
+ DbTreeItem* dbItem = dynamic_cast<DbTreeItem*>(treeModel->findItem(DbTreeItem::Type::DB, name));
+ if (!dbItem)
+ {
+ qWarning() << "Created and added db to tree, but could not find it while trying to move it to target group" << currItem->text();
+ return;
+ }
+ treeModel->move(dbItem, currItem);
+ }
+}
+
+void DbTree::editDb()
+{
+ Db* db = getSelectedDb();
+ if (!db)
+ return;
+
+ bool perm = CFG->isDbInConfig(db->getName());
+
+ DbDialog dialog(DbDialog::EDIT, this);
+ dialog.setDb(db);
+ dialog.setPermanent(perm);
+ dialog.exec();
+}
+
+void DbTree::removeDb()
+{
+ Db* db = getSelectedDb();
+ if (!db)
+ return;
+
+ QMessageBox::StandardButton result = QMessageBox::question(this, tr("Delete database"), tr("Are you sure you want to delete database '%1'?").arg(db->getName().left(ITEM_TEXT_LIMIT)));
+ if (result != QMessageBox::Yes)
+ return;
+
+ DBLIST->removeDb(db);
+}
+
+void DbTree::connectToDb()
+{
+ Db* db = getSelectedDb();
+ if (!db)
+ return;
+
+ if (db->isOpen())
+ return;
+
+ db->open();
+}
+
+void DbTree::disconnectFromDb()
+{
+ Db* db = getSelectedDb();
+ if (!db)
+ return;
+
+ if (!db->isOpen())
+ return;
+
+ db->close();
+}
+
+
+void DbTree::import()
+{
+ if (!ImportManager::isAnyPluginAvailable())
+ {
+ notifyError(tr("Cannot import, because no import plugin is loaded."));
+ return;
+ }
+
+ ImportDialog dialog(this);
+ Db* db = getSelectedDb();
+ if (db)
+ dialog.setDb(db);
+
+ dialog.exec();
+}
+
+void DbTree::exportDb()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isValid())
+ return;
+
+ if (!ExportManager::isAnyPluginAvailable())
+ {
+ notifyError(tr("Cannot export, because no export plugin is loaded."));
+ return;
+ }
+
+ ExportDialog dialog(this);
+ dialog.setDatabaseMode(db);
+ dialog.exec();
+}
+
+void DbTree::addTable()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ newTable(item);
+}
+
+void DbTree::editTable()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString table = item->getTable();
+ if (table.isNull())
+ {
+ qWarning() << "Tried to edit table, while table wasn't selected in DbTree.";
+ return;
+ }
+
+ openTable(db, QString::null, table); // TODO put database name when supported
+}
+
+void DbTree::delTable()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString table = item->getTable();
+ if (table.isNull())
+ {
+ qWarning() << "Tried to drop table, while table wasn't selected in DbTree.";
+ return;
+ }
+
+ DbObjectDialogs dialogs(db);
+ dialogs.dropObject(table); // TODO add database prefix when supported
+}
+
+void DbTree::addIndex()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString table = item->getTable();
+
+ DbObjectDialogs dialogs(db);
+ dialogs.addIndex(table);
+}
+
+void DbTree::editIndex()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString index = item->getIndex();
+
+ DbObjectDialogs dialogs(db);
+ dialogs.editIndex(index);
+}
+
+void DbTree::delIndex()
+{
+ delSelectedObject();
+}
+
+void DbTree::addTrigger()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db)
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString table = item->getTable();
+ QString view = item->getView();
+
+ DbObjectDialogs dialogs(db);
+ dialogs.addTrigger(table, view);
+}
+
+void DbTree::editTrigger()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString trigger = item->getTrigger();
+
+ DbObjectDialogs dialogs(db);
+ dialogs.editTrigger(trigger);
+}
+
+void DbTree::delTrigger()
+{
+ delSelectedObject();
+}
+
+void DbTree::addView()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ newView(item);
+}
+
+void DbTree::editView()
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString view = item->getView();
+ if (view.isNull())
+ {
+ qWarning() << "Tried to edit view, while view wasn't selected in DbTree.";
+ return;
+ }
+
+ openView(db, QString(), view); // TODO handle named database when supported
+}
+
+void DbTree::delView()
+{
+ delSelectedObject();
+}
+
+void DbTree::exportTable()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString table = item->getTable();
+ if (table.isNull())
+ {
+ qWarning() << "Tried to export table, while table wasn't selected in DbTree.";
+ return;
+ }
+
+ if (!ExportManager::isAnyPluginAvailable())
+ {
+ notifyError(tr("Cannot export, because no export plugin is loaded."));
+ return;
+ }
+
+ ExportDialog dialog(this);
+ dialog.setTableMode(db, table);
+ dialog.exec();
+}
+
+void DbTree::importTable()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString table = item->getTable();
+ if (table.isNull())
+ {
+ qWarning() << "Tried to import into table, while table wasn't selected in DbTree.";
+ return;
+ }
+
+ if (!ImportManager::isAnyPluginAvailable())
+ {
+ notifyError(tr("Cannot import, because no import plugin is loaded."));
+ return;
+ }
+
+ ImportDialog dialog(this);
+ dialog.setDbAndTable(db, table);
+ dialog.exec();
+}
+
+void DbTree::populateTable()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString table = item->getTable();
+ if (table.isNull())
+ {
+ qWarning() << "Tried to populate table, while table wasn't selected in DbTree.";
+ return;
+ }
+
+ PopulateDialog dialog(this);
+ dialog.setDbAndTable(db, table);
+ dialog.exec();
+}
+
+void DbTree::addColumn()
+{
+ DbTreeItem* item = ui->treeView->currentItem();
+ if (!item)
+ return;
+
+ addColumn(item);
+}
+
+void DbTree::editColumn()
+{
+ DbTreeItem* item = ui->treeView->currentItem();
+ if (!item)
+ return;
+
+ editColumn(item);
+}
+
+void DbTree::delColumn()
+{
+ DbTreeItem* item = ui->treeView->currentItem();
+ if (!item)
+ return;
+
+ delColumn(item);
+}
+
+void DbTree::convertDb()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbConverterDialog dialog(this);
+ dialog.setDb(db);
+ dialog.exec();
+}
+
+void DbTree::vacuumDb()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isValid())
+ return;
+
+ SqlQueryPtr res = db->exec("VACUUM;");
+ if (res->isError())
+ notifyError(tr("Error while executing VACUUM on the database %1: %2").arg(db->getName(), res->getErrorText()));
+ else
+ notifyInfo(tr("VACUUM execution finished successfully."));
+}
+
+void DbTree::integrityCheck()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isValid())
+ return;
+
+ EditorWindow* win = MAINWINDOW->openSqlEditor();
+ if (!win->setCurrentDb(db))
+ {
+ qCritical() << "Created EditorWindow had not got requested database:" << db->getName();
+ win->close();
+ return;
+ }
+
+ win->getMdiWindow()->rename(tr("Integrity check (%1)").arg(db->getName()));
+ win->setContents("PRAGMA integrity_check;");
+ win->execute();
+}
+
+void DbTree::createSimilarTable()
+{
+ Db* db = getSelectedDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* item = ui->treeView->currentItem();
+ QString table = item->getTable();
+ if (table.isNull())
+ {
+ qWarning() << "Tried to clone table, while table wasn't selected in DbTree.";
+ return;
+ }
+
+ DbObjectDialogs dialog(db);
+ dialog.addTableSimilarTo(QString(), table);
+}
+
+void DbTree::addColumn(DbTreeItem* item)
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ DbTreeItem* tableItem = nullptr;
+
+ if (item->getType() == DbTreeItem::Type::TABLE)
+ tableItem = item;
+ else
+ tableItem = item->findParentItem(DbTreeItem::Type::TABLE);
+
+ if (!tableItem)
+ return;
+
+ TableWindow* tableWin = openTable(tableItem);
+ tableWin->addColumn();
+}
+
+void DbTree::editColumn(DbTreeItem* item)
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ if (item->getType() != DbTreeItem::Type::COLUMN)
+ return;
+
+ DbTreeItem* tableItem = item->findParentItem(DbTreeItem::Type::TABLE);
+ if (!tableItem)
+ return;
+
+ TableWindow* tableWin = openTable(tableItem);
+ tableWin->editColumn(item->text());
+}
+
+void DbTree::delColumn(DbTreeItem* item)
+{
+ Db* db = getSelectedOpenDb();
+ if (!db || !db->isValid())
+ return;
+
+ if (item->getType() != DbTreeItem::Type::COLUMN)
+ return;
+
+ DbTreeItem* tableItem = item->findParentItem(DbTreeItem::Type::TABLE);
+ if (!tableItem)
+ return;
+
+ TableWindow* tableWin = openTable(tableItem);
+ tableWin->delColumn(item->text());
+}
+
+void DbTree::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+ UNUSED(previous);
+ updateActionStates(treeModel->itemFromIndex(current));
+}
+
+void DbTree::deleteSelected()
+{
+ QModelIndexList idxList = ui->treeView->getSelectedIndexes();
+ QList<DbTreeItem*> items;
+ foreach (const QModelIndex& idx, idxList)
+ items << dynamic_cast<DbTreeItem*>(treeModel->itemFromIndex(idx));
+
+ deleteItems(items);
+}
+
+void DbTree::deleteItems(const QList<DbTreeItem*>& itemsToDelete)
+{
+ QList<DbTreeItem*> items = itemsToDelete;
+
+ filterUndeletableItems(items);
+ filterItemsWithParentInList(items);
+
+ // Warning user about items to be deleted
+ static const QString itemTmp = "<img src=\"%1\"/> %2";
+
+ QStringList toDelete;
+ QStringList databasesToRemove;
+ QString itemStr;
+ int groupItems = 0;
+ foreach (DbTreeItem* item, items)
+ {
+ itemStr = itemTmp.arg(item->getIcon()->toUrl()).arg(item->text().left(ITEM_TEXT_LIMIT));
+
+ if (item->getType() == DbTreeItem::Type::DB)
+ databasesToRemove << itemStr;
+ else
+ toDelete << itemStr;
+
+ if (item->getType() == DbTreeItem::Type::DIR)
+ groupItems++;
+ }
+
+ QStringList actions;
+ if (toDelete.size() > 0)
+ actions << tr("Following objects will be deleted: %1.").arg(toDelete.join(", "));
+
+ if (databasesToRemove.size() > 0)
+ actions << tr("Following databases will be removed from list: %1.").arg(databasesToRemove.join(", "));
+
+ if (groupItems > 0)
+ actions << tr("Remainig objects from deleted group will be moved in place where the group used to be.");
+
+ QString msg = tr("%1<br><br>Are you sure you want to continue?").arg(actions.join("<br><br>"));
+
+ QMessageBox::StandardButton result = QMessageBox::question(this, tr("Delete objects"), msg);
+ if (result != QMessageBox::Yes)
+ return;
+
+ // Deleting items
+ QSet<Db*> databasesToRefresh;
+ for (DbTreeItem* item : items)
+ {
+ databasesToRefresh << item->getDb();
+ deleteItem(item);
+ }
+
+ for (Db* dbToRefresh : databasesToRefresh)
+ DBTREE->refreshSchema(dbToRefresh);
+}
+
+void DbTree::refreshSchemas()
+{
+ foreach (Db* db, DBLIST->getDbList())
+ treeModel->refreshSchema(db);
+}
+
+void DbTree::interrupt()
+{
+ treeModel->interrupt();
+}
+
+void DbTree::refreshSchema()
+{
+ Db* db = getSelectedDb();
+ refreshSchema(db);
+}
+
+void DbTree::updateActionsForCurrent()
+{
+ updateActionStates(ui->treeView->currentItem());
+}
+
+void DbTree::dbConnected(Db* db)
+{
+ updateActionsForCurrent();
+ updateDbIcon(db);
+}
+
+void DbTree::dbDisconnected(Db* db)
+{
+ updateActionsForCurrent();
+ updateDbIcon(db);
+}
+
+void DbTree::updateDbIcon(Db* db)
+{
+ DbTreeItem* item = treeModel->findItem(DbTreeItem::Type::DB, db);
+ if (item)
+ item->updateDbIcon();
+}
+
+void DbTree::refreshFont()
+{
+ ui->treeView->doItemsLayout();
+}
+
+void DbTree::setupDefShortcuts()
+{
+ setShortcutContext({
+ CLEAR_FILTER, DEL_SELECTED, REFRESH_SCHEMA, REFRESH_SCHEMAS,
+ ADD_DB, SELECT_ALL, COPY, PASTE
+ }, Qt::WidgetWithChildrenShortcut);
+
+ BIND_SHORTCUTS(DbTree, Action);
+}
+
+int qHash(DbTree::Action action)
+{
+ return static_cast<int>(action);
+}