CatalogueSideBarWidget.cpp
313 lines
| 11.6 KiB
| text/x-c
|
CppLexer
r1130 | #include "Catalogue/CatalogueSideBarWidget.h" | |||
#include "ui_CatalogueSideBarWidget.h" | ||||
r1162 | #include <SqpApplication.h> | |||
#include <Catalogue/CatalogueController.h> | ||||
r1283 | #include <Catalogue/CatalogueExplorerHelper.h> | |||
r1284 | #include <Catalogue/CatalogueTreeItems/CatalogueTextTreeItem.h> | |||
#include <Catalogue/CatalogueTreeItems/CatalogueTreeItem.h> | ||||
r1283 | #include <Catalogue/CatalogueTreeModel.h> | |||
r1162 | #include <CatalogueDao.h> | |||
#include <ComparaisonPredicate.h> | ||||
#include <DBCatalogue.h> | ||||
r1174 | #include <QMenu> | |||
r1180 | Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget") | |||
r1130 | ||||
r1284 | 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; | ||||
r1133 | ||||
struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate { | ||||
r1162 | ||||
r1283 | CatalogueTreeModel *m_TreeModel = nullptr; | |||
void configureTreeWidget(QTreeView *treeView); | ||||
QModelIndex addDatabaseItem(const QString &name); | ||||
r1284 | CatalogueAbstractTreeItem *getDatabaseItem(const QString &name); | |||
r1176 | void addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue, | |||
r1283 | const QModelIndex &databaseIndex); | |||
r1180 | ||||
r1284 | CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const; | |||
r1283 | void setHasChanges(bool value, const QModelIndex &index, QTreeView *treeView); | |||
bool hasChanges(const QModelIndex &index, QTreeView *treeView); | ||||
r1285 | ||||
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; | ||||
} | ||||
r1133 | }; | |||
r1130 | CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent) | |||
r1133 | : QWidget(parent), | |||
ui(new Ui::CatalogueSideBarWidget), | ||||
impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()} | ||||
r1130 | { | |||
ui->setupUi(this); | ||||
r1138 | ||||
r1283 | 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); | ||||
r1175 | ||||
r1165 | auto emitSelection = [this]() { | |||
r1285 | 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; | ||||
r1165 | } | |||
r1140 | }; | |||
r1283 | 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); | ||||
}); | ||||
r1174 | ||||
r1283 | ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu); | |||
r1284 | connect(ui->treeView, &QTreeView::customContextMenuRequested, this, | |||
r1174 | &CatalogueSideBarWidget::onContextMenuRequested); | |||
r1130 | } | |||
CatalogueSideBarWidget::~CatalogueSideBarWidget() | ||||
{ | ||||
delete ui; | ||||
} | ||||
r1133 | ||||
r1180 | void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue, | |||
bool hasChanges) | ||||
{ | ||||
r1283 | if (auto catalogueItem = impl->getCatalogueItem(catalogue)) { | |||
auto index = impl->m_TreeModel->indexOf(catalogueItem); | ||||
impl->setHasChanges(hasChanges, index, ui->treeView); | ||||
r1284 | // catalogueItem->refresh(); | |||
r1180 | } | |||
} | ||||
r1174 | void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos) | |||
{ | ||||
QMenu menu{this}; | ||||
r1283 | auto currentIndex = ui->treeView->currentIndex(); | |||
auto currentItem = impl->m_TreeModel->item(currentIndex); | ||||
if (!currentItem) { | ||||
return; | ||||
} | ||||
r1174 | switch (currentItem->type()) { | |||
case CATALOGUE_ITEM_TYPE: | ||||
r1283 | menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); }); | |||
r1174 | 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()) { | ||||
r1283 | menu.exec(ui->treeView->mapToGlobal(pos)); | |||
r1174 | } | |||
} | ||||
r1283 | void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView) | |||
r1133 | { | |||
r1284 | auto allEventsItem = new CatalogueTextTreeItem{QIcon{":/icones/allEvents.png"}, "All Events", | |||
ALL_EVENT_ITEM_TYPE}; | ||||
r1283 | m_TreeModel->addTopLevelItem(allEventsItem); | |||
r1133 | ||||
r1284 | auto trashItem | |||
= new CatalogueTextTreeItem{QIcon{":/icones/trash.png"}, "Trash", TRASH_ITEM_TYPE}; | ||||
r1283 | m_TreeModel->addTopLevelItem(trashItem); | |||
r1133 | ||||
r1283 | auto separator = new QFrame{treeView}; | |||
r1133 | separator->setFrameShape(QFrame::HLine); | |||
r1284 | auto separatorItem | |||
= new CatalogueTextTreeItem{QIcon{}, QString{}, CatalogueAbstractTreeItem::DEFAULT_TYPE}; | ||||
separatorItem->setEnabled(false); | ||||
r1283 | auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem); | |||
treeView->setIndexWidget(separatorIndex, separator); | ||||
r1137 | ||||
r1196 | auto repositories = sqpApp->catalogueController().getRepositories(); | |||
for (auto dbname : repositories) { | ||||
r1283 | auto dbIndex = addDatabaseItem(dbname); | |||
r1196 | auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname); | |||
for (auto catalogue : catalogues) { | ||||
r1283 | addCatalogueItem(catalogue, dbIndex); | |||
r1196 | } | |||
r1162 | } | |||
r1137 | ||||
r1283 | treeView->expandAll(); | |||
r1137 | } | |||
r1283 | QModelIndex | |||
CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name) | ||||
r1137 | { | |||
r1284 | auto databaseItem | |||
= new CatalogueTextTreeItem{QIcon{":/icones/database.png"}, {name}, DATABASE_ITEM_TYPE}; | ||||
r1283 | auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem); | |||
r1137 | ||||
r1283 | return databaseIndex; | |||
r1137 | } | |||
r1284 | CatalogueAbstractTreeItem * | |||
r1283 | CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name) | |||
r1167 | { | |||
r1284 | for (auto item : m_TreeModel->topLevelItems()) { | |||
if (item->type() == DATABASE_ITEM_TYPE && item->text() == name) { | ||||
r1167 | return item; | |||
} | ||||
} | ||||
return nullptr; | ||||
} | ||||
r1137 | void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem( | |||
r1283 | const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex) | |||
r1137 | { | |||
r1284 | auto catalogueItem | |||
= new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE}; | ||||
r1283 | m_TreeModel->addChildItem(catalogueItem, databaseIndex); | |||
r1133 | } | |||
r1180 | ||||
r1284 | CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem( | |||
r1283 | const std::shared_ptr<DBCatalogue> &catalogue) const | |||
r1180 | { | |||
r1284 | for (auto item : m_TreeModel->topLevelItems()) { | |||
r1180 | if (item->type() == DATABASE_ITEM_TYPE) { | |||
r1284 | for (auto childItem : item->children()) { | |||
r1180 | if (childItem->type() == CATALOGUE_ITEM_TYPE) { | |||
r1284 | auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem); | |||
r1180 | 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; | ||||
} | ||||
r1283 | ||||
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( | ||||
treeView, | ||||
[this, validationIndex, treeView]() { | ||||
setHasChanges(false, validationIndex, treeView); | ||||
}, | ||||
[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; | ||||
} | ||||