Engauge Digitizer  2
DlgEditPoint.cpp
1 #include "DigitizeStateAbstractBase.h"
2 #include "DlgEditPoint.h"
3 #include "DlgValidatorAbstract.h"
4 #include "DlgValidatorFactory.h"
5 #include "DocumentModelCoords.h"
6 #include "EngaugeAssert.h"
7 #include "FormatCoordsUnits.h"
8 #include "FormatDateTime.h"
9 #include "FormatDegreesMinutesSecondsNonPolarTheta.h"
10 #include "FormatDegreesMinutesSecondsPolarTheta.h"
11 #include "Logger.h"
12 #include "MainWindow.h"
13 #include <QDoubleValidator>
14 #include <QGridLayout>
15 #include <QGroupBox>
16 #include <QHBoxLayout>
17 #include <QLabel>
18 #include <QRect>
19 #include <QVBoxLayout>
20 #include "Transformation.h"
21 
22 const Qt::Alignment ALIGNMENT = Qt::AlignCenter;
23 
24 const int MIN_WIDTH_TO_FIT_STRANGE_UNITS = 200;
25 
26 const bool IS_X_THETA = true;
27 const bool IS_NOT_X_THETA = false;
28 
30  DigitizeStateAbstractBase &digitizeState,
31  const DocumentModelCoords &modelCoords,
32  const QCursor &cursorShape,
33  const Transformation &transformation,
34  const double *xInitialValue,
35  const double *yInitialValue) :
36  QDialog (&mainWindow),
37  m_cursorShape (cursorShape),
38  m_modelCoords (modelCoords)
39 {
40  LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::DlgEditPoint";
41 
42  // To guarantee the override cursor is always removed, we call removeOverrideCursor here rather than in the code that
43  // allocates this DlgEditPoint. The digitizeState argument is otherwise unused.
44  digitizeState.removeOverrideCursor();
45 
46  connect (this, SIGNAL (signalSetOverrideCursor (QCursor)), &mainWindow, SLOT (slotSetOverrideCursor (QCursor)));
47 
48  QVBoxLayout *layout = new QVBoxLayout;
49  setLayout (layout);
50 
51  setCursor (QCursor (Qt::ArrowCursor));
52  setModal(true);
53  setWindowTitle (tr ("Edit Axis Point"));
54 
55  createCoords (layout);
56  createOkCancel (layout);
57 
58  initializeGraphCoordinates (xInitialValue,
59  yInitialValue,
60  transformation);
61 
62  updateControls ();
63 }
64 
65 DlgEditPoint::~DlgEditPoint()
66 {
67  LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::~DlgEditPoint";
68 
69  emit signalSetOverrideCursor (m_cursorShape);
70 }
71 
72 void DlgEditPoint::createCoords (QVBoxLayout *layoutOuter)
73 {
74  // Constraints on x and y are needed for log scaling
75  bool isConstraintX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG);
76  bool isConstraintY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG);
77  DlgValidatorFactory dlgValidatorFactory;
78  m_validatorGraphX = dlgValidatorFactory.createCartesianOrPolarWithPolarPolar (m_modelCoords.coordScaleXTheta(),
79  isCartesian (),
80  m_modelCoords.coordUnitsX(),
81  m_modelCoords.coordUnitsTheta(),
82  m_modelCoords.coordUnitsDate(),
83  m_modelCoords.coordUnitsTime());
84  m_validatorGraphY = dlgValidatorFactory.createCartesianOrPolarWithNonPolarPolar (m_modelCoords.coordScaleYRadius(),
85  isCartesian (),
86  m_modelCoords.coordUnitsY(),
87  m_modelCoords.coordUnitsRadius(),
88  m_modelCoords.coordUnitsDate(),
89  m_modelCoords.coordUnitsTime());
90 
91  // Label, with guidance in terms of legal ranges and units
92  QString description = QString ("Graph Coordinates (%1, %2)%3%4%5%6%7%8 as (%9, %10):")
93  .arg (nameXTheta ())
94  .arg (nameYRadius ())
95  .arg (isConstraintX || isConstraintY ? " with " : "")
96  .arg (isConstraintX ? QString (nameXTheta ()) : "")
97  .arg (isConstraintX ? " > 0" : "")
98  .arg (isConstraintX && isConstraintY ? " and " : "")
99  .arg ( isConstraintY ? QString (nameYRadius ()) : "")
100  .arg ( isConstraintY ? " > 0" : "")
101  .arg (unitsType (IS_X_THETA))
102  .arg (unitsType (IS_NOT_X_THETA));
103  QGroupBox *panel = new QGroupBox (description, this);
104  layoutOuter->addWidget (panel);
105 
106  QHBoxLayout *layout = new QHBoxLayout (panel);
107  panel->setLayout (layout);
108 
109  // Row
110  QLabel *labelGraphParLeft = new QLabel (tr ("("), this);
111  layout->addWidget(labelGraphParLeft, 0);
112 
113  m_editGraphX = new QLineEdit;
114  m_editGraphX->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
115  m_editGraphX->setAlignment (ALIGNMENT);
116  m_editGraphX->setValidator (m_validatorGraphX);
117  // setStatusTip does not work for modal dialogs
118  m_editGraphX->setWhatsThis (tr ("Enter the first graph coordinate of the axis point.\n\n"
119  "For cartesian plots this is X. For polar plots this is the radius R."));
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 QLineEdit;
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 of the axis point.\n\n"
132  "For cartesian plots this is Y. For plot plots this is the angle Theta."));
133  layout->addWidget(m_editGraphY, 0);
134  connect (m_editGraphY, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
135 
136  QLabel *labelGraphParRight = new QLabel (tr (")"), this);
137  layout->addWidget(labelGraphParRight, 0);
138 }
139 
140 void DlgEditPoint::createOkCancel (QVBoxLayout *layoutOuter)
141 {
142  QWidget *panel = new QWidget (this);
143  layoutOuter->addWidget (panel, 0, Qt::AlignCenter);
144 
145  QHBoxLayout *layout = new QHBoxLayout (panel);
146  panel->setLayout (layout);
147 
148  m_btnOk = new QPushButton (tr ("Ok"), this);
149  layout->addWidget(m_btnOk);
150  connect (m_btnOk, SIGNAL (released ()), this, SLOT (accept ()));
151 
152  m_btnCancel = new QPushButton (tr ("Cancel"), this);
153  layout->addWidget(m_btnCancel);
154  connect (m_btnCancel, SIGNAL (released ()), this, SLOT (reject ()));
155 }
156 
157 void DlgEditPoint::initializeGraphCoordinates (const double *xInitialValue,
158  const double *yInitialValue,
159  const Transformation &transformation)
160 {
161  LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::initializeGraphCoordinates";
162 
163  QString xTheta, yRadius;
164  if ((xInitialValue != 0) &&
165  (yInitialValue != 0)) {
166 
167  FormatCoordsUnits format;
168  format.unformattedToFormatted (*xInitialValue,
169  *yInitialValue,
170  m_modelCoords,
171  xTheta,
172  yRadius,
173  transformation);
174  }
175 
176  m_editGraphX->setText (xTheta);
177  m_editGraphY->setText (yRadius);
178 }
179 
180 bool DlgEditPoint::isCartesian () const
181 {
182  return (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN);
183 }
184 
185 QChar DlgEditPoint::nameXTheta () const
186 {
187  return (isCartesian () ? QChar ('X') : THETA);
188 }
189 
190 QChar DlgEditPoint::nameYRadius () const
191 {
192  return (isCartesian () ? QChar ('Y') : QChar ('R'));
193 }
194 
195 QPointF DlgEditPoint::posGraph () const
196 {
197  double xTheta, yRadius;
198 
199  FormatCoordsUnits format;
200 
201  format.formattedToUnformatted (m_editGraphX->text(),
202  m_editGraphY->text(),
203  m_modelCoords,
204  xTheta,
205  yRadius);
206 
207  return QPointF (xTheta,
208  yRadius);
209 }
210 
211 void DlgEditPoint::slotTextChanged (const QString &)
212 {
213  updateControls ();
214 }
215 
216 QString DlgEditPoint::unitsType (bool isXTheta) const
217 {
218  if (isCartesian ()) {
219  if (isXTheta) {
220  return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsX());
221  } else {
222  return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsY());
223  }
224  } else {
225  if (isXTheta) {
226  return coordUnitsPolarThetaToBriefType (m_modelCoords.coordUnitsTheta());
227  } else {
228  return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsRadius());
229  }
230  }
231 }
232 
233 void DlgEditPoint::updateControls ()
234 {
235  // Check for not empty (which allows single minus sign) and for valid number (which prevents single minus sign)
236  QString textX = m_editGraphX->text();
237  QString textY = m_editGraphY->text();
238  int posX, posY;
239  m_btnOk->setEnabled (!textX.isEmpty () &&
240  !textY.isEmpty () &&
241  (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable) &&
242  (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable));
243 }
244 
DlgEditPoint(MainWindow &mainWindow, DigitizeStateAbstractBase &digitizeState, const DocumentModelCoords &modelCoords, const QCursor &cursorShape, 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...
DlgValidatorAbstract * createCartesianOrPolarWithPolarPolar(CoordScale coordScale, bool isCartesian, CoordUnitsNonPolarTheta coordUnitsCartesian, CoordUnitsPolarTheta coordUnitsPolar, CoordUnitsDate coordUnitsDate, CoordUnitsTime coordUnitsTime) const
Factory method for generating validators for either cartesian or polar case, when polar format is spe...
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.
CoordUnitsTime coordUnitsTime() const
Get method for time format when used.
void unformattedToFormatted(double xThetaUnformatted, double yRadiusUnformatted, const DocumentModelCoords &modelCoords, QString &xThetaFormatted, QString &yRadiusFormatted, const Transformation &transformation) const
Convert unformatted numeric value to formatted string. Transformation is used to determine best resol...
void signalSetOverrideCursor(QCursor)
Send a signal to trigger the setting of the override cursor.
QPointF posGraph() const
Return the graph coordinates position specified by the user. Only applies if dialog was accepted...
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.
CoordsType coordsType() const
Get method for coordinates type.
DlgValidatorAbstract * createCartesianOrPolarWithNonPolarPolar(CoordScale coordScale, bool isCartesian, CoordUnitsNonPolarTheta coordUnitsCartesian, CoordUnitsNonPolarTheta coordUnitsPolar, CoordUnitsDate coordUnitsDate, CoordUnitsTime coordUnitsTime) const
Factory method for generating validators for either cartesian or polar case, when polar format is spe...
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.
void removeOverrideCursor()
Remove the override cursor if it is in use. This is called after a leave event, and prior to displayi...
Base class for all digitizing states. This serves as an interface to DigitizeStateContext.
Validator factory.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:60
void formattedToUnformatted(const QString &xThetaFormatted, const QString &yRadiusFormatted, const DocumentModelCoords &modelCoords, double &xThetaUnformatted, double &yRadiusUnformatted) const
Convert formatted string to unformatted numeric value.
CoordUnitsPolarTheta coordUnitsTheta() const
Get method for theta unit.