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