##// END OF EJS Templates
Refactoring of catalogue display using a QTreeView and a custom model based on QTreeWidgetItem
trabillard -
r1283:74c199fc287e
parent child
Show More
@@ -0,0 +1,47
1 #ifndef SCIQLOP_CATALOGUETREEMODEL_H
2 #define SCIQLOP_CATALOGUETREEMODEL_H
3
4 #include <Common/spimpl.h>
5 #include <QAbstractItemModel>
6 #include <QTreeWidgetItem>
7
8 /**
9 * @brief Model to display catalogue items based on QTreeWidgetItem
10 * @warning Do not use the method QTreeWidgetItem::treeWidget for an item added to this model or the application will crash
11 */
12 class CatalogueTreeModel : public QAbstractItemModel {
13 Q_OBJECT
14
15 signals:
16 void itemRenamed(const QModelIndex &index);
17
18 public:
19 CatalogueTreeModel(QObject *parent = nullptr);
20
21 enum class Column { Name, Validation, Count };
22
23 QModelIndex addTopLevelItem(QTreeWidgetItem *item);
24 int topLevelItemCount() const;
25 QTreeWidgetItem *topLevelItem(int i) const;
26
27 void addChildItem(QTreeWidgetItem *child, const QModelIndex &parentIndex);
28
29 QTreeWidgetItem *item(const QModelIndex &index) const;
30 QModelIndex indexOf(QTreeWidgetItem *item, int column = 0) const;
31
32 // model
33 QModelIndex index(int row, int column,
34 const QModelIndex &parent = QModelIndex()) const override;
35 QModelIndex parent(const QModelIndex &index) const override;
36 int rowCount(const QModelIndex &parent) const override;
37 int columnCount(const QModelIndex &parent) const override;
38 Qt::ItemFlags flags(const QModelIndex &index) const override;
39 QVariant data(const QModelIndex &index, int role) const override;
40 bool setData(const QModelIndex &index, const QVariant &value, int role) override;
41
42 private:
43 class CatalogueTreeModelPrivate;
44 spimpl::unique_impl_ptr<CatalogueTreeModelPrivate> impl;
45 };
46
47 #endif // CATALOGUETREEMODEL_H
@@ -0,0 +1,169
1 #include "Catalogue/CatalogueTreeModel.h"
2
3 #include <QTreeWidgetItem>
4 #include <memory>
5
6 struct CatalogueTreeModel::CatalogueTreeModelPrivate {
7 std::unique_ptr<QTreeWidgetItem> m_RootItem = nullptr;
8
9 CatalogueTreeModelPrivate() : m_RootItem{std::make_unique<QTreeWidgetItem>()} {}
10 };
11
12 CatalogueTreeModel::CatalogueTreeModel(QObject *parent)
13 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueTreeModelPrivate>()}
14 {
15 }
16
17 QModelIndex CatalogueTreeModel::addTopLevelItem(QTreeWidgetItem *item)
18 {
19 beginInsertRows(QModelIndex(), impl->m_RootItem->childCount(), impl->m_RootItem->childCount());
20 impl->m_RootItem->addChild(item);
21 endInsertRows();
22
23 return index(impl->m_RootItem->childCount() - 1, 0);
24 }
25
26 int CatalogueTreeModel::topLevelItemCount() const
27 {
28 return impl->m_RootItem->childCount();
29 }
30
31 QTreeWidgetItem *CatalogueTreeModel::topLevelItem(int i) const
32 {
33 return impl->m_RootItem->child(i);
34 }
35
36 void CatalogueTreeModel::addChildItem(QTreeWidgetItem *child, const QModelIndex &parentIndex)
37 {
38 auto parentItem = item(parentIndex);
39 beginInsertRows(parentIndex, parentItem->childCount(), parentItem->childCount());
40 parentItem->addChild(child);
41 endInsertRows();
42 }
43
44 QTreeWidgetItem *CatalogueTreeModel::item(const QModelIndex &index) const
45 {
46 return static_cast<QTreeWidgetItem *>(index.internalPointer());
47 }
48
49 QModelIndex CatalogueTreeModel::indexOf(QTreeWidgetItem *item, int column) const
50 {
51 auto parentItem = item->parent();
52 if (!parentItem) {
53 return QModelIndex();
54 }
55
56 auto row = parentItem->indexOfChild(item);
57 return createIndex(row, column, item);
58 }
59
60 QModelIndex CatalogueTreeModel::index(int row, int column, const QModelIndex &parent) const
61 {
62 if (!hasIndex(row, column, parent)) {
63 return QModelIndex();
64 }
65
66 QTreeWidgetItem *parentItem = nullptr;
67
68 if (!parent.isValid()) {
69 parentItem = impl->m_RootItem.get();
70 }
71 else {
72 parentItem = static_cast<QTreeWidgetItem *>(parent.internalPointer());
73 }
74
75 QTreeWidgetItem *childItem = parentItem->child(row);
76 if (childItem) {
77 return createIndex(row, column, childItem);
78 }
79
80 return QModelIndex();
81 }
82
83
84 QModelIndex CatalogueTreeModel::parent(const QModelIndex &index) const
85 {
86 if (!index.isValid()) {
87 return QModelIndex();
88 }
89
90 auto childItem = static_cast<QTreeWidgetItem *>(index.internalPointer());
91 auto parentItem = childItem->parent();
92
93 if (parentItem == nullptr || parentItem->parent() == nullptr) {
94 return QModelIndex();
95 }
96
97 auto row = parentItem->parent()->indexOfChild(parentItem);
98 return createIndex(row, 0, parentItem);
99 }
100
101 int CatalogueTreeModel::rowCount(const QModelIndex &parent) const
102 {
103 QTreeWidgetItem *parentItem = nullptr;
104 if (parent.column() > 0) {
105 return 0;
106 }
107
108 if (!parent.isValid()) {
109 parentItem = impl->m_RootItem.get();
110 }
111 else {
112 parentItem = static_cast<QTreeWidgetItem *>(parent.internalPointer());
113 }
114
115 return parentItem->childCount();
116 }
117
118 int CatalogueTreeModel::columnCount(const QModelIndex &parent) const
119 {
120 return (int)Column::Count;
121 }
122
123 Qt::ItemFlags CatalogueTreeModel::flags(const QModelIndex &index) const
124 {
125 if (index.column() == (int)Column::Validation) {
126 return Qt::NoItemFlags;
127 }
128
129 auto item = static_cast<QTreeWidgetItem *>(index.internalPointer());
130 if (item) {
131 return item->flags();
132 }
133
134 return Qt::NoItemFlags;
135 }
136
137 QVariant CatalogueTreeModel::data(const QModelIndex &index, int role) const
138 {
139 if (!index.isValid()) {
140 return QModelIndex();
141 }
142
143 auto item = static_cast<QTreeWidgetItem *>(index.internalPointer());
144 if (item) {
145 return item->data(index.column(), role);
146 }
147
148 return QModelIndex();
149 }
150
151 bool CatalogueTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
152 {
153 if (!index.isValid()) {
154 return false;
155 }
156
157 auto item = static_cast<QTreeWidgetItem *>(index.internalPointer());
158 if (item) {
159 item->setData(index.column(), role, value);
160
161 if (index.column() == (int)Column::Name) {
162 emit itemRenamed(index);
163 }
164
165 return true;
166 }
167
168 return false;
169 }
@@ -1,36 +1,34
1 1 #ifndef SCIQLOP_CATALOGUETREEWIDGETITEM_H
2 2 #define SCIQLOP_CATALOGUETREEWIDGETITEM_H
3 3
4 4 #include <Common/spimpl.h>
5 5 #include <QTreeWidgetItem>
6 6
7 7 class DBCatalogue;
8 8
9 9
10 10 class CatalogueTreeWidgetItem : public QTreeWidgetItem {
11 11 public:
12 12 CatalogueTreeWidgetItem(std::shared_ptr<DBCatalogue> catalogue,
13 13 int type = QTreeWidgetItem::Type);
14 14
15 15 QVariant data(int column, int role) const override;
16 16 void setData(int column, int role, const QVariant &value) override;
17 17
18 18 /// Returns the catalogue represented by the item
19 19 std::shared_ptr<DBCatalogue> catalogue() const;
20 20
21 /// Displays or hides the save and cancel buttons indicating that the catalogue has unsaved
22 /// changes
23 21 void setHasChanges(bool value);
24 22
25 23 /// Returns true if the widget indicating the event has unsaved changes is displayed
26 24 bool hasChanges();
27 25
28 26 /// Refreshes the data displayed by the item from the catalogue
29 27 void refresh();
30 28
31 29 private:
32 30 class CatalogueTreeWidgetItemPrivate;
33 31 spimpl::unique_impl_ptr<CatalogueTreeWidgetItemPrivate> impl;
34 32 };
35 33
36 34 #endif // SCIQLOP_CATALOGUETREEWIDGETITEM_H
@@ -1,143 +1,145
1 1 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
2 2 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
3 3
4 4 gui_moc_headers = [
5 5 'include/DataSource/DataSourceWidget.h',
6 6 'include/Settings/SqpSettingsDialog.h',
7 7 'include/Settings/SqpSettingsGeneralWidget.h',
8 8 'include/SidePane/SqpSidePane.h',
9 9 'include/SqpApplication.h',
10 10 'include/DragAndDrop/DragDropScroller.h',
11 11 'include/DragAndDrop/DragDropTabSwitcher.h',
12 12 'include/TimeWidget/TimeWidget.h',
13 13 'include/Variable/VariableInspectorWidget.h',
14 14 'include/Variable/RenameVariableDialog.h',
15 15 'include/Visualization/qcustomplot.h',
16 16 'include/Visualization/VisualizationGraphWidget.h',
17 17 'include/Visualization/VisualizationTabWidget.h',
18 18 'include/Visualization/VisualizationWidget.h',
19 19 'include/Visualization/VisualizationZoneWidget.h',
20 20 'include/Visualization/VisualizationDragDropContainer.h',
21 21 'include/Visualization/VisualizationDragWidget.h',
22 22 'include/Visualization/ColorScaleEditor.h',
23 23 'include/Actions/SelectionZoneAction.h',
24 24 'include/Visualization/VisualizationMultiZoneSelectionDialog.h',
25 25 'include/Catalogue/CatalogueExplorer.h',
26 26 'include/Catalogue/CatalogueEventsWidget.h',
27 27 'include/Catalogue/CatalogueSideBarWidget.h',
28 28 'include/Catalogue/CatalogueInspectorWidget.h',
29 29 'include/Catalogue/CatalogueEventsModel.h',
30 'include/Catalogue/CreateEventDialog.h'
30 'include/Catalogue/CreateEventDialog.h',
31 'include/Catalogue/CatalogueTreeModel.h'
31 32 ]
32 33
33 34 gui_ui_files = [
34 35 'ui/DataSource/DataSourceWidget.ui',
35 36 'ui/Settings/SqpSettingsDialog.ui',
36 37 'ui/Settings/SqpSettingsGeneralWidget.ui',
37 38 'ui/SidePane/SqpSidePane.ui',
38 39 'ui/TimeWidget/TimeWidget.ui',
39 40 'ui/Variable/VariableInspectorWidget.ui',
40 41 'ui/Variable/RenameVariableDialog.ui',
41 42 'ui/Variable/VariableMenuHeaderWidget.ui',
42 43 'ui/Visualization/VisualizationGraphWidget.ui',
43 44 'ui/Visualization/VisualizationTabWidget.ui',
44 45 'ui/Visualization/VisualizationWidget.ui',
45 46 'ui/Visualization/VisualizationZoneWidget.ui',
46 47 'ui/Visualization/ColorScaleEditor.ui',
47 48 'ui/Visualization/VisualizationMultiZoneSelectionDialog.ui',
48 49 'ui/Catalogue/CatalogueExplorer.ui',
49 50 'ui/Catalogue/CatalogueEventsWidget.ui',
50 51 'ui/Catalogue/CatalogueSideBarWidget.ui',
51 52 'ui/Catalogue/CatalogueInspectorWidget.ui',
52 53 'ui/Catalogue/CreateEventDialog.ui'
53 54 ]
54 55
55 56 gui_qresources = ['resources/sqpguiresources.qrc']
56 57
57 58 rcc_gen = generator(rcc,
58 59 output : 'qrc_@BASENAME@.cpp',
59 60 arguments : [
60 61 '--output',
61 62 '@OUTPUT@',
62 63 '@INPUT@',
63 64 '@EXTRA_ARGS@'])
64 65
65 66 rcc_files = rcc_gen.process(gui_qresources, extra_args : ['-name', 'sqpguiresources'])
66 67
67 68 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
68 69 ui_files : gui_ui_files)
69 70
70 71 gui_sources = [
71 72 'src/SqpApplication.cpp',
72 73 'src/DragAndDrop/DragDropGuiController.cpp',
73 74 'src/DragAndDrop/DragDropScroller.cpp',
74 75 'src/DragAndDrop/DragDropTabSwitcher.cpp',
75 76 'src/Common/ColorUtils.cpp',
76 77 'src/Common/VisualizationDef.cpp',
77 78 'src/DataSource/DataSourceTreeWidgetItem.cpp',
78 79 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
79 80 'src/DataSource/DataSourceWidget.cpp',
80 81 'src/DataSource/DataSourceTreeWidget.cpp',
81 82 'src/Settings/SqpSettingsDialog.cpp',
82 83 'src/Settings/SqpSettingsGeneralWidget.cpp',
83 84 'src/SidePane/SqpSidePane.cpp',
84 85 'src/TimeWidget/TimeWidget.cpp',
85 86 'src/Variable/VariableInspectorWidget.cpp',
86 87 'src/Variable/VariableInspectorTableView.cpp',
87 88 'src/Variable/VariableMenuHeaderWidget.cpp',
88 89 'src/Variable/RenameVariableDialog.cpp',
89 90 'src/Visualization/VisualizationGraphHelper.cpp',
90 91 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
91 92 'src/Visualization/VisualizationGraphWidget.cpp',
92 93 'src/Visualization/VisualizationTabWidget.cpp',
93 94 'src/Visualization/VisualizationWidget.cpp',
94 95 'src/Visualization/VisualizationZoneWidget.cpp',
95 96 'src/Visualization/qcustomplot.cpp',
96 97 'src/Visualization/QCustomPlotSynchronizer.cpp',
97 98 'src/Visualization/operations/FindVariableOperation.cpp',
98 99 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
99 100 'src/Visualization/operations/MenuBuilder.cpp',
100 101 'src/Visualization/operations/RemoveVariableOperation.cpp',
101 102 'src/Visualization/operations/RescaleAxeOperation.cpp',
102 103 'src/Visualization/VisualizationDragDropContainer.cpp',
103 104 'src/Visualization/VisualizationDragWidget.cpp',
104 105 'src/Visualization/AxisRenderingUtils.cpp',
105 106 'src/Visualization/PlottablesRenderingUtils.cpp',
106 107 'src/Visualization/MacScrollBarStyle.cpp',
107 108 'src/Visualization/VisualizationCursorItem.cpp',
108 109 'src/Visualization/ColorScaleEditor.cpp',
109 110 'src/Visualization/SqpColorScale.cpp',
110 111 'src/Visualization/QCPColorMapIterator.cpp',
111 112 'src/Visualization/VisualizationSelectionZoneItem.cpp',
112 113 'src/Visualization/VisualizationSelectionZoneManager.cpp',
113 114 'src/Actions/SelectionZoneAction.cpp',
114 115 'src/Actions/ActionsGuiController.cpp',
115 116 'src/Visualization/VisualizationActionManager.cpp',
116 117 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
117 118 'src/Catalogue/CatalogueExplorer.cpp',
118 119 'src/Catalogue/CatalogueEventsWidget.cpp',
119 120 'src/Catalogue/CatalogueSideBarWidget.cpp',
120 121 'src/Catalogue/CatalogueInspectorWidget.cpp',
121 122 'src/Catalogue/CatalogueTreeWidgetItem.cpp',
122 123 'src/Catalogue/CatalogueEventsModel.cpp',
123 124 'src/Catalogue/CatalogueExplorerHelper.cpp',
124 125 'src/Catalogue/CatalogueActionManager.cpp',
125 'src/Catalogue/CreateEventDialog.cpp'
126 'src/Catalogue/CreateEventDialog.cpp',
127 'src/Catalogue/CatalogueTreeModel.cpp'
126 128 ]
127 129
128 130 gui_inc = include_directories(['include'])
129 131
130 132 sciqlop_gui_lib = library('sciqlopgui',
131 133 gui_sources,
132 134 gui_moc_files,
133 135 rcc_files,
134 136 include_directories : [gui_inc],
135 137 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep],
136 138 install : true
137 139 )
138 140
139 141 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
140 142 include_directories : gui_inc,
141 143 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep])
142 144
143 145
@@ -1,250 +1,298
1 1 #include "Catalogue/CatalogueSideBarWidget.h"
2 2 #include "ui_CatalogueSideBarWidget.h"
3 3 #include <SqpApplication.h>
4 4
5 5 #include <Catalogue/CatalogueController.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
7 #include <Catalogue/CatalogueTreeModel.h>
6 8 #include <Catalogue/CatalogueTreeWidgetItem.h>
7 9 #include <CatalogueDao.h>
8 10 #include <ComparaisonPredicate.h>
9 11 #include <DBCatalogue.h>
10 12
11 13 #include <QMenu>
12 14
13 15 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
14 16
15 17
16 18 constexpr auto ALL_EVENT_ITEM_TYPE = QTreeWidgetItem::UserType;
17 19 constexpr auto TRASH_ITEM_TYPE = QTreeWidgetItem::UserType + 1;
18 20 constexpr auto CATALOGUE_ITEM_TYPE = QTreeWidgetItem::UserType + 2;
19 21 constexpr auto DATABASE_ITEM_TYPE = QTreeWidgetItem::UserType + 3;
20 22
21 23
22 24 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
23 25
24 void configureTreeWidget(QTreeWidget *treeWidget);
25 QTreeWidgetItem *addDatabaseItem(const QString &name, QTreeWidget *treeWidget);
26 QTreeWidgetItem *getDatabaseItem(const QString &name, QTreeWidget *treeWidget);
26 CatalogueTreeModel *m_TreeModel = nullptr;
27
28 void configureTreeWidget(QTreeView *treeView);
29 QModelIndex addDatabaseItem(const QString &name);
30 QTreeWidgetItem *getDatabaseItem(const QString &name);
27 31 void addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
28 QTreeWidgetItem *parentDatabaseItem);
32 const QModelIndex &databaseIndex);
29 33
30 CatalogueTreeWidgetItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
31 QTreeWidget *treeWidget) const;
34 CatalogueTreeWidgetItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
35 void setHasChanges(bool value, const QModelIndex &index, QTreeView *treeView);
36 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
32 37 };
33 38
34 39 CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent)
35 40 : QWidget(parent),
36 41 ui(new Ui::CatalogueSideBarWidget),
37 42 impl{spimpl::make_unique_impl<CatalogueSideBarWidgetPrivate>()}
38 43 {
39 44 ui->setupUi(this);
40 impl->configureTreeWidget(ui->treeWidget);
41 45
42 ui->treeWidget->setColumnCount(2);
43 ui->treeWidget->header()->setStretchLastSection(false);
44 ui->treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
45 ui->treeWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch);
46 impl->m_TreeModel = new CatalogueTreeModel(this);
47 ui->treeView->setModel(impl->m_TreeModel);
48
49 impl->configureTreeWidget(ui->treeView);
50
51 ui->treeView->header()->setStretchLastSection(false);
52 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
53 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
46 54
47 55 auto emitSelection = [this]() {
48 56
49 auto selectedItems = ui->treeWidget->selectedItems();
57 auto selectedItems = ui->treeView->selectionModel()->selectedRows();
50 58 if (selectedItems.isEmpty()) {
51 59 emit this->selectionCleared();
52 60 }
53 61 else {
54 62 QVector<std::shared_ptr<DBCatalogue> > catalogues;
55 63 QStringList databases;
56 int selectionType = selectedItems.first()->type();
64 auto firstIndex = selectedItems.first();
65 auto firstItem = impl->m_TreeModel->item(firstIndex);
66 if (!firstItem) {
67 Q_ASSERT(false);
68 return;
69 }
70 auto selectionType = firstItem->type();
57 71
58 for (auto item : ui->treeWidget->selectedItems()) {
59 if (item->type() == selectionType) {
72 for (auto itemIndex : selectedItems) {
73 auto item = impl->m_TreeModel->item(itemIndex);
74 if (item && item->type() == selectionType) {
60 75 switch (selectionType) {
61 76 case CATALOGUE_ITEM_TYPE:
62 77 catalogues.append(
63 78 static_cast<CatalogueTreeWidgetItem *>(item)->catalogue());
64 79 break;
65 80 case DATABASE_ITEM_TYPE:
66 81 selectionType = DATABASE_ITEM_TYPE;
67 82 databases.append(item->text(0));
68 83 case ALL_EVENT_ITEM_TYPE: // fallthrough
69 84 case TRASH_ITEM_TYPE: // fallthrough
70 85 default:
71 86 break;
72 87 }
73 88 }
74 89 else {
75 90 // Incoherent multi selection
76 91 selectionType = -1;
77 92 break;
78 93 }
79 94 }
80 95
81 96 switch (selectionType) {
82 97 case CATALOGUE_ITEM_TYPE:
83 98 emit this->catalogueSelected(catalogues);
84 99 break;
85 100 case DATABASE_ITEM_TYPE:
86 101 emit this->databaseSelected(databases);
87 102 break;
88 103 case ALL_EVENT_ITEM_TYPE:
89 104 emit this->allEventsSelected();
90 105 break;
91 106 case TRASH_ITEM_TYPE:
92 107 emit this->trashSelected();
93 108 break;
94 109 default:
95 110 emit this->selectionCleared();
96 111 break;
97 112 }
98 113 }
99 114
100 115
101 116 };
102 117
103 connect(ui->treeWidget, &QTreeWidget::itemClicked, emitSelection);
104 connect(ui->treeWidget, &QTreeWidget::currentItemChanged, emitSelection);
105 connect(ui->treeWidget, &QTreeWidget::itemChanged,
106 [emitSelection, this](auto item, auto column) {
107 auto selectedItems = ui->treeWidget->selectedItems();
108 qDebug() << "ITEM CHANGED" << column;
109 if (selectedItems.contains(item) && column == 0) {
110 emitSelection();
111 }
112 });
118 connect(ui->treeView, &QTreeView::clicked, emitSelection);
119 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, emitSelection);
120 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [emitSelection, this](auto index) {
121 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
122 if (selectedIndexes.contains(index)) {
123 emitSelection();
124 }
125
126 auto item = impl->m_TreeModel->item(index);
127 impl->setHasChanges(true, index, ui->treeView);
128 });
113 129
114 ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
115 connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this,
130 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
131 connect(ui->treeView, &QTreeWidget::customContextMenuRequested, this,
116 132 &CatalogueSideBarWidget::onContextMenuRequested);
117 133 }
118 134
119 135 CatalogueSideBarWidget::~CatalogueSideBarWidget()
120 136 {
121 137 delete ui;
122 138 }
123 139
124 140 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
125 141 bool hasChanges)
126 142 {
127 if (auto catalogueItem = impl->getCatalogueItem(catalogue, ui->treeWidget)) {
128 catalogueItem->setHasChanges(hasChanges);
143 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
144 auto index = impl->m_TreeModel->indexOf(catalogueItem);
145 impl->setHasChanges(hasChanges, index, ui->treeView);
129 146 catalogueItem->refresh();
130 147 }
131 148 }
132 149
133 150 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
134 151 {
135 152 QMenu menu{this};
136 153
137 auto currentItem = ui->treeWidget->currentItem();
154 auto currentIndex = ui->treeView->currentIndex();
155 auto currentItem = impl->m_TreeModel->item(currentIndex);
156 if (!currentItem) {
157 return;
158 }
159
138 160 switch (currentItem->type()) {
139 161 case CATALOGUE_ITEM_TYPE:
140 menu.addAction("Rename",
141 [this, currentItem]() { ui->treeWidget->editItem(currentItem); });
162 menu.addAction("Rename", [this, currentIndex]() { ui->treeView->edit(currentIndex); });
142 163 break;
143 164 case DATABASE_ITEM_TYPE:
144 165 break;
145 166 case ALL_EVENT_ITEM_TYPE:
146 167 break;
147 168 case TRASH_ITEM_TYPE:
148 169 menu.addAction("Empty Trash", []() {
149 170 // TODO
150 171 });
151 172 break;
152 173 default:
153 174 break;
154 175 }
155 176
156 177 if (!menu.isEmpty()) {
157 menu.exec(ui->treeWidget->mapToGlobal(pos));
178 menu.exec(ui->treeView->mapToGlobal(pos));
158 179 }
159 180 }
160 181
161 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(
162 QTreeWidget *treeWidget)
182 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::configureTreeWidget(QTreeView *treeView)
163 183 {
164 184 auto allEventsItem = new QTreeWidgetItem{{"All Events"}, ALL_EVENT_ITEM_TYPE};
165 185 allEventsItem->setIcon(0, QIcon(":/icones/allEvents.png"));
166 treeWidget->addTopLevelItem(allEventsItem);
186 m_TreeModel->addTopLevelItem(allEventsItem);
167 187
168 188 auto trashItem = new QTreeWidgetItem{{"Trash"}, TRASH_ITEM_TYPE};
169 189 trashItem->setIcon(0, QIcon(":/icones/trash.png"));
170 treeWidget->addTopLevelItem(trashItem);
190 m_TreeModel->addTopLevelItem(trashItem);
171 191
172 auto separator = new QFrame{treeWidget};
192 auto separator = new QFrame{treeView};
173 193 separator->setFrameShape(QFrame::HLine);
174 194 auto separatorItem = new QTreeWidgetItem{};
175 195 separatorItem->setFlags(Qt::NoItemFlags);
176 treeWidget->addTopLevelItem(separatorItem);
177 treeWidget->setItemWidget(separatorItem, 0, separator);
196 auto separatorIndex = m_TreeModel->addTopLevelItem(separatorItem);
197 treeView->setIndexWidget(separatorIndex, separator);
178 198
179 199 auto repositories = sqpApp->catalogueController().getRepositories();
180 200 for (auto dbname : repositories) {
181 auto db = addDatabaseItem(dbname, treeWidget);
182
201 auto dbIndex = addDatabaseItem(dbname);
183 202 auto catalogues = sqpApp->catalogueController().retrieveCatalogues(dbname);
184 203 for (auto catalogue : catalogues) {
185 addCatalogueItem(catalogue, db);
204 addCatalogueItem(catalogue, dbIndex);
186 205 }
187 206 }
188 207
189 treeWidget->expandAll();
208 treeView->expandAll();
190 209 }
191 210
192 QTreeWidgetItem *
193 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name,
194 QTreeWidget *treeWidget)
211 QModelIndex
212 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addDatabaseItem(const QString &name)
195 213 {
196 214 auto databaseItem = new QTreeWidgetItem{{name}, DATABASE_ITEM_TYPE};
197 215 databaseItem->setIcon(0, QIcon{":/icones/database.png"});
198 treeWidget->addTopLevelItem(databaseItem);
216 auto databaseIndex = m_TreeModel->addTopLevelItem(databaseItem);
199 217
200 return databaseItem;
218 return databaseIndex;
201 219 }
202 220
203 221 QTreeWidgetItem *
204 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name,
205 QTreeWidget *treeWidget)
222 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QString &name)
206 223 {
207 for (auto i = 0; i < treeWidget->topLevelItemCount(); ++i) {
208 auto item = treeWidget->topLevelItem(i);
224 for (auto i = 0; i < m_TreeModel->topLevelItemCount(); ++i) {
225 auto item = m_TreeModel->topLevelItem(i);
209 226 if (item->type() == DATABASE_ITEM_TYPE && item->text(0) == name) {
210 227 return item;
211 228 }
212 229 }
213 230
214 231 return nullptr;
215 232 }
216 233
217 234 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
218 const std::shared_ptr<DBCatalogue> &catalogue, QTreeWidgetItem *parentDatabaseItem)
235 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
219 236 {
220 237 auto catalogueItem = new CatalogueTreeWidgetItem{catalogue, CATALOGUE_ITEM_TYPE};
221 238 catalogueItem->setIcon(0, QIcon{":/icones/catalogue.png"});
222 parentDatabaseItem->addChild(catalogueItem);
239 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
223 240 }
224 241
225 242 CatalogueTreeWidgetItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
226 const std::shared_ptr<DBCatalogue> &catalogue, QTreeWidget *treeWidget) const
243 const std::shared_ptr<DBCatalogue> &catalogue) const
227 244 {
228 for (auto i = 0; i < treeWidget->topLevelItemCount(); ++i) {
229 auto item = treeWidget->topLevelItem(i);
245 for (auto i = 0; i < m_TreeModel->topLevelItemCount(); ++i) {
246 auto item = m_TreeModel->topLevelItem(i);
230 247 if (item->type() == DATABASE_ITEM_TYPE) {
231 248 for (auto j = 0; j < item->childCount(); ++j) {
232 249 auto childItem = item->child(j);
233 250 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
234 251 auto catalogueItem = static_cast<CatalogueTreeWidgetItem *>(childItem);
235 252 if (catalogueItem->catalogue() == catalogue) {
236 253 return catalogueItem;
237 254 }
238 255 }
239 256 else {
240 257 qCWarning(LOG_CatalogueSideBarWidget()) << "getCatalogueItem: Invalid tree "
241 258 "structure. A database item should "
242 259 "only contain catalogues.";
243 260 Q_ASSERT(false);
244 261 }
245 262 }
246 263 }
247 264 }
248 265
249 266 return nullptr;
250 267 }
268
269 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(bool value,
270 const QModelIndex &index,
271 QTreeView *treeView)
272 {
273 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
274 if (value) {
275 if (!hasChanges(validationIndex, treeView)) {
276 auto widget = CatalogueExplorerHelper::buildValidationWidget(
277 treeView,
278 [this, validationIndex, treeView]() {
279 setHasChanges(false, validationIndex, treeView);
280 },
281 [this, validationIndex, treeView]() {
282 setHasChanges(false, validationIndex, treeView);
283 });
284 treeView->setIndexWidget(validationIndex, widget);
285 }
286 }
287 else {
288 // Note: the widget is destroyed
289 treeView->setIndexWidget(validationIndex, nullptr);
290 }
291 }
292
293 bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QModelIndex &index,
294 QTreeView *treeView)
295 {
296 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
297 return treeView->indexWidget(validationIndex) != nullptr;
298 }
@@ -1,91 +1,69
1 1 #include "Catalogue/CatalogueTreeWidgetItem.h"
2 2 #include <Catalogue/CatalogueExplorerHelper.h>
3 3
4 4 #include <Catalogue/CatalogueController.h>
5 5 #include <SqpApplication.h>
6 6
7 7 #include <memory>
8 8
9 9 #include <DBCatalogue.h>
10 10
11 11 /// Column in the tree widget where the apply and cancel buttons must appear
12 12 const auto APPLY_CANCEL_BUTTONS_COLUMN = 1;
13 13
14 14 struct CatalogueTreeWidgetItem::CatalogueTreeWidgetItemPrivate {
15 15
16 16 std::shared_ptr<DBCatalogue> m_Catalogue;
17 17
18 18 CatalogueTreeWidgetItemPrivate(std::shared_ptr<DBCatalogue> catalogue) : m_Catalogue(catalogue)
19 19 {
20 20 }
21 21 };
22 22
23 23
24 24 CatalogueTreeWidgetItem::CatalogueTreeWidgetItem(std::shared_ptr<DBCatalogue> catalogue, int type)
25 25 : QTreeWidgetItem(type),
26 26 impl{spimpl::make_unique_impl<CatalogueTreeWidgetItemPrivate>(catalogue)}
27 27 {
28 setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
28 setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDropEnabled);
29 29 }
30 30
31 31 QVariant CatalogueTreeWidgetItem::data(int column, int role) const
32 32 {
33 33 if (column == 0) {
34 34 switch (role) {
35 35 case Qt::EditRole: // fallthrough
36 36 case Qt::DisplayRole:
37 37 return impl->m_Catalogue->getName();
38 38 default:
39 39 break;
40 40 }
41 41 }
42 42
43 43 return QTreeWidgetItem::data(column, role);
44 44 }
45 45
46 46 void CatalogueTreeWidgetItem::setData(int column, int role, const QVariant &value)
47 47 {
48 48 if (role == Qt::EditRole && column == 0) {
49 49 auto newName = value.toString();
50 50 if (newName != impl->m_Catalogue->getName()) {
51 51 setText(0, newName);
52 52 impl->m_Catalogue->setName(newName);
53 53 sqpApp->catalogueController().updateCatalogue(impl->m_Catalogue);
54 setHasChanges(true);
55 54 }
56 55 }
57 56 else {
58 57 QTreeWidgetItem::setData(column, role, value);
59 58 }
60 59 }
61 60
62 61 std::shared_ptr<DBCatalogue> CatalogueTreeWidgetItem::catalogue() const
63 62 {
64 63 return impl->m_Catalogue;
65 64 }
66 65
67 void CatalogueTreeWidgetItem::setHasChanges(bool value)
68 {
69 if (value) {
70 if (!hasChanges()) {
71 auto widget = CatalogueExplorerHelper::buildValidationWidget(
72 treeWidget(), [this]() { setHasChanges(false); },
73 [this]() { setHasChanges(false); });
74 treeWidget()->setItemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN, widget);
75 }
76 }
77 else {
78 // Note: the widget is destroyed
79 treeWidget()->setItemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN, nullptr);
80 }
81 }
82
83 bool CatalogueTreeWidgetItem::hasChanges()
84 {
85 return treeWidget()->itemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN) != nullptr;
86 }
87
88 66 void CatalogueTreeWidgetItem::refresh()
89 67 {
90 68 emitDataChanged();
91 69 }
@@ -1,96 +1,103
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <ui version="4.0">
3 3 <class>CatalogueSideBarWidget</class>
4 4 <widget class="QWidget" name="CatalogueSideBarWidget">
5 5 <property name="geometry">
6 6 <rect>
7 7 <x>0</x>
8 8 <y>0</y>
9 9 <width>330</width>
10 10 <height>523</height>
11 11 </rect>
12 12 </property>
13 13 <property name="windowTitle">
14 14 <string>Form</string>
15 15 </property>
16 16 <layout class="QVBoxLayout" name="verticalLayout">
17 17 <property name="leftMargin">
18 18 <number>0</number>
19 19 </property>
20 20 <property name="topMargin">
21 21 <number>0</number>
22 22 </property>
23 23 <property name="rightMargin">
24 24 <number>0</number>
25 25 </property>
26 26 <property name="bottomMargin">
27 27 <number>0</number>
28 28 </property>
29 29 <item>
30 30 <layout class="QHBoxLayout" name="horizontalLayout">
31 31 <item>
32 32 <widget class="QToolButton" name="btnAdd">
33 33 <property name="text">
34 34 <string>+</string>
35 35 </property>
36 36 <property name="icon">
37 37 <iconset resource="../../resources/sqpguiresources.qrc">
38 38 <normaloff>:/icones/add.png</normaloff>:/icones/add.png</iconset>
39 39 </property>
40 40 <property name="autoRaise">
41 41 <bool>true</bool>
42 42 </property>
43 43 </widget>
44 44 </item>
45 45 <item>
46 46 <widget class="QToolButton" name="btnRemove">
47 47 <property name="text">
48 48 <string> - </string>
49 49 </property>
50 50 <property name="icon">
51 51 <iconset resource="../../resources/sqpguiresources.qrc">
52 52 <normaloff>:/icones/remove.png</normaloff>:/icones/remove.png</iconset>
53 53 </property>
54 54 <property name="autoRaise">
55 55 <bool>true</bool>
56 56 </property>
57 57 </widget>
58 58 </item>
59 59 <item>
60 60 <spacer name="horizontalSpacer">
61 61 <property name="orientation">
62 62 <enum>Qt::Horizontal</enum>
63 63 </property>
64 64 <property name="sizeHint" stdset="0">
65 65 <size>
66 66 <width>40</width>
67 67 <height>20</height>
68 68 </size>
69 69 </property>
70 70 </spacer>
71 71 </item>
72 72 </layout>
73 73 </item>
74 74 <item>
75 <widget class="QTreeWidget" name="treeWidget">
75 <widget class="QTreeView" name="treeView">
76 <property name="acceptDrops">
77 <bool>true</bool>
78 </property>
79 <property name="dragDropMode">
80 <enum>QAbstractItemView::DropOnly</enum>
81 </property>
82 <property name="defaultDropAction">
83 <enum>Qt::CopyAction</enum>
84 </property>
76 85 <property name="selectionMode">
77 86 <enum>QAbstractItemView::ExtendedSelection</enum>
78 87 </property>
79 <attribute name="headerVisible">
80 <bool>false</bool>
88 <property name="headerHidden">
89 <bool>true</bool>
90 </property>
91 <attribute name="headerDefaultSectionSize">
92 <number>0</number>
81 93 </attribute>
82 <column>
83 <property name="text">
84 <string notr="true">1</string>
85 </property>
86 </column>
87 94 </widget>
88 95 </item>
89 96 </layout>
90 97 </widget>
91 98 <resources>
92 99 <include location="../../resources/sqpguiresources.qrc"/>
93 100 <include location="../../resources/sqpguiresources.qrc"/>
94 101 </resources>
95 102 <connections/>
96 103 </ui>
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

Status change > Approved

You need to be logged in to leave comments. Login now