Engauge Digitizer 2
Loading...
Searching...
No Matches
DlgSettingsCurveList.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3 * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4 * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5 ******************************************************************************************************/
6
7#include "ButtonWhatsThis.h"
8#include "CmdMediator.h"
10#include "CurveNameList.h"
12#include "EngaugeAssert.h"
13#include "Logger.h"
14#include "MainWindow.h"
15#include <QCheckBox>
16#include <QDebug>
17#include <QGridLayout>
18#include <QLabel>
19#include <QListView>
20#include <QMessageBox>
21#include <QPushButton>
22#include <QSettings>
23#include <QSpacerItem>
24#include <QTableView>
25#include <QTextStream>
26#include "QtToString.h"
27#include <QWhatsThis>
28#include "Settings.h"
29#include "SettingsForGraph.h"
30
31const int MINIMUM_HEIGHT = 500;
32
34 DlgSettingsAbstractBase (tr ("Curve List"),
35 "DlgSettingsCurveList",
37 m_curveNameList (nullptr)
38{
39 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::DlgSettingsCurveList";
40
41 QWidget *subPanel = createSubPanel ();
42 finishPanel (subPanel);
43}
44
46{
47 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::~DlgSettingsCurveList";
48}
49
50void DlgSettingsCurveList::appendCurveName (const QString &curveNameNew,
51 const QString &curveNameOriginal,
52 int numPoints)
53{
54 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::appendCurveName"
55 << " curve=" << curveNameNew.toLatin1().data();
56
57 ENGAUGE_CHECK_PTR (m_curveNameList);
58
59 int row = m_curveNameList->rowCount ();
60 insertCurveName (row,
61 curveNameNew,
62 curveNameOriginal,
63 numPoints);
64}
65
66void DlgSettingsCurveList::createButtons (QGridLayout *layout,
67 int &row)
68{
69 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::createButtons";
70
71 m_btnAdd = new QPushButton (tr ("Add..."));
72 m_btnAdd->setWhatsThis (tr ("Adds a new curve to the curve list. The curve name can be edited in the curve name list.\n\n"
73 "Every curve name must be unique"));
74 m_btnAdd->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
75 connect (m_btnAdd, SIGNAL (released ()), this, SLOT (slotNew()));
76 layout->addWidget (m_btnAdd, row, 1, 1, 1, Qt::AlignLeft);
77
78 m_btnRemove = new QPushButton (tr ("Remove"));
79 m_btnRemove->setWhatsThis (tr ("Removes the currently selected curve from the curve list.\n\n"
80 "There must always be at least one curve"));
81 m_btnRemove->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
82 connect (m_btnRemove, SIGNAL (released ()), this, SLOT (slotRemove()));
83 layout->addWidget (m_btnRemove, row++, 2, 1, 1, Qt::AlignRight);
84}
85
86void DlgSettingsCurveList::createListCurves (QGridLayout *layout,
87 int &row)
88{
89 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::createListCurves";
90
91 QLabel *label = new QLabel (QString ("%1:").arg (tr ("Curve Names")));
92 layout->addWidget (label, row++, 1);
93
94 // There is no Qt::ItemIsEditable flag for QListView, so instead we set that flag for the QListViewItems
95 m_listCurves = new QListView;
96 m_listCurves->setWhatsThis (tr ("List of the curves belonging to this document.\n\n"
97 "Click on a curve name to edit it. Each curve name must be unique.\n\n"
98 "Reorder curves by dragging them around."));
99 m_listCurves->setMinimumHeight (200);
100 m_listCurves->setSelectionBehavior (QAbstractItemView::SelectItems);
101 m_listCurves->setDragDropOverwriteMode (false);
102 m_listCurves->setSelectionMode (QAbstractItemView::SingleSelection);
103 m_listCurves->setDefaultDropAction (Qt::MoveAction);
104 m_listCurves->setDragDropOverwriteMode (false);
105 m_listCurves->setDragEnabled (true);
106 m_listCurves->setDropIndicatorShown (true); // Visible confirmation that each row can be dragged and dropped to move
107 m_listCurves->setDragDropMode (QAbstractItemView::InternalMove);
108 layout->addWidget (m_listCurves, row, 1, 1, 2);
109
110 createWhatsThis (layout,
111 m_btnWhatsThis,
112 row++,
113 3);
114
115 m_curveNameList = new CurveNameList;
116 connect (m_curveNameList, SIGNAL (rowsAboutToBeRemoved (const QModelIndex &, int, int)),
117 this, SLOT (slotRowsAboutToBeRemoved (const QModelIndex &, int, int)));
118 connect (m_curveNameList, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex &, const QVector<int> &)),
119 this, SLOT (slotDataChanged (const QModelIndex &, const QModelIndex &, const QVector<int> &)));
120
121 m_listCurves->setModel (m_curveNameList);
122}
123
125{
126 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::createOptionalSaveDefault";
127
128 m_btnSaveDefault = new QPushButton (tr ("Save As Default"));
129 m_btnSaveDefault->setWhatsThis (tr ("Save the curve names for use as defaults for future graph curves."));
130 connect (m_btnSaveDefault, SIGNAL (released ()), this, SLOT (slotSaveDefault ()));
131 layout->addWidget (m_btnSaveDefault, 0, Qt::AlignLeft);
132
133 m_btnResetDefault = new QPushButton (tr ("Reset Default"));
134 m_btnResetDefault->setWhatsThis (tr ("Reset the defaults for future graph curves to the original settings."));
135 connect (m_btnResetDefault, SIGNAL (released ()), this, SLOT (slotResetDefault()));
136 layout->addWidget (m_btnResetDefault, 0, Qt::AlignRight);
137
138 QSpacerItem *spacer = new QSpacerItem (40, 2);
139 layout->addItem (spacer);
140}
141
143{
144 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::createSubPanel";
145
146 const int EMPTY_COLUMN_WIDTH = 30;
147
148 QWidget *subPanel = new QWidget ();
149 QGridLayout *layout = new QGridLayout (subPanel);
150 subPanel->setLayout (layout);
151
152 int row = 0;
153 createListCurves (layout, row);
154 createButtons (layout, row);
155
156 layout->setColumnStretch (0, 0); // Empty first column
157 layout->setColumnMinimumWidth (0, EMPTY_COLUMN_WIDTH);
158 layout->setColumnStretch (1, 1); // New
159 layout->setColumnStretch (2, 1); // Remove
160 layout->setColumnStretch (3, 0); // Empty last column
161 layout->setColumnMinimumWidth (3, EMPTY_COLUMN_WIDTH);
162
163 return subPanel;
164}
165
166bool DlgSettingsCurveList::endsWithNumber (const QString &str) const
167{
168 bool success = false;
169
170 if (!str.isEmpty ()) {
171
172 success = (str.right (1).at (0).digitValue() >= 0);
173 }
174
175 return success;
176}
177
179{
180 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::handleOk";
181
183 cmdMediator ().document(),
184 *m_curveNameList);
185 cmdMediator ().push (cmd);
186
187 hide ();
188}
189
190void DlgSettingsCurveList::insertCurveName (int row,
191 const QString &curveNameNew,
192 const QString &curveNameOriginal,
193 int numPoints)
194{
195 // Track all entries
196 m_curveNameList->insertRow (row,
197 curveNameNew,
198 curveNameOriginal,
199 unsigned (numPoints));
200}
201
203{
204 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::load";
205
207
208 // Perform comprehensive clearing
209 m_listCurves->reset ();
210 m_curveNameList->reset ();
211
212 QStringList curveNames = cmdMediator.curvesGraphsNames ();
213 QStringList::const_iterator itr;
214 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
215 QString curveName = *itr;
216 appendCurveName (curveName,
217 curveName,
218 cmdMediator.curvesGraphsNumPoints (curveName));
219 }
220
221 selectCurveName (curveNames.first());
222
223 updateControls (); // Make especially sure Remove is disabled if there is just one curve, or none are selected
224 enableOk (false); // Disable Ok button since there not yet any changes
225}
226
227int DlgSettingsCurveList::newRowFromSelection () const
228{
229 int numSelectedItems = m_listCurves->selectionModel ()->selectedIndexes ().count ();
230 int numItems = m_listCurves->model ()->rowCount ();
231
232 // Determine index where new entry will be inserted
233 int newRow = -1;
234 if ((numSelectedItems == 0) &&
235 (numItems > 0)) {
236
237 // Append after list which has at least one entry
238 newRow = numItems;
239
240 } else if (numSelectedItems == 1) {
241
242 // Insert after the selected index
243 newRow = 1 + m_listCurves->selectionModel ()->selectedIndexes ().at (0).row ();
244
245 }
246
247 return newRow;
248}
249
250QString DlgSettingsCurveList::nextCurveName () const
251{
252 const QString DASH_ONE ("-1"); // Nice value to start a new range at a lower level than the current level
253
254 ENGAUGE_CHECK_PTR (m_listCurves);
255
256 int newRow = newRowFromSelection ();
257 int numItems = m_listCurves->model ()->rowCount ();
258
259 // Curves names of existing before/after curves
260 QString curveNameBefore, curveNameAfter;
261 if (newRow > 0) {
262
263 QModelIndex index = m_curveNameList->index (newRow - 1, 0);
264 curveNameBefore = m_curveNameList->data (index).toString ();
265
266 }
267
268 if ((0 <= newRow) && (newRow < numItems)) {
269
270 QModelIndex index = m_curveNameList->index (newRow, 0);
271 curveNameAfter = m_curveNameList->data (index).toString ();
272
273 }
274
275 // New curve name computed from previous curve name
276 QString curveNameNext;
277 if (curveNameBefore.isEmpty () && !curveNameAfter.isEmpty () && endsWithNumber (curveNameAfter)) {
278
279 // Pick a name before curveNameAfter
280 int numberAfter = numberAtEnd (curveNameAfter);
281 int numberNew = numberAfter - 1;
282 int pos = curveNameAfter.lastIndexOf (QString::number (numberAfter));
283 if (pos >= 0) {
284
285 curveNameNext = QString ("%1%2")
286 .arg (curveNameAfter.left (pos))
287 .arg (numberNew);
288
289 } else {
290
291 curveNameNext = curveNameAfter; // Better than nothing
292
293 }
294
295 } else if (curveNameBefore.isEmpty ()) {
296
297 curveNameNext = DEFAULT_GRAPH_CURVE_NAME; // If necessary, this will be deconflicted below
298
299 } else {
300
301 curveNameNext = curveNameBefore; // This will be deconflicted below
302
303 if (endsWithNumber (curveNameBefore)) {
304
305 // Curve name ends with a number. Pick a name after curveNameBefore, being sure to not match curveNameAfter
306 int numberBefore = numberAtEnd (curveNameBefore);
307 int numberNew = numberBefore + 1;
308 int pos = curveNameBefore.lastIndexOf (QString::number (numberBefore));
309 if (pos >= 0) {
310
311 curveNameNext = QString ("%1%2")
312 .arg (curveNameBefore.left (pos))
313 .arg (numberNew);
314 if (curveNameNext == curveNameAfter) {
315
316 // The difference between before and after is exactly one so we go to a lower level
317 curveNameNext = QString ("%1%2")
318 .arg (curveNameBefore)
319 .arg (DASH_ONE);
320 }
321 }
322 }
323 }
324
325 // Curve name from settings takes precedence
326 SettingsForGraph settingsForGraph;
327 int indexOneBasedNext = numItems + 1;
328 curveNameNext = settingsForGraph.defaultCurveName (indexOneBasedNext,
329 curveNameNext);
330
331 // At this point we have curveNameNext which does not conflict with curveNameBefore or
332 // curveNameAfter, but it may in rare cases conflict with some other curve name. We keep
333 // adding to the name until there is no conflict
334 while (m_curveNameList->containsCurveNameCurrent (curveNameNext)) {
335 curveNameNext += DASH_ONE;
336 }
337
338 return curveNameNext;
339}
340
341int DlgSettingsCurveList::numberAtEnd (const QString &str) const
342{
343 ENGAUGE_ASSERT (endsWithNumber (str));
344
345 // Go backward until the first nondigit
346 int sign = +1;
347 int ch = str.size () - 1;
348 while (str.at (ch).digitValue() >= 0) {
349 --ch;
350
351 if (ch < 0) {
352 break;
353 }
354 }
355 ++ch;
356
357 return sign * str.mid (ch).toInt ();
358}
359
360unsigned int DlgSettingsCurveList::numPointsForSelectedCurves () const
361{
362 QList<unsigned int > rowsSelected;
363
364 // Create a list of curves that are currently selected
365 for (int i = 0; i < m_listCurves->selectionModel()->selectedIndexes ().count (); i++) {
366
367 int row = m_listCurves->selectionModel()->selectedIndexes ().at (i).row ();
368 rowsSelected << unsigned (row);
369 }
370
371 return m_curveNameList->numPointsForSelectedCurves (rowsSelected);
372}
373
374void DlgSettingsCurveList::printStream(QTextStream &str) const
375{
376 str << m_curveNameList->currentCurvesAsString();
377}
378
379void DlgSettingsCurveList::removeSelectedCurves ()
380{
381 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::removeSelectedCurves";
382
383 ENGAUGE_ASSERT (m_listCurves->selectionModel ()->selectedIndexes ().count () > 0); // Also guarantees number of indexes > 0
384
385 // Identify the first index after the last selected index
386 QString firstCurveAfter; // Empty case means there was no index afer the last selected index
387 for (int row = m_listCurves->model()->rowCount() - 1; row >= 0; row--) {
388
389 QModelIndex indexCurrent = m_listCurves->model()->index(row, CURVE_NAME_LIST_COLUMN_CURRENT);
390 if (indexCurrent == m_listCurves->selectionModel()->selectedIndexes().last()) {
391
392 // This is the last selected index, which will be removed below. Exit immediately with firstCurveAfter set
393 break;
394 }
395
396 firstCurveAfter = indexCurrent.data().toString();
397 }
398
399 // Delete the selected indexes from last to first
400 for (int i = m_listCurves->selectionModel ()->selectedIndexes ().count () - 1; i >= 0; i--) {
401
402 int row = m_listCurves->selectionModel ()->selectedIndexes ().at (i).row ();
403
404 m_curveNameList->removeRow (row);
405 }
406
407 if (firstCurveAfter.isEmpty ()) {
408
409 // Select the last remaining curve. These steps seem more complicated than necessary
410 int numItems = m_listCurves->model()->rowCount();
411 QModelIndex indexLast = m_listCurves->model()->index (numItems - 1, CURVE_NAME_LIST_COLUMN_CURRENT);
412 firstCurveAfter = m_listCurves->model()->data (indexLast).toString();
413
414 }
415
416 // Select an item
417 selectCurveName(firstCurveAfter);
418}
419
420void DlgSettingsCurveList::selectCurveName (const QString &curveWanted)
421{
422 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::selectCurveName"
423 << " curve=" << curveWanted.toLatin1().data();
424
425 for (int row = 0; row < m_listCurves->model()->rowCount(); row++) {
426
427 QModelIndex index = m_listCurves->model()->index (row, CURVE_NAME_LIST_COLUMN_CURRENT);
428 QString curveGot = index.data ().toString ();
429
430 if (curveWanted == curveGot) {
431
432 // Found the curve we want to select
433 m_listCurves->setCurrentIndex (index);
434 break;
435
436 }
437 }
438}
439
441{
442 if (!smallDialogs) {
443 setMinimumHeight (MINIMUM_HEIGHT);
444 }
445}
446
447void DlgSettingsCurveList::slotDataChanged (const QModelIndex &topLeft,
448 const QModelIndex &bottomRight,
449 const QVector<int> &roles)
450{
451 // LOG4CPP_INFO_S is below
452
453 // Since list just changed we dump all of it, including the visible and hidden data
454 QString curveEntries;
455 QTextStream str (&curveEntries);
456 printStream (str);
457
458 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::slotDataChanged"
459 << " topLeft=(" << topLeft.row () << "," << topLeft.column () << ")"
460 << " bottomRight=(" << bottomRight.row () << "," << bottomRight.column () << ")"
461 << " roles=" << rolesAsString (roles).toLatin1 ().data ()
462 << " defaultDragOption=" << (m_listCurves->defaultDropAction() == Qt::MoveAction ? "MoveAction" : "CopyAction")
463 << " curveEntries=(" << curveEntries.toLatin1().data() << ")";
464
465 updateControls ();
466}
467
468void DlgSettingsCurveList::slotNew ()
469{
470 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::slotNew";
471
472 const QString NO_ORIGINAL_CURVE_NAME;
473 const int NO_POINTS = 0;
474
475 QString curveNameSuggestion = nextCurveName ();
476
477 int row = newRowFromSelection();
478
479 insertCurveName (row,
480 curveNameSuggestion,
481 NO_ORIGINAL_CURVE_NAME,
482 NO_POINTS);
483
484 selectCurveName (curveNameSuggestion);
485
486 updateControls();
487}
488
489void DlgSettingsCurveList::slotRemove ()
490{
491 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::slotRemove";
492
493 // Count the number of curve points to be deleted
494 int numPoints = signed (numPointsForSelectedCurves ());
495
496 int rtn = QMessageBox::Ok;
497 if (numPoints > 0) {
498
499 QString msg;
500 if (m_listCurves->selectionModel ()->selectedIndexes ().count () == 1) {
501 msg = QString ("%1 %2 %3")
502 .arg (tr ("Removing this curve will also remove"))
503 .arg (numPoints)
504 .arg (tr ("points. Continue?"));
505 } else {
506 msg = QString ("%1 %2 %3")
507 .arg (tr ("Removing these curves will also remove"))
508 .arg (numPoints)
509 .arg (tr ("points. Continue?"));
510 }
511
512 rtn = QMessageBox::warning (nullptr,
513 tr ("Curves With Points"),
514 msg,
515 QMessageBox::Ok,
516 QMessageBox::Cancel);
517 }
518
519 if (rtn == QMessageBox::Ok) {
520 removeSelectedCurves ();
521 }
522
523 updateControls();
524}
525
526void DlgSettingsCurveList::slotResetDefault()
527{
528 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::slotResetDefault";
529
530 const QString REMOVE_ALL_SETTINGS_IN_GROUP; // Empty string
531
532 QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
533
534 int indexOneBased = 1;
535
536 SettingsForGraph settingsForGraph;
537 QString groupName = settingsForGraph.groupNameForNthCurve (indexOneBased);
538 while (settings.childGroups().contains (groupName)) {
539
540 settings.beginGroup (groupName);
541 settings.remove (REMOVE_ALL_SETTINGS_IN_GROUP); // Remove this group by removing its settings
542 settings.endGroup ();
543
544 ++indexOneBased;
545 groupName = settingsForGraph.groupNameForNthCurve (indexOneBased);
546 }
547}
548
550 int rowFirst,
551 int rowLast)
552{
553 LOG4CPP_DEBUG_S ((*mainCat)) << "DlgSettingsCurveList::slotRowsAboutToBeRemoved"
554 << " parentValid=" << (parent.isValid() ? "yes" : "no")
555 << " rowFirst=" << rowFirst
556 << " rowLast=" << rowLast;
557
558 updateControls ();
559}
560
561void DlgSettingsCurveList::slotSaveDefault()
562{
563 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::slotSaveDefault";
564
565 QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
566
567 for (int row = 0; row < m_curveNameList->rowCount (); row++) {
568
569 QModelIndex idxCurrent = m_curveNameList->index (row, 0);
570
571 QString curveNameCurrent = m_curveNameList->data (idxCurrent).toString ();
572
573 int indexOneBased = row + 1;
574
575 SettingsForGraph settingsForGraph;
576 QString groupName = settingsForGraph.groupNameForNthCurve (indexOneBased);
577
578 settings.beginGroup (groupName);
579 settings.setValue (SETTINGS_CURVE_NAME,
580 curveNameCurrent);
581 settings.endGroup ();
582 }
583}
584
586{
587 QWhatsThis::enterWhatsThisMode();
588}
589
590void DlgSettingsCurveList::updateControls ()
591{
592 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveList::updateControls";
593
594 enableOk (true);
595
596 ENGAUGE_CHECK_PTR (m_listCurves);
597
598 int numSelectedItems = m_listCurves->selectionModel ()->selectedIndexes ().count ();
599 int numItems = m_curveNameList->rowCount ();
600
601 // Leave at least one curve
602 m_btnRemove->setEnabled ((numSelectedItems > 0) && (numSelectedItems < numItems));
603}
@ CURVE_NAME_LIST_COLUMN_CURRENT
const QString DEFAULT_GRAPH_CURVE_NAME
const int MINIMUM_HEIGHT
#define ENGAUGE_ASSERT(cond)
Drop in replacement for Q_ASSERT.
#define ENGAUGE_CHECK_PTR(ptr)
Drop in replacement for Q_CHECK_PTR.
log4cpp::Category * mainCat
Definition Logger.cpp:14
QString rolesAsString(const QVector< int > &roles)
const QString SETTINGS_ENGAUGE
const QString SETTINGS_DIGITIZER
const QString SETTINGS_CURVE_NAME
Command queue stack.
Definition CmdMediator.h:24
Command for DlgSettingsCurveList.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
One row per curve name.
void insertRow(int row, const QString &curveCurrent, const QString &curveOriginal, unsigned int pointCount)
Create a new entry at the specified row.
DlgSettingsAbstractBase(const QString &title, const QString &dialogName, MainWindow &mainWindow)
Single constructor.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
void finishPanel(QWidget *subPanel, int minimumWidth=MINIMUM_DIALOG_WIDTH, int minimumHeightOrZero=0)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
void createWhatsThis(QGridLayout *layout, ButtonWhatsThis *button, int row, int column)
Create a WhatsThis button in a grid layout.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
MainWindow & mainWindow()
Get method for MainWindow.
DlgSettingsCurveList(MainWindow &mainWindow)
Single constructor.
void slotRowsAboutToBeRemoved(const QModelIndex &parent, int rowFirst, int rowLast)
Cleanup after rows have been removed in the model. We remove the corresponding rows in the QListView.
virtual void handleOk()
Process slotOk.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
void load(CmdMediator &cmdMediator)
Load settings from Document.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition MainWindow.h:95
Manage storage and retrieval of the settings for the curves.
QString groupNameForNthCurve(int indexOneBased) const
Return the group name, that appears in the settings file/registry, for the specified curve index.
QString defaultCurveName(int indexOneBased, const QString &defaultName) const
Default graph name for the specified curve index.
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18
#define LOG4CPP_DEBUG_S(logger)
Definition convenience.h:20