Engauge Digitizer 2
Loading...
Searching...
No Matches
DlgEditPoint.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 "DigitizeStateAbstractBase.h"
8#include "DlgEditPoint.h"
9#include "DlgValidatorAbstract.h"
10#include "DlgValidatorFactory.h"
11#include "DocumentAxesPointsRequired.h"
12#include "DocumentModelCoords.h"
13#include "EngaugeAssert.h"
14#include "FormatCoordsUnits.h"
15#include "FormatDateTime.h"
16#include "FormatDegreesMinutesSecondsNonPolarTheta.h"
17#include "FormatDegreesMinutesSecondsPolarTheta.h"
18#include "Logger.h"
19#include "MainWindow.h"
20#include "MainWindowModel.h"
21#include <QDoubleValidator>
22#include <QGridLayout>
23#include <QGroupBox>
24#include <QHBoxLayout>
25#include <QLabel>
26#include <QRect>
27#include <QVBoxLayout>
28#include "Transformation.h"
29
30const Qt::Alignment ALIGNMENT = Qt::AlignCenter;
31
32const int MIN_WIDTH_TO_FIT_STRANGE_UNITS = 200;
33
34const bool IS_X_THETA = true;
35const bool IS_NOT_X_THETA = false;
36
38 DigitizeStateAbstractBase &digitizeState,
39 const DocumentModelCoords &modelCoords,
40 const MainWindowModel &modelMainWindow,
41 const QCursor &cursorShape,
42 const Transformation &transformation,
43 DocumentAxesPointsRequired documentAxesPointsRequired,
44 bool isXOnly,
45 const double *xInitialValue,
46 const double *yInitialValue) :
47 QDialog (&mainWindow),
48 m_cursorShape (cursorShape),
49 m_documentAxesPointsRequired (documentAxesPointsRequired),
50 m_modelCoords (modelCoords),
51 m_modelMainWindow (modelMainWindow)
52{
53 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::DlgEditPoint";
54
55 // Either one or two coordinates are desired
56 bool isX = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) || isXOnly;
57 bool isY = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) || !isXOnly;
58
59 // To guarantee the override cursor is always removed, we call removeOverrideCursor here rather than in the code that
60 // allocates this DlgEditPoint. The digitizeState argument is otherwise unused.
61 digitizeState.removeOverrideCursor();
62
63 connect (this, SIGNAL (signalSetOverrideCursor (QCursor)), &mainWindow, SLOT (slotSetOverrideCursor (QCursor)));
64
65 QVBoxLayout *layout = new QVBoxLayout;
66 setLayout (layout);
67
68 setCursor (QCursor (Qt::ArrowCursor));
69 setModal(true);
70 setWindowTitle (tr ("Edit Axis Point"));
71
72 createCoords (layout);
73 createOkCancel (layout);
74
75 initializeGraphCoordinates (xInitialValue,
76 yInitialValue,
77 transformation,
78 isX,
79 isY);
80
81 updateControls ();
82}
83
84DlgEditPoint::~DlgEditPoint()
85{
86 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::~DlgEditPoint";
87
88 emit signalSetOverrideCursor (m_cursorShape);
89}
90
91void DlgEditPoint::createCoords (QVBoxLayout *layoutOuter)
92{
93 // Constraints on x and y are needed for log scaling
94 bool isConstraintX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG);
95 bool isConstraintY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG);
96 DlgValidatorFactory dlgValidatorFactory;
97 m_validatorGraphX = dlgValidatorFactory.createCartesianOrPolarWithPolarPolar (m_modelCoords.coordScaleXTheta(),
98 isCartesian (),
99 m_modelCoords.coordUnitsX(),
100 m_modelCoords.coordUnitsTheta(),
101 m_modelCoords.coordUnitsDate(),
102 m_modelCoords.coordUnitsTime(),
103 m_modelMainWindow.locale());
104 m_validatorGraphY = dlgValidatorFactory.createCartesianOrPolarWithNonPolarPolar (m_modelCoords.coordScaleYRadius(),
105 isCartesian (),
106 m_modelCoords.coordUnitsY(),
107 m_modelCoords.coordUnitsRadius(),
108 m_modelCoords.coordUnitsDate(),
109 m_modelCoords.coordUnitsTime(),
110 m_modelMainWindow.locale());
111
112 // Label, with guidance in terms of legal ranges and units
113 QString description = QString ("%1 (%2, %3)%4%5%6%7%8%9 %10 (%11, %12):")
114 .arg (tr ("Graph Coordinates"))
115 .arg (nameXTheta ())
116 .arg (nameYRadius ())
117 .arg (isConstraintX || isConstraintY ? " with " : "")
118 .arg (isConstraintX ? QString (nameXTheta ()) : "")
119 .arg (isConstraintX ? " > 0" : "")
120 .arg (isConstraintX && isConstraintY ? " and " : "")
121 .arg ( isConstraintY ? QString (nameYRadius ()) : "")
122 .arg ( isConstraintY ? " > 0" : "")
123 .arg (tr ("as"))
124 .arg (unitsType (IS_X_THETA))
125 .arg (unitsType (IS_NOT_X_THETA));
126 QGroupBox *panel = new QGroupBox (description, this);
127 layoutOuter->addWidget (panel);
128
129 QHBoxLayout *layout = new QHBoxLayout (panel);
130 panel->setLayout (layout);
131
132 // Row
133 QLabel *labelGraphParLeft = new QLabel (tr ("("), this);
134 layout->addWidget(labelGraphParLeft, 0);
135
136 m_editGraphX = new QLineEdit;
137 m_editGraphX->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
138 m_editGraphX->setAlignment (ALIGNMENT);
139 m_editGraphX->setValidator (m_validatorGraphX);
140 // setStatusTip does not work for modal dialogs
141 m_editGraphX->setWhatsThis (tr ("Enter the first graph coordinate of the axis point.\n\n"
142 "For cartesian plots this is X. For polar plots this is the radius R.\n\n"
143 "The expected format of the coordinate value is determined by the locale setting. If "
144 "typed values are not recognized as expected, check the locale setting in Settings / Main Window..."));
145 layout->addWidget(m_editGraphX, 0);
146 connect (m_editGraphX, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
147
148 QLabel *labelGraphComma = new QLabel (tr (", "), this);
149 layout->addWidget(labelGraphComma, 0);
150
151 m_editGraphY = new QLineEdit;
152 m_editGraphY->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
153 m_editGraphY->setAlignment (ALIGNMENT);
154 m_editGraphY->setValidator (m_validatorGraphY);
155 // setStatusTip does not work for modal dialogs
156 m_editGraphY->setWhatsThis (tr ("Enter the second graph coordinate of the axis point.\n\n"
157 "For cartesian plots this is Y. For plot plots this is the angle Theta.\n\n"
158 "The expected format of the coordinate value is determined by the locale setting. If "
159 "typed values are not recognized as expected, check the locale setting in Settings / Main Window..."));
160 layout->addWidget(m_editGraphY, 0);
161 connect (m_editGraphY, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
162
163 QLabel *labelGraphParRight = new QLabel (tr (")"), this);
164 layout->addWidget(labelGraphParRight, 0);
165}
166
167void DlgEditPoint::createOkCancel (QVBoxLayout *layoutOuter)
168{
169 QWidget *panel = new QWidget (this);
170 layoutOuter->addWidget (panel, 0, Qt::AlignCenter);
171
172 QHBoxLayout *layout = new QHBoxLayout (panel);
173 panel->setLayout (layout);
174
175 m_btnOk = new QPushButton (tr ("Ok"), this);
176 layout->addWidget(m_btnOk);
177 connect (m_btnOk, SIGNAL (released ()), this, SLOT (accept ()));
178
179 m_btnCancel = new QPushButton (tr ("Cancel"), this);
180 layout->addWidget(m_btnCancel);
181 connect (m_btnCancel, SIGNAL (released ()), this, SLOT (reject ()));
182}
183
184void DlgEditPoint::initializeGraphCoordinates (const double *xInitialValue,
185 const double *yInitialValue,
186 const Transformation &transformation,
187 bool isX,
188 bool isY)
189{
190 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::initializeGraphCoordinates";
191
192 QString xTheta, yRadius;
193 if ((xInitialValue != 0) &&
194 (yInitialValue != 0)) {
195
196 FormatCoordsUnits format;
197 format.unformattedToFormatted (*xInitialValue,
198 *yInitialValue,
199 m_modelCoords,
200 m_modelMainWindow,
201 xTheta,
202 yRadius,
203 transformation);
204 }
205
206 if (isX) {
207 m_editGraphX->setText (xTheta);
208 } else {
209 m_editGraphX->setText ("");
210 }
211
212 if (isY) {
213 m_editGraphY->setText (yRadius);
214 } else {
215 m_editGraphY->setText ("");
216 }
217}
218
219bool DlgEditPoint::isCartesian () const
220{
221 return (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN);
222}
223
224QChar DlgEditPoint::nameXTheta () const
225{
226 return (isCartesian () ? QChar ('X') : THETA);
227}
228
229QChar DlgEditPoint::nameYRadius () const
230{
231 return (isCartesian () ? QChar ('Y') : QChar ('R'));
232}
233
234QPointF DlgEditPoint::posGraph (bool &isXOnly) const
235{
236 double xTheta, yRadius;
237
238 FormatCoordsUnits format;
239
240 format.formattedToUnformatted (m_editGraphX->text(),
241 m_editGraphY->text(),
242 m_modelCoords,
243 m_modelMainWindow,
244 xTheta,
245 yRadius);
246
247 // If yRadius value is empty then this is the xTheta value only
248 isXOnly = m_editGraphY->text().isEmpty();
249
250 return QPointF (xTheta,
251 yRadius);
252}
253
254void DlgEditPoint::slotTextChanged (const QString &)
255{
256 updateControls ();
257}
258
259QString DlgEditPoint::unitsType (bool isXTheta) const
260{
261 if (isCartesian ()) {
262 if (isXTheta) {
263 return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsX());
264 } else {
265 return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsY());
266 }
267 } else {
268 if (isXTheta) {
269 return coordUnitsPolarThetaToBriefType (m_modelCoords.coordUnitsTheta());
270 } else {
271 return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsRadius());
272 }
273 }
274}
275
276void DlgEditPoint::updateControls ()
277{
278 QString textX = m_editGraphX->text();
279 QString textY = m_editGraphY->text();
280
281 int posX, posY;
282
283 if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_4) {
284
285 bool gotX = (!textX.isEmpty() &&
286 (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable));
287 bool gotY = (!textY.isEmpty() &&
288 (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable));
289
290 // Check for not empty in one coordinate and for valid number in the other coordinate
291 m_btnOk->setEnabled ((textX.isEmpty() && gotY) ||
292 (textY.isEmpty() && gotX));
293
294 } else {
295
296 // Check for not empty (which allows single minus sign) and for valid number (which prevents single minus sign)
297 m_btnOk->setEnabled (!textX.isEmpty () &&
298 !textY.isEmpty () &&
299 (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable) &&
300 (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable));
301
302 }
303}
Base class for all digitizing states. This serves as an interface to DigitizeStateContext.
void removeOverrideCursor()
Remove the override cursor if it is in use. This is called after a leave event, and prior to displayi...
QPointF posGraph(bool &isXOnly) const
Return the graph coordinates position specified by the user. Only applies if dialog was accepted.
void signalSetOverrideCursor(QCursor)
Send a signal to trigger the setting of the override cursor.
DlgEditPoint(MainWindow &mainWindow, DigitizeStateAbstractBase &digitizeState, const DocumentModelCoords &modelCoords, const MainWindowModel &modelMainWindow, const QCursor &cursorShape, const Transformation &transformation, DocumentAxesPointsRequired documentAxesPointsRequired, bool isXOnly=false, 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.
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 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:78
Affine transformation between screen and graph coordinates, based on digitized axis points.