##// END OF EJS Templates
"Apply" and "cancel" buttons on an event
trabillard -
r1162:73d5f3ef941a
parent child
Show More
@@ -0,0 +1,13
1 #ifndef SCIQLOP_CATALOGUEEXPLORERHELPER_H
2 #define SCIQLOP_CATALOGUEEXPLORERHELPER_H
3
4 #include <QWidget>
5
6 #include <functional>
7
8 struct CatalogueExplorerHelper {
9 static QWidget *buildValidationWidget(QWidget *parent, std::function<void()> save,
10 std::function<void()> discard);
11 };
12
13 #endif // SCIQLOP_CATALOGUEEXPLORERHELPER_H
@@ -0,0 +1,32
1 #include "Catalogue/CatalogueExplorerHelper.h"
2
3 #include <QBoxLayout>
4 #include <QToolButton>
5
6 const auto VALIDATION_BUTTON_ICON_SIZE = 12;
7
8 QWidget *CatalogueExplorerHelper::buildValidationWidget(QWidget *parent, std::function<void()> save,
9 std::function<void()> discard)
10 {
11 auto widget = new QWidget{parent};
12
13 auto layout = new QHBoxLayout{widget};
14 layout->setContentsMargins(0, 0, 0, 0);
15 layout->setSpacing(0);
16
17 auto btnValid = new QToolButton{widget};
18 btnValid->setIcon(QIcon{":/icones/save"});
19 btnValid->setIconSize(QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
20 btnValid->setAutoRaise(true);
21 QObject::connect(btnValid, &QToolButton::clicked, save);
22 layout->addWidget(btnValid);
23
24 auto btnDiscard = new QToolButton{widget};
25 btnDiscard->setIcon(QIcon{":/icones/discard"});
26 btnDiscard->setIconSize(QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
27 btnDiscard->setAutoRaise(true);
28 QObject::connect(btnDiscard, &QToolButton::clicked, discard);
29 layout->addWidget(btnDiscard);
30
31 return widget;
32 }
@@ -3,17 +3,29
3 3
4 4 #include <Common/spimpl.h>
5 5 #include <QAbstractItemModel>
6 #include <QLoggingCategory>
7 #include <unordered_set>
6 8
7 9 class DBEvent;
8 10 class DBEventProduct;
9 11
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsModel)
13
10 14 class CatalogueEventsModel : public QAbstractItemModel {
15 Q_OBJECT
16
17 signals:
18 void modelSorted();
19
11 20 public:
12 21 CatalogueEventsModel(QObject *parent = nullptr);
13 22
23 enum class Column { Name, TStart, TEnd, Tags, Product, Validation, NbColumn };
24
14 25 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
15 26 void addEvent(const std::shared_ptr<DBEvent> &event);
16 27 void removeEvent(const std::shared_ptr<DBEvent> &event);
28 QVector<std::shared_ptr<DBEvent> > events() const;
17 29
18 30 enum class ItemType { Root, Event, EventProduct };
19 31 ItemType itemTypeOf(const QModelIndex &index) const;
@@ -21,8 +33,18 public:
21 33 std::shared_ptr<DBEvent> getParentEvent(const QModelIndex &index) const;
22 34 std::shared_ptr<DBEventProduct> getEventProduct(const QModelIndex &index) const;
23 35
36 /// Refresh the data for the specified event
24 37 void refreshEvent(const std::shared_ptr<DBEvent> &event);
25 38
39 /// Returns a QModelIndex which represent the specified event
40 QModelIndex indexOf(const std::shared_ptr<DBEvent> &event) const;
41
42 /// Marks a change flag on the specified event to allow sorting on the validation column
43 void setEventHasChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
44
45 /// Returns true if the specified event has unsaved changes
46 bool eventsHasChanges(const std::shared_ptr<DBEvent> &event) const;
47
26 48 // Model
27 49 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
28 50 QModelIndex parent(const QModelIndex &index) const;
@@ -22,6 +22,9 public:
22 22 /// changes
23 23 void setHasChanges(bool value);
24 24
25 /// Returns true if the widget indicating the event has unsaved changes is displayed
26 bool hasChanges();
27
25 28 /// Refreshes the data displayed by the item from the catalogue
26 29 void refresh();
27 30
@@ -25,7 +25,8 gui_moc_headers = [
25 25 'include/Catalogue/CatalogueExplorer.h',
26 26 'include/Catalogue/CatalogueEventsWidget.h',
27 27 'include/Catalogue/CatalogueSideBarWidget.h',
28 'include/Catalogue/CatalogueInspectorWidget.h'
28 'include/Catalogue/CatalogueInspectorWidget.h',
29 'include/Catalogue/CatalogueEventsModel.h'
29 30 ]
30 31
31 32 gui_ui_files = [
@@ -116,7 +117,8 gui_sources = [
116 117 'src/Catalogue/CatalogueSideBarWidget.cpp',
117 118 'src/Catalogue/CatalogueInspectorWidget.cpp',
118 119 'src/Catalogue/CatalogueTreeWidgetItem.cpp',
119 'src/Catalogue/CatalogueEventsModel.cpp'
120 'src/Catalogue/CatalogueEventsModel.cpp',
121 'src/Catalogue/CatalogueExplorerHelper.cpp'
120 122 ]
121 123
122 124 gui_inc = include_directories(['include'])
@@ -15,33 +15,46
15 15 #include <QHash>
16 16 #include <QMimeData>
17 17
18 Q_LOGGING_CATEGORY(LOG_CatalogueEventsModel, "CatalogueEventsModel")
19
18 20 const auto EVENT_ITEM_TYPE = 1;
19 21 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
20 22
21 23 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
22 24 QVector<std::shared_ptr<DBEvent> > m_Events;
23 25 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
26 std::unordered_set<std::shared_ptr<DBEvent> > m_EventsWithChanges;
24 27
25 enum class Column { Name, TStart, TEnd, Tags, Product, NbColumn };
26 28 QStringList columnNames()
27 29 {
28 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"), tr("Tags"), tr("Product")};
30 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"),
31 tr("Tags"), tr("Product"), tr("")};
32 }
33
34 QVariant sortData(int col, const std::shared_ptr<DBEvent> &event) const
35 {
36 if (col == (int)CatalogueEventsModel::Column::Validation) {
37 return m_EventsWithChanges.find(event) != m_EventsWithChanges.cend() ? true
38 : QVariant();
39 }
40
41 return eventData(col, event);
29 42 }
30 43
31 44 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
32 45 {
33 46 switch (static_cast<Column>(col)) {
34 case Column::Name:
47 case CatalogueEventsModel::Column::Name:
35 48 return event->getName();
36 case Column::TStart:
49 case CatalogueEventsModel::Column::TStart:
37 50 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
38 51 : QVariant{};
39 case Column::TEnd:
52 case CatalogueEventsModel::Column::TEnd:
40 53 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
41 54 : QVariant{};
42 case Column::Product:
55 case CatalogueEventsModel::Column::Product:
43 56 return QString::number(nbEventProducts(event)) + " product(s)";
44 case Column::Tags: {
57 case CatalogueEventsModel::Column::Tags: {
45 58 QString tagList;
46 59 auto tags = event->getTags();
47 60 for (auto tag : tags) {
@@ -51,6 +64,8 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
51 64
52 65 return tagList;
53 66 }
67 case CatalogueEventsModel::Column::Validation:
68 return QVariant();
54 69 default:
55 70 break;
56 71 }
@@ -80,17 +95,18 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
80 95 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
81 96 {
82 97 switch (static_cast<Column>(col)) {
83 case Column::Name:
98 case CatalogueEventsModel::Column::Name:
84 99 return eventProduct->getProductId();
85 case Column::TStart:
100 case CatalogueEventsModel::Column::TStart:
86 101 return DateUtils::dateTime(eventProduct->getTStart());
87 case Column::TEnd:
102 case CatalogueEventsModel::Column::TEnd:
88 103 return DateUtils::dateTime(eventProduct->getTEnd());
89 case Column::Product:
104 case CatalogueEventsModel::Column::Product:
90 105 return eventProduct->getProductId();
91 case Column::Tags: {
106 case CatalogueEventsModel::Column::Tags:
92 107 return QString();
93 }
108 case CatalogueEventsModel::Column::Validation:
109 return QVariant();
94 110 default:
95 111 break;
96 112 }
@@ -111,6 +127,7 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &e
111 127
112 128 impl->m_Events = events;
113 129 impl->m_EventProducts.clear();
130 impl->m_EventsWithChanges.clear();
114 131 for (auto event : events) {
115 132 impl->parseEventProduct(event);
116 133 }
@@ -165,21 +182,58 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
165 182 beginRemoveRows(QModelIndex(), index, index);
166 183 impl->m_Events.removeAt(index);
167 184 impl->m_EventProducts.erase(event.get());
185 impl->m_EventsWithChanges.erase(event);
168 186 endRemoveRows();
169 187 }
170 188 }
171 189
190 QVector<std::shared_ptr<DBEvent> > CatalogueEventsModel::events() const
191 {
192 return impl->m_Events;
193 }
194
172 195 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event)
173 196 {
174 auto i = impl->m_Events.indexOf(event);
175 if (i >= 0) {
176 auto eventIndex = index(i, 0);
197 auto eventIndex = indexOf(event);
198 if (eventIndex.isValid()) {
199
200 // Refreshes the event line
177 201 auto colCount = columnCount();
178 emit dataChanged(eventIndex, index(i, colCount));
202 emit dataChanged(eventIndex, index(eventIndex.row(), colCount));
179 203
204 // Also refreshes its children event products
180 205 auto childCount = rowCount(eventIndex);
181 206 emit dataChanged(index(0, 0, eventIndex), index(childCount, colCount, eventIndex));
182 207 }
208 else {
209 qCWarning(LOG_CatalogueEventsModel()) << "refreshEvent: event not found.";
210 }
211 }
212
213 QModelIndex CatalogueEventsModel::indexOf(const std::shared_ptr<DBEvent> &event) const
214 {
215 auto row = impl->m_Events.indexOf(event);
216 if (row >= 0) {
217 return index(row, 0);
218 }
219
220 return QModelIndex();
221 }
222
223 void CatalogueEventsModel::setEventHasChanges(const std::shared_ptr<DBEvent> &event,
224 bool hasChanges)
225 {
226 if (hasChanges) {
227 impl->m_EventsWithChanges.insert(event);
228 }
229 else {
230 impl->m_EventsWithChanges.erase(event);
231 }
232 }
233
234 bool CatalogueEventsModel::eventsHasChanges(const std::shared_ptr<DBEvent> &event) const
235 {
236 return impl->m_EventsWithChanges.find(event) != impl->m_EventsWithChanges.cend();
183 237 }
184 238
185 239 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
@@ -255,7 +309,7 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
255 309
256 310 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
257 311 {
258 return static_cast<int>(CatalogueEventsModelPrivate::Column::NbColumn);
312 return static_cast<int>(CatalogueEventsModel::Column::NbColumn);
259 313 }
260 314
261 315 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
@@ -302,8 +356,8 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
302 356 {
303 357 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
304 358 [this, column, order](auto e1, auto e2) {
305 auto data1 = impl->eventData(column, e1);
306 auto data2 = impl->eventData(column, e2);
359 auto data1 = impl->sortData(column, e1);
360 auto data2 = impl->sortData(column, e2);
307 361
308 362 auto result = data1.toString() < data2.toString();
309 363
@@ -311,6 +365,7 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
311 365 });
312 366
313 367 emit dataChanged(QModelIndex(), QModelIndex());
368 emit modelSorted();
314 369 }
315 370
316 371 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
@@ -3,6 +3,7
3 3
4 4 #include <Catalogue/CatalogueController.h>
5 5 #include <Catalogue/CatalogueEventsModel.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
6 7 #include <CatalogueDao.h>
7 8 #include <DBCatalogue.h>
8 9 #include <SqpApplication.h>
@@ -16,8 +17,8
16 17
17 18 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
18 19
19 /// Format of the dates appearing in the label of a cursor
20 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss");
20 /// Fixed size of the validation column
21 const auto VALIDATION_COLUMN_SIZE = 35;
21 22
22 23 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
23 24
@@ -277,8 +278,20 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
277 278 });
278 279
279 280 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
280 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
281 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
282 QHeaderView::Stretch);
283 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
284 QHeaderView::Fixed);
285 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
286 VALIDATION_COLUMN_SIZE);
281 287 ui->treeView->header()->setSortIndicatorShown(true);
288
289 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
290 auto allEvents = impl->m_Model->events();
291 for (auto event : allEvents) {
292 setEventChanges(event, impl->m_Model->eventsHasChanges(event));
293 }
294 });
282 295 }
283 296
284 297 CatalogueEventsWidget::~CatalogueEventsWidget()
@@ -294,6 +307,25 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualiz
294 307 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
295 308 {
296 309 impl->m_Model->refreshEvent(event);
310
311 auto eventIndex = impl->m_Model->indexOf(event);
312 auto validationIndex
313 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
314
315 if (hasChanges) {
316 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
317 auto widget = CatalogueExplorerHelper::buildValidationWidget(
318 ui->treeView, [this, event]() { setEventChanges(event, false); },
319 [this, event]() { setEventChanges(event, false); });
320 ui->treeView->setIndexWidget(validationIndex, widget);
321 }
322 }
323 else {
324 // Note: the widget is destroyed
325 ui->treeView->setIndexWidget(validationIndex, nullptr);
326 }
327
328 impl->m_Model->setEventHasChanges(event, hasChanges);
297 329 }
298 330
299 331 void CatalogueEventsWidget::populateWithCatalogues(
@@ -1,12 +1,9
1 1 #include "Catalogue/CatalogueTreeWidgetItem.h"
2 #include <Catalogue/CatalogueExplorerHelper.h>
2 3
3 4 #include <memory>
4 5
5 6 #include <DBCatalogue.h>
6 #include <QBoxLayout>
7 #include <QToolButton>
8
9 const auto VALIDATION_BUTTON_ICON_SIZE = 12;
10 7
11 8 /// Column in the tree widget where the apply and cancel buttons must appear
12 9 const auto APPLY_CANCEL_BUTTONS_COLUMN = 1;
@@ -66,29 +63,11 std::shared_ptr<DBCatalogue> CatalogueTreeWidgetItem::catalogue() const
66 63 void CatalogueTreeWidgetItem::setHasChanges(bool value)
67 64 {
68 65 if (value) {
69 if (treeWidget()->itemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN) == nullptr) {
70 auto widet = new QWidget{treeWidget()};
71
72 auto layout = new QHBoxLayout{widet};
73 layout->setContentsMargins(0, 0, 0, 0);
74 layout->setSpacing(0);
75
76 auto btnValid = new QToolButton{widet};
77 btnValid->setIcon(QIcon{":/icones/save"});
78 btnValid->setIconSize(QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
79 btnValid->setAutoRaise(true);
80 QObject::connect(btnValid, &QToolButton::clicked, [this]() { setHasChanges(false); });
81 layout->addWidget(btnValid);
82
83 auto btnDiscard = new QToolButton{widet};
84 btnDiscard->setIcon(QIcon{":/icones/discard"});
85 btnDiscard->setIconSize(
86 QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
87 btnDiscard->setAutoRaise(true);
88 QObject::connect(btnDiscard, &QToolButton::clicked, [this]() { setHasChanges(false); });
89 layout->addWidget(btnDiscard);
90
91 treeWidget()->setItemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN, {widet});
66 if (!hasChanges()) {
67 auto widget = CatalogueExplorerHelper::buildValidationWidget(
68 treeWidget(), [this]() { setHasChanges(false); },
69 [this]() { setHasChanges(false); });
70 treeWidget()->setItemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN, widget);
92 71 }
93 72 }
94 73 else {
@@ -97,6 +76,11 void CatalogueTreeWidgetItem::setHasChanges(bool value)
97 76 }
98 77 }
99 78
79 bool CatalogueTreeWidgetItem::hasChanges()
80 {
81 return treeWidget()->itemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN) != nullptr;
82 }
83
100 84 void CatalogueTreeWidgetItem::refresh()
101 85 {
102 86 emitDataChanged();
General Comments 0
You need to be logged in to leave comments. Login now