CatalogueSideBarWidget.cpp
337 lines
| 12.5 KiB
| text/x-c
|
CppLexer
r1095 | #include "Catalogue/CatalogueSideBarWidget.h" | |||
#include "ui_CatalogueSideBarWidget.h" | ||||
r1129 | #include <SqpApplication.h> | |||
#include <Catalogue/CatalogueController.h> | ||||
r1228 | #include <Catalogue/CatalogueExplorerHelper.h> | |||
r1229 | #include <Catalogue/CatalogueTreeItems/CatalogueTextTreeItem.h> | |||
#include <Catalogue/CatalogueTreeItems/CatalogueTreeItem.h> | ||||
r1228 | #include <Catalogue/CatalogueTreeModel.h> | |||
r1129 | #include <CatalogueDao.h> | |||
#include <ComparaisonPredicate.h> | ||||
#include <DBCatalogue.h> | ||||
r1141 | #include <QMenu> | |||
r1147 | Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget") | |||
r1095 | ||||
r1229 | constexpr auto ALL_EVENT_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 1; | |||
constexpr auto TRASH_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 2; | ||||
constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3; | ||||
constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4; | ||||
r1098 | ||||
struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate { | ||||
r1129 | ||||
r1228 | CatalogueTreeModel *m_TreeModel = nullptr; | |||
void configureTreeWidget(QTreeView *treeView); | ||||
QModelIndex addDatabaseItem(const QString &name); | ||||
r1229 | CatalogueAbstractTreeItem *getDatabaseItem(const QString &name); | |||
r1143 | void addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue, | |||
r1228 | const QModelIndex &databaseIndex); | |||
r1147 | ||||
r1229 | CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const; | |||
r1228 | void setHasChanges(bool value, const QModelIndex &index, QTreeView *treeView); | |||
bool hasChanges(const QModelIndex &index, QTreeView *treeView); | ||||
r1230 | ||||
int selectionType(QTreeView *treeView) const | ||||
{ | ||||
auto selectedItems = treeView->selectionModel()->selectedRows(); | ||||
if (selectedItems.isEmpty()) { | ||||
return CatalogueAbstractTreeItem::DEFAULT_TYPE; | ||||
} | ||||
else { | ||||
auto firstIndex = selectedItems.first(); | ||||
auto firstItem = m_TreeModel->item(firstIndex); | ||||
if (!firstItem) { | ||||
Q_ASSERT(false); | ||||
return CatalogueAbstractTreeItem::DEFAULT_TYPE; | ||||
} | ||||
auto selectionType = firstItem->type(); | ||||
for (auto itemIndex : selectedItems) { | ||||
auto item = m_TreeModel->item(itemIndex); | ||||
if (!item || item->type() != selectionType) { | ||||
// Incoherent multi selection | ||||
selectionType = CatalogueAbstractTreeItem::DEFAULT_TYPE; | ||||
break; | ||||
} | ||||
} | ||||
return selectionType; | ||||
} | ||||
} | ||||
QVector<std::shared_ptr<DBCatalogue> > selectedCatalogues(QTreeView *treeView) const | ||||
{ | ||||
QVector<std::shared_ptr<DBCatalogue> > catalogues; | ||||
auto selectedItems = treeView->selectionModel()->selectedRows(); | ||||
for (auto itemIndex : selectedItems) { | ||||
auto item = m_TreeModel->item(itemIndex); | ||||
if (item && item->type() == CATALOGUE_ITEM_TYPE) { | ||||
catalogues.append(static_cast<CatalogueTreeItem *>(item)->catalogue()); | ||||
} | ||||
} | ||||
return catalogues; | ||||
} | ||||
QStringList selectedRepositories(QTreeView *treeView) const | ||||
{ | ||||
QStringList repositories; | ||||
auto selectedItems = treeView->selectionModel()->selectedRows(); | ||||
for (auto itemIndex : selectedItems) { | ||||
auto item = m_TreeModel->item(itemIndex); | ||||
if (item && item->type() == DATABASE_ITEM_TYPE) { | ||||
repositories.append(item->text()); | ||||
} | ||||
} | ||||
return repositories; | ||||
} | ||||
r1098 | }; | |||
r1095 | CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent) | |||
r1098 | : QWidget(parent), | |||
ui(new Ui::CatalogueSideBarWidget), | ||||
impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()} | ||||
r1095 | { | |||
ui->setupUi(this); | ||||
r1103 | ||||
r1228 | impl->m_TreeModel = new CatalogueTreeModel(this); | |||
ui->treeView->setModel(impl->m_TreeModel); | ||||
impl->configureTreeWidget(ui->treeView); | ||||
ui->treeView->header()->setStretchLastSection(false); | ||||
ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); | ||||
ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch); | ||||
r1142 | ||||
r1132 | auto emitSelection = [this]() { | |||
r1230 | auto selectionType = impl->selectionType(ui->treeView); | |||
switch (selectionType) { | ||||
case CATALOGUE_ITEM_TYPE: | ||||
emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView)); | ||||
break; | ||||
case DATABASE_ITEM_TYPE: | ||||
emit this->databaseSelected(impl->selectedRepositories(ui->treeView)); | ||||
break; | ||||
case ALL_EVENT_ITEM_TYPE: | ||||
emit this->allEventsSelected(); | ||||
break; | ||||
case TRASH_ITEM_TYPE: | ||||
emit this->trashSelected(); | ||||
break; | ||||
default: | ||||
emit this->selectionCleared(); | ||||
break; | ||||
r1132 | } | |||
r1105 | }; | |||
r1228 | connect(ui->treeView, &QTreeView::clicked, emitSelection); | |||
connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, emitSelection); | ||||
connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [emitSelection, this](auto index) { | ||||
auto selectedIndexes = ui->treeView->selectionModel()->selectedRows(); | ||||
if (selectedIndexes.contains(index)) { | ||||
emitSelection(); | ||||
} | ||||
auto item = impl->m_TreeModel->item(index); | ||||
impl->setHasChanges(true, index, ui->treeView); | ||||
}); | ||||
r1141 | ||||
r1228 | ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu); | |||
r1229 | connect(ui->treeView, &QTreeView::customContextMenuRequested, this, | |||
r1141 | &CatalogueSideBarWidget::onContextMenuRequested); | |||
r1095 | } | |||
CatalogueSideBarWidget::~CatalogueSideBarWidget() | ||||
{ | ||||
delete ui; | ||||
} | ||||
r1098 | ||||
r1231 | void CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue, | |||
const QString &repository) | ||||
{ | ||||
auto repositoryItem = impl->getDatabaseItem(repository); | ||||
impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem)); | ||||
} | ||||
r1147 | void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue, | |||
bool hasChanges) | ||||
{ | ||||
r1228 | if (auto catalogueItem = impl->getCatalogueItem(catalogue)) { | |||
auto index = impl->m_TreeModel->indexOf(catalogueItem); | ||||
impl->setHasChanges(hasChanges, index, ui->treeView); | ||||
r1229 | // catalogueItem->refresh(); | |||
r1147 | } | |||
} | ||||
r1231 | QVector<std::shared_ptr<DBCatalogue> > | |||
CatalogueSideBarWidget::getCatalogues(const QString &repository) const | ||||
{ | ||||
QVector<std::shared_ptr<DBCatalogue> > result; | ||||
auto repositoryItem = impl->getDatabaseItem(repository); | ||||
for (auto child : repositoryItem->children()) { | ||||
if (child->type() == CATALOGUE_ITEM_TYPE) { | ||||
auto catalogueItem = static_cast<CatalogueTreeItem *>(child); | ||||
result << catalogueItem->catalogue(); | ||||
} | ||||
else { | ||||
qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogues: invalid structure"; | ||||
} | ||||
} | ||||
return result; | ||||
} | ||||
r1141 | void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos) | |||
{ | ||||
QMenu menu{this}; | ||||
r1228 | auto currentIndex = ui->treeView->currentIndex(); | |||
auto currentItem = impl->m_TreeModel->item(currentIndex); | ||||
if (!currentItem) { | ||||
return; | ||||
} | ||||
r1141 | switch (currentItem->type()) { | |||
case CATALOGUE_ITEM_TYPE: | ||||
r1228 | menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); }); | |||
r1141 | break; | |||
case DATABASE_ITEM_TYPE: | ||||
break; | ||||
case ALL_EVENT_ITEM_TYPE: | ||||
break; | ||||
case TRASH_ITEM_TYPE: | ||||
menu.addAction("Empty Trash", []() { | ||||
// TODO | ||||
}); | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
if (!menu.isEmpty()) { | ||||
r1228 | menu.exec(ui->treeView->mapToGlobal(pos)); | |||
r1141 | } | |||
} | ||||
r1228 | void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView) | |||
r1098 | { | |||
r1229 | auto allEventsItem = new CatalogueTextTreeItem{QIcon{":/icones/allEvents.png"}, "All Events", | |||
ALL_EVENT_ITEM_TYPE}; | ||||
r1235 | auto allEventIndex = m_TreeModel->addTopLevelItem(allEventsItem); | |||
treeView->setCurrentIndex(allEventIndex); | ||||
r1098 | ||||
r1229 | auto trashItem | |||
= new CatalogueTextTreeItem{QIcon{":/icones/trash.png"}, "Trash", TRASH_ITEM_TYPE}; | ||||
r1228 | m_TreeModel->addTopLevelItem(trashItem); | |||
r1098 | ||||
r1228 | auto separator = new QFrame{treeView}; | |||
r1098 | separator->setFrameShape(QFrame::HLine); | |||
r1229 | auto separatorItem | |||
= new CatalogueTextTreeItem{QIcon{}, QString{}, CatalogueAbstractTreeItem::DEFAULT_TYPE}; | ||||
separatorItem->setEnabled(false); | ||||
r1228 | auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem); | |||
treeView->setIndexWidget(separatorIndex, separator); | ||||
r1102 | ||||
r1164 | auto repositories = sqpApp->catalogueController().getRepositories(); | |||
for (auto dbname : repositories) { | ||||
r1228 | auto dbIndex = addDatabaseItem(dbname); | |||
r1164 | auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname); | |||
for (auto catalogue : catalogues) { | ||||
r1228 | addCatalogueItem(catalogue, dbIndex); | |||
r1164 | } | |||
r1129 | } | |||
r1102 | ||||
r1228 | treeView->expandAll(); | |||
r1102 | } | |||
r1228 | QModelIndex | |||
CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name) | ||||
r1102 | { | |||
r1229 | auto databaseItem | |||
= new CatalogueTextTreeItem{QIcon{":/icones/database.png"}, {name}, DATABASE_ITEM_TYPE}; | ||||
r1228 | auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem); | |||
r1102 | ||||
r1228 | return databaseIndex; | |||
r1102 | } | |||
r1229 | CatalogueAbstractTreeItem * | |||
r1228 | CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name) | |||
r1134 | { | |||
r1229 | for (auto item : m_TreeModel->topLevelItems()) { | |||
if (item->type() == DATABASE_ITEM_TYPE && item->text() == name) { | ||||
r1134 | return item; | |||
} | ||||
} | ||||
return nullptr; | ||||
} | ||||
r1102 | void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem( | |||
r1228 | const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex) | |||
r1102 | { | |||
r1229 | auto catalogueItem | |||
= new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE}; | ||||
r1228 | m_TreeModel->addChildItem(catalogueItem, databaseIndex); | |||
r1098 | } | |||
r1147 | ||||
r1229 | CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem( | |||
r1228 | const std::shared_ptr<DBCatalogue> &catalogue) const | |||
r1147 | { | |||
r1229 | for (auto item : m_TreeModel->topLevelItems()) { | |||
r1147 | if (item->type() == DATABASE_ITEM_TYPE) { | |||
r1229 | for (auto childItem : item->children()) { | |||
r1147 | if (childItem->type() == CATALOGUE_ITEM_TYPE) { | |||
r1229 | auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem); | |||
r1147 | if (catalogueItem->catalogue() == catalogue) { | |||
return catalogueItem; | ||||
} | ||||
} | ||||
else { | ||||
qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogueItem: Invalid tree " | ||||
"structure. A database item should " | ||||
"only contain catalogues."; | ||||
Q_ASSERT(false); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
return nullptr; | ||||
} | ||||
r1228 | ||||
void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(bool value, | ||||
const QModelIndex &index, | ||||
QTreeView *treeView) | ||||
{ | ||||
auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation); | ||||
if (value) { | ||||
if (!hasChanges(validationIndex, treeView)) { | ||||
auto widget = CatalogueExplorerHelper::buildValidationWidget( | ||||
r1243 | treeView, [this, validationIndex, | |||
treeView]() { setHasChanges(false, validationIndex, treeView); }, | ||||
r1228 | [this, validationIndex, treeView]() { | |||
setHasChanges(false, validationIndex, treeView); | ||||
}); | ||||
treeView->setIndexWidget(validationIndex, widget); | ||||
} | ||||
} | ||||
else { | ||||
// Note: the widget is destroyed | ||||
treeView->setIndexWidget(validationIndex, nullptr); | ||||
} | ||||
} | ||||
bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QModelIndex &index, | ||||
QTreeView *treeView) | ||||
{ | ||||
auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation); | ||||
return treeView->indexWidget(validationIndex) != nullptr; | ||||
} | ||||