diff options
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp')
| -rw-r--r-- | SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp b/SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp new file mode 100644 index 0000000..75579d5 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/selectabledbobjmodel.cpp @@ -0,0 +1,244 @@ +#include "selectabledbobjmodel.h" +#include "dbtree/dbtreeitem.h" +#include "dbtree/dbtreemodel.h" +#include <QDebug> +#include <QTreeView> + +SelectableDbObjModel::SelectableDbObjModel(QObject *parent) : + QSortFilterProxyModel(parent) +{ +} + +QVariant SelectableDbObjModel::data(const QModelIndex& index, int role) const +{ + if (role != Qt::CheckStateRole) + return QSortFilterProxyModel::data(index, role); + + return getStateFromChilds(index); +} + +bool SelectableDbObjModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if (role != Qt::CheckStateRole) + return QSortFilterProxyModel::setData(index, value, role); + + Qt::CheckState checked = static_cast<Qt::CheckState>(value.toInt()); + setRecurrently(index, checked); + emit dataChanged(index, index, {Qt::CheckStateRole}); + + return true; +} + +Qt::ItemFlags SelectableDbObjModel::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = QSortFilterProxyModel::flags(index); + DbTreeItem* item = getItemForProxyIndex(index); + switch (item->getType()) + { + case DbTreeItem::Type::TABLE: + case DbTreeItem::Type::VIRTUAL_TABLE: + case DbTreeItem::Type::INDEX: + case DbTreeItem::Type::TRIGGER: + case DbTreeItem::Type::VIEW: + case DbTreeItem::Type::DB: + case DbTreeItem::Type::TABLES: + case DbTreeItem::Type::INDEXES: + case DbTreeItem::Type::TRIGGERS: + case DbTreeItem::Type::VIEWS: + { + flags |= Qt::ItemIsUserCheckable; + if (index.child(0, 0).isValid()) + flags |= Qt::ItemIsTristate; + + break; + } + case DbTreeItem::Type::DIR: + case DbTreeItem::Type::COLUMNS: + case DbTreeItem::Type::COLUMN: + case DbTreeItem::Type::ITEM_PROTOTYPE: + break; + } + + return flags; +} + +QString SelectableDbObjModel::getDbName() const +{ + return dbName; +} + +void SelectableDbObjModel::setDbName(const QString& value) +{ + beginResetModel(); + dbName = value; + checkedObjects.clear(); + endResetModel(); +} +QStringList SelectableDbObjModel::getCheckedObjects() const +{ + return checkedObjects.toList(); +} + +void SelectableDbObjModel::setCheckedObjects(const QStringList& value) +{ + checkedObjects = value.toSet(); +} + +void SelectableDbObjModel::setRootChecked(bool checked) +{ + QModelIndex idx = index(0, 0); + if (!idx.isValid()) + return; + + setData(idx, checked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); +} + +DbTreeItem* SelectableDbObjModel::getItemForIndex(const QModelIndex& index) const +{ + return getItemForProxyIndex(index); +} + +bool SelectableDbObjModel::filterAcceptsRow(int srcRow, const QModelIndex& srcParent) const +{ + QModelIndex idx = sourceModel()->index(srcRow, 0, srcParent); + DbTreeItem* item = dynamic_cast<DbTreeItem*>(dynamic_cast<DbTreeModel*>(sourceModel())->itemFromIndex(idx)); + DbTreeItem* dbItem = item->getPathToParentItem(DbTreeItem::Type::DB).last(); + + // These 3 conditions could be written as one OR-ed, but this is easier to debug which one fails this way. + if (!dbItem) + return false; + + if (item->getType() == DbTreeItem::Type::DIR) + return checkRecurrentlyForDb(item); + + if (!dbItem->getDb()) + return false; + + if (dbItem->getDb()->getName() != dbName) + return false; + + switch (item->getType()) + { + case DbTreeItem::Type::TABLE: + case DbTreeItem::Type::VIRTUAL_TABLE: + case DbTreeItem::Type::INDEX: + case DbTreeItem::Type::TRIGGER: + case DbTreeItem::Type::VIEW: + case DbTreeItem::Type::DB: + return true; + case DbTreeItem::Type::TABLES: + case DbTreeItem::Type::INDEXES: + case DbTreeItem::Type::TRIGGERS: + case DbTreeItem::Type::VIEWS: + return item->rowCount() > 0; + case DbTreeItem::Type::DIR: + case DbTreeItem::Type::COLUMNS: + case DbTreeItem::Type::COLUMN: + case DbTreeItem::Type::ITEM_PROTOTYPE: + return false; + } + return false; +} + +DbTreeItem* SelectableDbObjModel::getItemForProxyIndex(const QModelIndex& index) const +{ + QModelIndex srcIdx = mapToSource(index); + DbTreeItem* item = dynamic_cast<DbTreeItem*>(dynamic_cast<DbTreeModel*>(sourceModel())->itemFromIndex(srcIdx)); + return item; +} + +Qt::CheckState SelectableDbObjModel::getStateFromChilds(const QModelIndex& index) const +{ + DbTreeItem* item = getItemForProxyIndex(index); + if (!item) + return Qt::Unchecked; + + if (!index.child(0, 0).isValid()) + { + if (isObject(item) && checkedObjects.contains(item->text())) + return Qt::Checked; + else + return Qt::Unchecked; + } + + int total = 0; + int checked = 0; + int partial = 0; + Qt::CheckState state; + QModelIndex child; + for (int i = 0; (child = index.child(i, 0)).isValid(); i++) + { + if (!child.flags().testFlag(Qt::ItemIsUserCheckable)) + continue; + + total++; + state = static_cast<Qt::CheckState>(child.data(Qt::CheckStateRole).toInt()); + if (state == Qt::Checked || state == Qt::PartiallyChecked) + { + checked++; + if (state == Qt::PartiallyChecked) + partial++; + } + } + + if (total == checked) + { + if (partial > 0) + return Qt::PartiallyChecked; + else + return Qt::Checked; + } + + if (checked == 0) + { + if (isObject(item) && checkedObjects.contains(item->text())) + return Qt::PartiallyChecked; + else + return Qt::Unchecked; + } + + return Qt::PartiallyChecked; +} + +void SelectableDbObjModel::setRecurrently(const QModelIndex& index, Qt::CheckState checked) +{ + DbTreeItem* item = getItemForProxyIndex(index); + if (!item) + return; + + if (checked && isObject(item)) + checkedObjects << item->text(); + else + checkedObjects.remove(item->text()); + + if (!index.child(0, 0).isValid()) + return; + + // Limiting checked to 'checked/unchecked', cause recurrent marking cannot set partially checked, it makes no sense + checked = (checked > 0 ? Qt::Checked : Qt::Unchecked); + + QModelIndex child; + for (int i = 0; (child = index.child(i, 0)).isValid(); i++) + setData(child, checked, Qt::CheckStateRole); +} + +bool SelectableDbObjModel::isObject(DbTreeItem* item) const +{ + switch (item->getType()) + { + case DbTreeItem::Type::TABLE: + case DbTreeItem::Type::INDEX: + case DbTreeItem::Type::TRIGGER: + case DbTreeItem::Type::VIEW: + case DbTreeItem::Type::VIRTUAL_TABLE: + return true; + default: + break; + } + return false; +} + +bool SelectableDbObjModel::checkRecurrentlyForDb(DbTreeItem* item) const +{ + return item->findItem(DbTreeItem::Type::DB, dbName) != nullptr; +} |
