Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/dialogs/fix/GNEFixElementsDialog.h
169684 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GNEFixElementsDialog.h
15
/// @author Pablo Alvarez Lopez
16
/// @date Jul 2025
17
///
18
// template used to fix elements during saving
19
/****************************************************************************/
20
#pragma once
21
#include <config.h>
22
23
#include <netedit/dialogs/basic/GNEErrorBasicDialog.h>
24
#include <netedit/dialogs/basic/GNEInformationBasicDialog.h>
25
#include <utils/foxtools/MFXGroupBoxModule.h>
26
#include <utils/gui/div/GUIDesigns.h>
27
#include <utils/gui/windows/GUIAppEnum.h>
28
29
// ===========================================================================
30
// class definitions
31
// ===========================================================================
32
33
template <typename T>
34
class GNEFixElementsDialog : public GNEDialog {
35
36
public:
37
/// @brief Conflict
38
class ConflictElement {
39
40
public:
41
/// @brief constructor
42
ConflictElement(T element, const std::string& id, FXIcon* icon, const std::string& description) :
43
myElement(element),
44
myID(id),
45
myIcon(icon),
46
myDescription(description) {}
47
48
/// @brief destructor
49
~ConflictElement() {}
50
51
/// @brief conflicted element
52
T getElement() const {
53
return myElement;
54
}
55
56
/// @brief get element ID
57
const std::string& getID() const {
58
return myID;
59
}
60
61
/// @brief get element icon
62
FXIcon* getIcon() const {
63
return myIcon;
64
}
65
66
/// @brief get conflict description
67
const std::string& getDescription() const {
68
return myDescription;
69
}
70
71
private:
72
/// @brief conflicted element
73
T myElement;
74
75
/// @brief ID of the element
76
std::string myID;
77
78
/// @brief icon
79
FXIcon* myIcon = nullptr;
80
81
/// @brief conflict description
82
std::string myDescription;
83
84
/// @brief invalidate default constructor
85
ConflictElement() = delete;
86
};
87
88
/// @brief GNEFixOptions module
89
class FixOptions : public MFXGroupBoxModule {
90
91
public:
92
/// @brief constructor
93
FixOptions(GNEFixElementsDialog<T>* fixElementDialog, FXVerticalFrame* frameParent, const std::string& title) :
94
MFXGroupBoxModule(frameParent, title, MFXGroupBoxModule::Options::SAVE),
95
myFixElementDialogParent(fixElementDialog) {
96
// register this fix option to list of fix options
97
fixElementDialog->registerFixOptions(this);
98
// Create table
99
myTable = new FXTable(getCollapsableFrame(), this, MID_TABLE, GUIDesignTableFixElements);
100
// create frames for options
101
FXHorizontalFrame* optionsFrame = new FXHorizontalFrame(getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame);
102
myLeftFrameOptions = new FXVerticalFrame(optionsFrame, GUIDesignAuxiliarFrameFixedWidth(int(myTable->getWidth() * 0.5)));
103
myRightFrameOptions = new FXVerticalFrame(optionsFrame, GUIDesignAuxiliarFrameFixedWidth(int(myTable->getWidth() * 0.5)));
104
}
105
106
/// @brief select internal test solution (used in internal tests)
107
virtual void selectInternalTestSolution(const std::string& solution) = 0;
108
109
/// @brief apply selected fix option
110
virtual bool applyFixOption() = 0;
111
112
/// @name FOX-callbacks
113
/// @{
114
115
/// @brief called when user select a option
116
virtual long onCmdSelectOption(FXObject*, FXSelector, void*) = 0;
117
118
/// @}
119
120
/// @brief set invalid elements to fix
121
void setInvalidElements(const std::vector<ConflictElement>& conflictedElements) {
122
// parse invalid elements
123
myConflictedElements = conflictedElements;
124
// configure table
125
myTable->setTableSize((int)(myConflictedElements.size()), 3);
126
myTable->setSelBackColor(FXRGBA(255, 255, 255, 255));
127
myTable->setSelTextColor(FXRGBA(0, 0, 0, 255));
128
myTable->setEditable(false);
129
// configure header
130
myTable->setVisibleColumns(4);
131
myTable->setColumnHeaderHeight(GUIDesignHeight);
132
myTable->getRowHeader()->setWidth(0);
133
// icon
134
myTable->setColumnWidth(0, GUIDesignHeight);
135
myTable->setColumnText(0, "");
136
// ID
137
myTable->setColumnWidth(1, 110);
138
myTable->setColumnText(1, toString(SUMO_ATTR_ID).c_str());
139
// description
140
myTable->setColumnWidth(2, myTable->getWidth() - GUIDesignHeight - 110 - 15);
141
myTable->setColumnText(2, TL("Conflict"));
142
// Declare pointer to FXTableItem
143
FXTableItem* item = nullptr;
144
// iterate over invalid edges
145
for (int i = 0; i < (int)myConflictedElements.size(); i++) {
146
// Set icon
147
item = new FXTableItem("", myConflictedElements.at(i).getIcon());
148
item->setIconPosition(FXTableItem::CENTER_X);
149
myTable->setItem(i, 0, item);
150
// Set ID
151
item = new FXTableItem(myConflictedElements.at(i).getID().c_str());
152
item->setJustify(FXTableItem::LEFT | FXTableItem::CENTER_Y);
153
myTable->setItem(i, 1, item);
154
// Set conflict
155
item = new FXTableItem(myConflictedElements.at(i).getDescription().c_str());
156
item->setJustify(FXTableItem::LEFT | FXTableItem::CENTER_Y);
157
myTable->setItem(i, 2, item);
158
// set row height
159
myTable->setRowHeight(i, GUIDesignHeight);
160
}
161
// check if enable or disable options
162
if (myConflictedElements.size() > 0) {
163
enableOptions();
164
} else {
165
disableOptions();
166
}
167
}
168
169
protected:
170
/// @brief pointer to the parent dialog
171
GNEFixElementsDialog* myFixElementDialogParent = nullptr;
172
173
/// @brief Table with the demand elements
174
FXTable* myTable = nullptr;
175
176
/// @brief vertical left frame for options
177
FXVerticalFrame* myLeftFrameOptions = nullptr;
178
179
/// @brief vertical right frame for options
180
FXVerticalFrame* myRightFrameOptions = nullptr;
181
182
/// @brief list of elements to fix
183
std::vector<ConflictElement> myConflictedElements;
184
185
/// @brief default constructor
186
FixOptions() :
187
MFXGroupBoxModule() {
188
}
189
190
/// @brief add option to options container (used for adjust width and enable/disable)
191
void registerOption(FXWindow* option) {
192
myOptions.push_back(option);
193
// adjust width
194
option->setWidth(int(myTable->getWidth() * 0.5));
195
}
196
197
private:
198
/// @brief list of options
199
std::vector<FXWindow*> myOptions;
200
201
/// @brief enable options
202
void enableOptions() {
203
// enable each option
204
for (auto option : myOptions) {
205
option->enable();
206
}
207
}
208
209
/// @brief disable options
210
void disableOptions() {
211
// disable each option
212
for (auto option : myOptions) {
213
option->disable();
214
}
215
}
216
217
/// @brief save save list of conflicted items to a file (Reimplemented from MFXGroupBoxModule)
218
bool saveContents() const {
219
// open file dialog to save list of conflicted items
220
const FXString file = MFXUtils::getFilename2Write(myTable,
221
TL("Save list of conflicted items"),
222
SUMOXMLDefinitions::TXTFileExtensions.getMultilineString().c_str(),
223
GUIIconSubSys::getIcon(GUIIcon::SAVE), gCurrentFolder);
224
// continue if file is not empty
225
if (file == "") {
226
return false;
227
} else {
228
try {
229
// open output device
230
OutputDevice& device = OutputDevice::getDevice(file.text());
231
// get invalid element ID and problem
232
for (const auto& conflictedElement : myConflictedElements) {
233
device << conflictedElement.getID() << ":" << conflictedElement.getDescription() << "\n";
234
}
235
// close output device
236
device.close();
237
// open information message box
238
GNEInformationBasicDialog(myFixElementDialogParent->myApplicationWindow,
239
TL("Saving successfully"),
240
TL("List of conflicted items was successfully saved"));
241
return true;
242
} catch (IOError& e) {
243
// open message box error
244
GNEErrorBasicDialog(myFixElementDialogParent->myApplicationWindow,
245
TL("Saving list of conflicted items failed"), e.what());
246
return false;
247
}
248
}
249
}
250
251
/// @brief Invalidated copy constructor.
252
FixOptions(const FixOptions&) = delete;
253
254
/// @brief Invalidated assignment operator.
255
FixOptions& operator=(const FixOptions&) = delete;
256
};
257
258
/// @brief Constructor
259
GNEFixElementsDialog(GNEApplicationWindow* mainWindow, const std::string title,
260
GUIIcon icon, DialogType type):
261
GNEDialog(mainWindow, title.c_str(), icon, type, GNEDialog::Buttons::ACCEPT_CANCEL,
262
GNEDialog::OpenType::MODAL, ResizeMode::STATIC) {
263
// create left and right frames
264
FXHorizontalFrame* columnFrame = new FXHorizontalFrame(myContentFrame, GUIDesignAuxiliarHorizontalFrame);
265
myLeftFrame = new FXVerticalFrame(columnFrame, GUIDesignAuxiliarVerticalFrame);
266
myRightFrame = new FXVerticalFrame(columnFrame, GUIDesignAuxiliarVerticalFrame);
267
}
268
269
/// @brief destructor
270
~GNEFixElementsDialog() {}
271
272
/// @brief pointer to the main window
273
GNEApplicationWindow* getApplicationWindow() {
274
return myApplicationWindow;
275
}
276
277
/// @brief register fix options to the dialog (called automatically during FixOptions constructor)
278
void registerFixOptions(FixOptions* fixOptions) {
279
myFixOptions.push_back(fixOptions);
280
}
281
282
/// @brief run internal test
283
void runInternalTest(const InternalTestStep::DialogArgument* dialogArgument) {
284
// run internal test for each fix option
285
for (auto fixOption : myFixOptions) {
286
fixOption->selectInternalTestSolution(dialogArgument->getCustomAction());
287
}
288
}
289
290
/// @name FOX-callbacks
291
/// @{
292
293
/// @brief event after press accept button
294
long onCmdAccept(FXObject*, FXSelector, void*) {
295
bool abortSaving = false;
296
// apply each fix option in their correspond fixOption
297
for (auto fixOption : myFixOptions) {
298
// if applyFixOption returns false, abort saving (usually for selecting invalid elements)
299
if (fixOption->applyFixOption() == false) {
300
abortSaving = true;
301
}
302
}
303
// continue depending of abortSaving
304
if (abortSaving == false) {
305
return closeDialogAccepting();
306
} else {
307
return closeDialogCanceling();
308
}
309
}
310
311
/// @}
312
313
protected:
314
/// @brief vector with all fix options
315
std::vector<GNEFixElementsDialog::FixOptions*> myFixOptions;
316
317
/// @brief left frame for fix options
318
FXVerticalFrame* myLeftFrame = nullptr;
319
320
/// @brief right frame for fix options
321
FXVerticalFrame* myRightFrame = nullptr;
322
323
private:
324
/// @brief Invalidated copy constructor.
325
GNEFixElementsDialog(const GNEFixElementsDialog&) = delete;
326
327
/// @brief Invalidated assignment operator.
328
GNEFixElementsDialog& operator=(const GNEFixElementsDialog&) = delete;
329
};
330
331