Engauge Digitizer 2
Loading...
Searching...
No Matches
DlgSettingsCurveAddRemove.cpp
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 "CmdMediator.h"
8#include "CmdSettingsCurveAddRemove.h"
9#include "CurveNameList.h"
10#include "DlgSettingsCurveAddRemove.h"
11#include "EngaugeAssert.h"
12#include "Logger.h"
13#include "MainWindow.h"
14#include <QCheckBox>
15#include <QDebug>
16#include <QGridLayout>
17#include <QLabel>
18#include <QListView>
19#include <QMessageBox>
20#include <QPushButton>
21#include <QSettings>
22#include <QSpacerItem>
23#include "QtToString.h"
24#include "Settings.h"
25#include "SettingsForGraph.h"
26
28 DlgSettingsAbstractBase (tr ("Curve Add/Remove"),
29 "DlgSettingsCurveAddRemove",
30 mainWindow)
31{
32 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::DlgSettingsCurveAddRemove";
33
34 QWidget *subPanel = createSubPanel ();
35 finishPanel (subPanel);
36}
37
38DlgSettingsCurveAddRemove::~DlgSettingsCurveAddRemove()
39{
40 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::~DlgSettingsCurveAddRemove";
41}
42
43void DlgSettingsCurveAddRemove::appendCurveName (const QString &curveNameNew,
44 const QString &curveNameOriginal,
45 int numPoints)
46{
47 ENGAUGE_CHECK_PTR (m_curveNameList);
48
49 int row = m_curveNameList->rowCount ();
50 insertCurveName (row,
51 curveNameNew,
52 curveNameOriginal,
53 numPoints);
54}
55
56void DlgSettingsCurveAddRemove::createButtons (QGridLayout *layout,
57 int &row)
58{
59 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::createButtons";
60
61 m_btnAdd = new QPushButton (tr ("Add..."));
62 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"
63 "Every curve name must be unique"));
64 m_btnAdd->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
65 connect (m_btnAdd, SIGNAL (released ()), this, SLOT (slotNew()));
66 layout->addWidget (m_btnAdd, row, 1, 1, 1, Qt::AlignLeft);
67
68 m_btnRemove = new QPushButton (tr ("Remove"));
69 m_btnRemove->setWhatsThis (tr ("Removes the currently selected curve from the curve list.\n\n"
70 "There must always be at least one curve"));
71 m_btnRemove->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
72 connect (m_btnRemove, SIGNAL (released ()), this, SLOT (slotRemove()));
73 layout->addWidget (m_btnRemove, row++, 2, 1, 1, Qt::AlignRight);
74}
75
76void DlgSettingsCurveAddRemove::createListCurves (QGridLayout *layout,
77 int &row)
78{
79 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::createListCurves";
80
81 QLabel *label = new QLabel (tr ("Curve Names:"));
82 layout->addWidget (label, row++, 1);
83
84 m_curveNameList = new CurveNameList;
85
86 // There is no Qt::ItemIsEditable flag for QListView, so instead we set that flag for the QListViewItems
87 m_listCurves = new QListView;
88 m_listCurves->setWhatsThis (tr ("List of the curves belonging to this document.\n\n"
89 "Click on a curve name to edit it. Each curve name must be unique.\n\n"
90 "Reorder curves by dragging them around."));
91 m_listCurves->setMinimumHeight (200);
92 m_listCurves->setSelectionMode (QAbstractItemView::ExtendedSelection);
93 m_listCurves->setDefaultDropAction (Qt::MoveAction);
94 m_listCurves->setDragDropOverwriteMode (true);
95 m_listCurves->setDragEnabled (true);
96 m_listCurves->setDropIndicatorShown (true);
97 m_listCurves->setDragDropMode (QAbstractItemView::InternalMove);
98 m_listCurves->setViewMode (QListView::ListMode);
99 m_listCurves->setMovement (QListView::Snap);
100 m_listCurves->setModel (m_curveNameList);
101 layout->addWidget (m_listCurves, row++, 1, 1, 2);
102 connect (m_curveNameList, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex &, const QVector<int> &)),
103 this, SLOT (slotDataChanged (const QModelIndex &, const QModelIndex &, const QVector<int> &)));
104 connect (m_listCurves->selectionModel (), SIGNAL (selectionChanged (QItemSelection, QItemSelection)),
105 this, SLOT (slotSelectionChanged (QItemSelection, QItemSelection)));
106}
107
109{
110 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::createOptionalSaveDefault";
111
112 m_btnSaveDefault = new QPushButton (tr ("Save As Default"));
113 m_btnSaveDefault->setWhatsThis (tr ("Save the curve names for use as defaults for future graph curves."));
114 connect (m_btnSaveDefault, SIGNAL (released ()), this, SLOT (slotSaveDefault ()));
115 layout->addWidget (m_btnSaveDefault, 0, Qt::AlignLeft);
116
117 QSpacerItem *spacer = new QSpacerItem (40, 2);
118 layout->addItem (spacer);
119}
120
122{
123 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::createSubPanel";
124
125 const int EMPTY_COLUMN_WIDTH = 30;
126
127 QWidget *subPanel = new QWidget ();
128 QGridLayout *layout = new QGridLayout (subPanel);
129 subPanel->setLayout (layout);
130
131 int row = 1;
132 createListCurves (layout, row);
133 createButtons (layout, row);
134
135 layout->setColumnStretch (0, 0); // Empty first column
136 layout->setColumnMinimumWidth (0, EMPTY_COLUMN_WIDTH);
137 layout->setColumnStretch (1, 1); // New
138 layout->setColumnStretch (2, 1); // Remove
139 layout->setColumnStretch (3, 0); // Empty last column
140 layout->setColumnMinimumWidth (3, EMPTY_COLUMN_WIDTH);
141
142 return subPanel;
143}
144
145bool DlgSettingsCurveAddRemove::endsWithNumber (const QString &str) const
146{
147 bool success = false;
148
149 if (!str.isEmpty ()) {
150
151 success = (str.right (1).at (0).digitValue() >= 0);
152 }
153
154 return success;
155}
156
158{
159 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::handleOk";
160
162 cmdMediator ().document(),
163 *m_curveNameList);
164 cmdMediator ().push (cmd);
165
166 hide ();
167}
168
169void DlgSettingsCurveAddRemove::insertCurveName (int row,
170 const QString &curveNameNew,
171 const QString &curveNameOriginal,
172 int numPoints)
173{
174 if (m_curveNameList->insertRow (row)) {
175
176 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::insertCurveName curveName=" << curveNameNew.toLatin1 ().data ();
177
178 CurveNameListEntry curvesEntry (curveNameNew,
179 curveNameOriginal,
180 numPoints);
181
182 m_curveNameList->setData (m_curveNameList->index (row, 0),
183 curvesEntry.curveNameCurrent ());
184 m_curveNameList->setData (m_curveNameList->index (row, 1),
185 curvesEntry.curveNameOriginal ());
186 m_curveNameList->setData (m_curveNameList->index (row, 2),
187 numPoints);
188
189 } else {
190
191 LOG4CPP_ERROR_S ((*mainCat)) << "DlgSettingsCurveAddRemove::insertCurveName failed curveName="
192 << curveNameNew.toLatin1 ().data ();
193
194 }
195}
196
198{
199 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::load";
200
202
203 // Remove any data from previous showing of dialog
204 while (m_curveNameList->rowCount () > 0) {
205 m_curveNameList->removeRow (0);
206 }
207
208 QStringList curveNames = cmdMediator.curvesGraphsNames ();
209 QStringList::const_iterator itr;
210 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
211 QString curveName = *itr;
212 appendCurveName (curveName,
213 curveName,
215 }
216
217 enableOk (false); // Disable Ok button since there not yet any changes
218}
219
220QString DlgSettingsCurveAddRemove::nextCurveName () const
221{
222 const QString DASH_ONE ("-1"); // Nice value to start a new range at a lower level than the current level
223
224 ENGAUGE_CHECK_PTR (m_listCurves);
225
226 int numSelectedItems = m_listCurves->selectionModel ()->selectedIndexes ().count ();
227 int numItems = m_listCurves->model ()->rowCount ();
228
229 // Determine index where new entry will be inserted
230 int currentIndex = -1;
231 if ((numSelectedItems == 0) &&
232 (numItems > 0)) {
233
234 // Append after list which has at least one entry
235 currentIndex = numItems;
236
237 } else if (numSelectedItems == 1) {
238
239 // Insert before the selected index
240 currentIndex = m_listCurves->selectionModel ()->selectedIndexes ().at (0).row ();
241
242 }
243
244 // Curves names of existing before/after curves
245 QString curveNameBefore, curveNameAfter;
246 if (currentIndex > 0) {
247
248 QModelIndex index = m_curveNameList->index (currentIndex - 1, 0);
249 curveNameBefore = m_curveNameList->data (index).toString ();
250
251 }
252
253 if ((0 <= currentIndex) && (currentIndex < numItems)) {
254
255 QModelIndex index = m_curveNameList->index (currentIndex, 0);
256 curveNameAfter = m_curveNameList->data (index).toString ();
257
258 }
259
260 // New curve name computed from previous curve name
261 QString curveNameNext;
262 if (curveNameBefore.isEmpty () && !curveNameAfter.isEmpty () && endsWithNumber (curveNameAfter)) {
263
264 // Pick a name before curveNameAfter
265 int numberAfter = numberAtEnd (curveNameAfter);
266 int numberNew = numberAfter - 1;
267 int pos = curveNameAfter.lastIndexOf (QString::number (numberAfter));
268 if (pos >= 0) {
269
270 curveNameNext = QString ("%1%2")
271 .arg (curveNameAfter.left (pos))
272 .arg (numberNew);
273
274 } else {
275
276 curveNameNext = curveNameAfter; // Better than nothing
277
278 }
279
280 } else if (curveNameBefore.isEmpty ()) {
281
282 curveNameNext = DEFAULT_GRAPH_CURVE_NAME; // If necessary, this will be deconflicted below
283
284 } else {
285
286 curveNameNext = curveNameBefore; // This will be deconflicted below
287
288 if (endsWithNumber (curveNameBefore)) {
289
290 // Curve name ends with a number. Pick a name after curveNameBefore, being sure to not match curveNameAfter
291 int numberBefore = numberAtEnd (curveNameBefore);
292 int numberNew = numberBefore + 1;
293 int pos = curveNameBefore.lastIndexOf (QString::number (numberBefore));
294 if (pos >= 0) {
295
296 curveNameNext = QString ("%1%2")
297 .arg (curveNameBefore.left (pos))
298 .arg (numberNew);
299 if (curveNameNext == curveNameAfter) {
300
301 // The difference between before and after is exactly one so we go to a lower level
302 curveNameNext = QString ("%1%2")
303 .arg (curveNameBefore)
304 .arg (DASH_ONE);
305 }
306 }
307 }
308 }
309
310 // Curve name from settings takes precedence
311 SettingsForGraph settingsForGraph;
312 int indexOneBasedNext = numItems + 1;
313 curveNameNext = settingsForGraph.defaultCurveName (indexOneBasedNext,
314 curveNameNext);
315
316 // At this point we have curveNameNext which does not conflict with curveNameBefore or
317 // curveNameAfter, but it may in rare cases conflict with some other curve name. We keep
318 // adding to the name until there is no conflict
319 while (m_curveNameList->containsCurveNameCurrent (curveNameNext)) {
320 curveNameNext += DASH_ONE;
321 }
322
323 return curveNameNext;
324}
325
326int DlgSettingsCurveAddRemove::numberAtEnd (const QString &str) const
327{
328 ENGAUGE_ASSERT (endsWithNumber (str));
329
330 // Go backward until the first nondigit
331 int sign = +1;
332 int ch = str.size () - 1;
333 while (str.at (ch).digitValue() >= 0) {
334 --ch;
335
336 if (ch < 0) {
337 break;
338 }
339 }
340 ++ch;
341
342 return sign * str.mid (ch).toInt ();
343}
344
345void DlgSettingsCurveAddRemove::removeSelectedCurves ()
346{
347 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::removeSelectedCurves";
348
349 for (int i = m_listCurves->selectionModel ()->selectedIndexes ().count () - 1; i >= 0; i--) {
350
351 int row = m_listCurves->selectionModel ()->selectedIndexes ().at (i).row ();
352
353 m_curveNameList->removeRow (row);
354 }
355}
356
357void DlgSettingsCurveAddRemove::slotDataChanged (const QModelIndex &topLeft,
358 const QModelIndex &bottomRight,
359 const QVector<int> &roles)
360{
361 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::slotDataChanged"
362 << " topLeft=(" << topLeft.row () << "," << topLeft.column () << ")"
363 << " bottomRight=(" << bottomRight.row () << "," << bottomRight.column () << ")"
364 << " roles=" << rolesAsString (roles).toLatin1 ().data ();
365
366 updateControls ();
367}
368
369void DlgSettingsCurveAddRemove::slotNew ()
370{
371 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::slotNew";
372
373 const QString NO_ORIGINAL_CURVE_NAME;
374 const int NO_POINTS = 0;
375
376 QString curveNameSuggestion = nextCurveName ();
377
378 appendCurveName (curveNameSuggestion,
379 NO_ORIGINAL_CURVE_NAME,
380 NO_POINTS);
381
382 updateControls();
383}
384
385void DlgSettingsCurveAddRemove::slotRemove ()
386{
387 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::slotRemove";
388
389 int numPoints = 0;
390 for (int i = 0; i < m_listCurves->selectionModel ()->selectedIndexes ().count (); i++) {
391
392 int row = m_listCurves->selectionModel ()->selectedIndexes ().at (i).row ();
393 QModelIndex idx = m_curveNameList->index (row, CurveNameListEntry::COL_NUM_POINTS ());
394 int curvePoints = m_curveNameList->data (idx, Qt::DisplayRole).toInt ();
395
396 numPoints += curvePoints;
397 }
398
399 int rtn = QMessageBox::Ok;
400 if (numPoints > 0) {
401
402 QString msg;
403 if (m_listCurves->selectionModel ()->selectedIndexes ().count () == 1) {
404 msg = QString ("%1 %2 %3")
405 .arg (tr ("Removing this curve will also remove"))
406 .arg (numPoints)
407 .arg (tr ("points. Continue?"));
408 } else {
409 msg = QString ("%1 %2 %3")
410 .arg (tr ("Removing these curves will also remove"))
411 .arg (numPoints)
412 .arg (tr ("points. Continue?"));
413 }
414
415 rtn = QMessageBox::warning (0,
416 tr ("Curves With Points"),
417 msg,
418 QMessageBox::Ok,
419 QMessageBox::Cancel);
420 }
421
422 if (rtn == QMessageBox::Ok) {
423 removeSelectedCurves ();
424 }
425
426 updateControls();
427}
428
429void DlgSettingsCurveAddRemove::slotSaveDefault()
430{
431 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::slotSaveDefault";
432
433 QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
434
435 for (int row = 0; row < m_curveNameList->rowCount (); row++) {
436
437 QModelIndex idxCurrent = m_curveNameList->index (row, 0);
438
439 QString curveNameCurrent = m_curveNameList->data (idxCurrent).toString ();
440
441 int indexOneBased = row + 1;
442
443 SettingsForGraph settingsForGraph;
444 QString groupName = settingsForGraph.groupNameForNthCurve (indexOneBased);
445
446 settings.beginGroup (groupName);
447 settings.setValue (SETTINGS_CURVE_NAME,
448 curveNameCurrent);
449 settings.endGroup ();
450 }
451}
452
453void DlgSettingsCurveAddRemove::slotSelectionChanged (QItemSelection, QItemSelection)
454{
455 updateControls ();
456}
457
458void DlgSettingsCurveAddRemove::updateControls ()
459{
460 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCurveAddRemove::updateControls";
461
462 enableOk (true);
463
464 ENGAUGE_CHECK_PTR (m_listCurves);
465
466 int numSelectedItems = m_listCurves->selectionModel ()->selectedIndexes ().count ();
467 int numItems = m_curveNameList->rowCount ();
468
469 // Leave at least one curve
470 m_btnRemove->setEnabled ((numSelectedItems > 0) && (numSelectedItems < numItems));
471}
Command queue stack.
Definition CmdMediator.h:24
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
int curvesGraphsNumPoints(const QString &curveName) const
See CurvesGraphs::curvesGraphsNumPoints.
Command for DlgSettingsCurveAddRemove.
Utility class for converting the QVariant in CurveNameList to/from the curve names as QStrings,...
static int COL_NUM_POINTS()
Get method for number of points constant.
Model for DlgSettingsCurveAddRemove and CmdSettingsCurveAddRemove.
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Retrieve data from model.
bool containsCurveNameCurrent(const QString &curveName) const
Return true if specified curve name is already in the list.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
One row per curve name.
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
Store one curve name data.
Abstract base class for all Settings dialogs.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
void finishPanel(QWidget *subPanel)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
MainWindow & mainWindow()
Get method for MainWindow.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
DlgSettingsCurveAddRemove(MainWindow &mainWindow)
Single constructor.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
virtual void handleOk()
Process slotOk.
void load(CmdMediator &cmdMediator)
Load settings from Document.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition MainWindow.h:78
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.