Engauge Digitizer 2
Loading...
Searching...
No Matches
DlgEditPointGraph.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2016 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 "DlgEditPointGraph.h"
10#include "DlgValidatorFactory.h"
11#include "DocumentModelCoords.h"
13#include "FormatCoordsUnits.h"
14#include "Logger.h"
15#include "MainWindow.h"
16#include "MainWindowModel.h"
17#include <QGroupBox>
18#include <QLabel>
19#include <QPushButton>
20#include "QtToString.h"
21#include <QVBoxLayout>
22#include "Transformation.h"
23
24const Qt::Alignment ALIGNMENT = Qt::AlignCenter;
25
27
29 const DocumentModelCoords &modelCoords,
30 const DocumentModelGeneral &modelGeneral,
31 const MainWindowModel &modelMainWindow,
32 const Transformation &transformation,
33 const double *xInitialValue,
34 const double *yInitialValue) :
35 QDialog (&mainWindow),
36 m_changed (false),
37 m_modelCoords (modelCoords),
38 m_modelGeneral (modelGeneral),
39 m_modelMainWindow (modelMainWindow)
40{
41 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointGraph::DlgEditPointGraph";
42
43 QVBoxLayout *layout = new QVBoxLayout;
44 setLayout (layout);
45
46 setCursor (QCursor (Qt::ArrowCursor));
47 setModal(true);
48 setWindowTitle (tr ("Edit Curve Point(s)"));
49
50 createCoords (layout);
51 createHint (layout);
52 createOkCancel (layout);
53
54 initializeGraphCoordinates (xInitialValue,
55 yInitialValue,
56 transformation);
57
58 m_changed = false; // Initialization of coordinate vaues changed this flag so we reset it and update the controls
59 updateControls ();
60}
61
63{
64 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointGraph::~DlgEditPointGraph";
65}
66
67void DlgEditPointGraph::createCoords (QVBoxLayout *layoutOuter)
68{
69 // Constraints on x and y are needed for log scaling
70 bool isConstraintX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG);
71 bool isConstraintY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG);
72 DlgValidatorFactory dlgValidatorFactory;
73 m_validatorGraphX = dlgValidatorFactory.createCartesianOrPolarWithPolarPolar (m_modelCoords.coordScaleXTheta(),
74 isCartesian (),
75 m_modelCoords.coordUnitsX(),
76 m_modelCoords.coordUnitsTheta(),
77 m_modelCoords.coordUnitsDate(),
78 m_modelCoords.coordUnitsTime(),
79 m_modelMainWindow.locale());
80 m_validatorGraphY = dlgValidatorFactory.createCartesianOrPolarWithNonPolarPolar (m_modelCoords.coordScaleYRadius(),
81 isCartesian (),
82 m_modelCoords.coordUnitsY(),
83 m_modelCoords.coordUnitsRadius(),
84 m_modelCoords.coordUnitsDate(),
85 m_modelCoords.coordUnitsTime(),
86 m_modelMainWindow.locale());
87
88 // Label, with guidance in terms of legal ranges and units
89 QString description = QString ("%1 (%2, %3)%4%5%6%7%8%9 %10:")
90 .arg (tr ("Graph Coordinates"))
91 .arg (nameXTheta ())
92 .arg (nameYRadius ())
93 .arg (isConstraintX || isConstraintY ? " with " : "")
94 .arg (isConstraintX ? QString (nameXTheta ()) : "")
95 .arg (isConstraintX ? " > 0" : "")
96 .arg (isConstraintX && isConstraintY ? " and " : "")
97 .arg ( isConstraintY ? QString (nameYRadius ()) : "")
98 .arg ( isConstraintY ? " > 0" : "")
99 .arg (tr ("as"));
100 QGroupBox *panel = new QGroupBox (description, this);
101 layoutOuter->addWidget (panel);
102
103 QHBoxLayout *layout = new QHBoxLayout (panel);
104 panel->setLayout (layout);
105
106 // Row
107 QLabel *labelGraphParLeft = new QLabel (tr ("("), this);
108 layout->addWidget(labelGraphParLeft, 0);
109
110 m_editGraphX = new DlgEditPointGraphLineEdit;
111 m_editGraphX->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
112 m_editGraphX->setAlignment (ALIGNMENT);
113 m_editGraphX->setValidator (m_validatorGraphX);
114 // setStatusTip does not work for modal dialogs
115 m_editGraphX->setWhatsThis (tr ("Enter the first graph coordinate value to be applied to the graph points.\n\n"
116 "Leave this field empty if no value is to be applied to the graph points.\n\n"
117 "For cartesian plots this is the X coordinate. For polar plots this is the radius R.\n\n"
118 "The expected format of the coordinate value is determined by the locale setting. If "
119 "typed values are not recognized as expected, check the locale setting in Settings / Main Window..."));
120 layout->addWidget(m_editGraphX, 0);
121 connect (m_editGraphX, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
122
123 QLabel *labelGraphComma = new QLabel (tr (", "), this);
124 layout->addWidget(labelGraphComma, 0);
125
126 m_editGraphY = new DlgEditPointGraphLineEdit;
127 m_editGraphY->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
128 m_editGraphY->setAlignment (ALIGNMENT);
129 m_editGraphY->setValidator (m_validatorGraphY);
130 // setStatusTip does not work for modal dialogs
131 m_editGraphY->setWhatsThis (tr ("Enter the second graph coordinate value to be applied to the graph points.\n\n"
132 "Leave this field empty if no value is to be applied to the graph points.\n\n"
133 "For cartesian plots this is the Y coordinate. For polar plots this is the angle Theta.\n\n"
134 "The expected format of the coordinate value is determined by the locale setting. If "
135 "typed values are not recognized as expected, check the locale setting in Settings / Main Window..."));
136 layout->addWidget(m_editGraphY, 0);
137 connect (m_editGraphY, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
138
139 QLabel *labelGraphParRight = new QLabel (tr (")"), this);
140 layout->addWidget(labelGraphParRight, 0);
141}
142
143void DlgEditPointGraph::createHint (QVBoxLayout *layoutOuter)
144{
145 // Insert a hint explaining why decimal points may not be accepted. Very confusing for user to figure out the problem at first, and
146 // then figure out which setting should change to fix it. The hint is centered so it is slightly less intrusive
147
148 QWidget *widget = new QWidget;
149 layoutOuter->addWidget (widget, 0, Qt::AlignCenter);
150
151 QHBoxLayout *layout = new QHBoxLayout;
152 widget->setLayout (layout);
153
154 QString locale = QLocaleToString (m_modelMainWindow.locale ());
155 QString hint = QString ("%1: %2")
156 .arg (tr ("Number format"))
157 .arg (locale);
158 QLabel *label = new QLabel (hint);
159 layout->addWidget (label);
160}
161
162void DlgEditPointGraph::createOkCancel (QVBoxLayout *layoutOuter)
163{
164 QWidget *panel = new QWidget (this);
165 layoutOuter->addWidget (panel, 0, Qt::AlignCenter);
166
167 QHBoxLayout *layout = new QHBoxLayout (panel);
168 panel->setLayout (layout);
169
170 m_btnOk = new QPushButton (tr ("Ok"), this);
171 layout->addWidget(m_btnOk);
172 connect (m_btnOk, SIGNAL (released ()), this, SLOT (accept ()));
173
174 m_btnCancel = new QPushButton (tr ("Cancel"), this);
175 layout->addWidget(m_btnCancel);
176 connect (m_btnCancel, SIGNAL (released ()), this, SLOT (reject ()));
177}
178
179void DlgEditPointGraph::initializeGraphCoordinates (const double *xInitialValue,
180 const double *yInitialValue,
181 const Transformation &transformation)
182{
183 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointGraph::initializeGraphCoordinates";
184
185 QString xTheta, yRadius;
186 if ((xInitialValue != nullptr) &&
187 (yInitialValue != nullptr)) {
188
189 FormatCoordsUnits format;
190 format.unformattedToFormatted (*xInitialValue,
191 *yInitialValue,
192 m_modelCoords,
193 m_modelGeneral,
194 m_modelMainWindow,
195 xTheta,
196 yRadius,
197 transformation);
198 }
199
200 m_editGraphX->setText (xTheta);
201 m_editGraphY->setText (yRadius);
202}
203
204bool DlgEditPointGraph::isCartesian () const
205{
206 return (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN);
207}
208
209QChar DlgEditPointGraph::nameXTheta () const
210{
211 return (isCartesian () ? QChar ('X') : THETA);
212}
213
214QChar DlgEditPointGraph::nameYRadius () const
215{
216 return (isCartesian () ? QChar ('Y') : QChar ('R'));
217}
218
220 double &x,
221 bool &isY,
222 double &y) const
223{
224 FormatCoordsUnits format;
225
226 // Use zero for any empty coordinate
227 QString xTextNotEmpty = QString ("%1").arg (m_editGraphX->text().isEmpty () ? "0" : m_editGraphX->text());
228 QString yTextNotEmpty = QString ("%1").arg (m_editGraphY->text().isEmpty () ? "0" : m_editGraphY->text());
229
230 format.formattedToUnformatted (xTextNotEmpty,
231 yTextNotEmpty,
232 m_modelCoords,
233 m_modelMainWindow,
234 x,
235 y);
236
237 isX = !m_editGraphX->text().isEmpty();
238 isY = !m_editGraphY->text().isEmpty();
239}
240
241void DlgEditPointGraph::slotTextChanged (const QString &)
242{
243 m_changed = true;
244 updateControls ();
245}
246
247QString DlgEditPointGraph::unitsType (bool isXTheta) const
248{
249 if (isCartesian ()) {
250 if (isXTheta) {
251 return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsX());
252 } else {
253 return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsY());
254 }
255 } else {
256 if (isXTheta) {
257 return coordUnitsPolarThetaToBriefType (m_modelCoords.coordUnitsTheta());
258 } else {
260 }
261 }
262}
263
264void DlgEditPointGraph::updateControls ()
265{
266 QString textX = m_editGraphX->text();
267 QString textY = m_editGraphY->text();
268
269 // Feedback indicating that empty coordinate will be skipped rather than applied to the selected points
270 m_editGraphX->updateBackground ();
271 m_editGraphY->updateBackground ();
272
273 // Tests that all have to be true
274 // 1) At least one value has been changed
275 // 2) At least one value is not empty
276 // 3) The values that are not empty are properly formatted. This is done remembering that we need to
277 // check for not empty (which allows single minus sign) and for valid number (which prevents single
278 // minus sign)
279 bool test2 = (!textX.isEmpty() || !textY.isEmpty());
280
281 int posX, posY;
282 bool test3 = true;
283 if (!textX.isEmpty()) {
284 test3 &= (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable);
285 }
286 if (!textY.isEmpty()) {
287 test3 &= (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable);
288 }
289
290 m_btnOk->setEnabled (m_changed && test2 && test3);
291}
@ COORD_SCALE_LOG
Definition CoordScale.h:14
const QChar THETA
QString coordUnitsNonPolarThetaToBriefType(CoordUnitsNonPolarTheta coordUnits)
QString coordUnitsPolarThetaToBriefType(CoordUnitsPolarTheta coordUnits)
@ COORDS_TYPE_CARTESIAN
Definition CoordsType.h:13
const Qt::Alignment ALIGNMENT
const int MIN_WIDTH_TO_FIT_STRANGE_UNITS
const Qt::Alignment ALIGNMENT
const int MIN_WIDTH_TO_FIT_STRANGE_UNITS
log4cpp::Category * mainCat
Definition Logger.cpp:14
QString QLocaleToString(const QLocale &locale)
Adds hover highlighting to QLineEdit.
void updateBackground()
Update background given the current state.
void posGraph(bool &isX, double &x, bool &isY, double &y) const
Return one or both coordinates. Only applies if dialog was accepted.
DlgEditPointGraph(MainWindow &mainWindow, const DocumentModelCoords &modelCoords, const DocumentModelGeneral &modelGeneral, const MainWindowModel &modelMainWindow, const Transformation &transformation, const double *xInitialValue=0, const double *yInitialValue=0)
Constructor for existing point which already has graph coordinates (which may be changed using this d...
virtual QValidator::State validate(QString &input, int &pos) const =0
Validate according to the numeric format specific to the leaf class.
Validator factory.
DlgValidatorAbstract * createCartesianOrPolarWithPolarPolar(CoordScale coordScale, bool isCartesian, CoordUnitsNonPolarTheta coordUnitsCartesian, CoordUnitsPolarTheta coordUnitsPolar, CoordUnitsDate coordUnitsDate, CoordUnitsTime coordUnitsTime, const QLocale &locale) const
Factory method for generating validators for either cartesian or polar case, when polar format is spe...
DlgValidatorAbstract * createCartesianOrPolarWithNonPolarPolar(CoordScale coordScale, bool isCartesian, CoordUnitsNonPolarTheta coordUnitsCartesian, CoordUnitsNonPolarTheta coordUnitsPolar, CoordUnitsDate coordUnitsDate, CoordUnitsTime coordUnitsTime, const QLocale &locale) const
Factory method for generating validators for either cartesian or polar case, when polar format is spe...
Model for DlgSettingsCoords and CmdSettingsCoords.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
CoordUnitsNonPolarTheta coordUnitsRadius() const
Get method for radius units.
CoordUnitsPolarTheta coordUnitsTheta() const
Get method for theta unit.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
CoordUnitsNonPolarTheta coordUnitsY() const
Get method for x units.
CoordUnitsTime coordUnitsTime() const
Get method for time format when used.
CoordUnitsNonPolarTheta coordUnitsX() const
Get method for x units.
CoordsType coordsType() const
Get method for coordinates type.
CoordUnitsDate coordUnitsDate() const
Get method for date format when used.
Model for DlgSettingsGeneral and CmdSettingsGeneral.
Highest-level wrapper around other Formats classes.
void formattedToUnformatted(const QString &xThetaFormatted, const QString &yRadiusFormatted, const DocumentModelCoords &modelCoords, const MainWindowModel &mainWindowModel, double &xThetaUnformatted, double &yRadiusUnformatted) const
Convert formatted string to unformatted numeric value.
void unformattedToFormatted(double xThetaUnformatted, double yRadiusUnformatted, const DocumentModelCoords &modelCoords, const DocumentModelGeneral &modelGeneral, const MainWindowModel &mainWindowModel, QString &xThetaFormatted, QString &yRadiusFormatted, const Transformation &transformation) const
Convert unformatted numeric value to formatted string. Transformation is used to determine best resol...
Model for DlgSettingsMainWindow.
QLocale locale() const
Get method for locale.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition MainWindow.h:92
Affine transformation between screen and graph coordinates, based on digitized axis points.
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18