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 "MainWindowModel.h"
14 #include <QDoubleValidator>
15 #include <QGridLayout>
16 #include <QGroupBox>
17 #include <QHBoxLayout>
18 #include <QLabel>
19 #include <QRect>
20 #include <QVBoxLayout>
21 #include "Transformation.h"
22 
23 const Qt::Alignment ALIGNMENT = Qt::AlignCenter;
24 
25 const int MIN_WIDTH_TO_FIT_STRANGE_UNITS = 200;
26 
27 const bool IS_X_THETA = true;
28 const bool IS_NOT_X_THETA = false;
29 
31  DigitizeStateAbstractBase &digitizeState,
32  const DocumentModelCoords &modelCoords,
33  const MainWindowModel &modelMainWindow,
34  const QCursor &cursorShape,
35  const Transformation &transformation,
36  const double *xInitialValue,
37  const double *yInitialValue) :
38  QDialog (&mainWindow),
39  m_cursorShape (cursorShape),
40  m_modelCoords (modelCoords),
41  m_modelMainWindow (modelMainWindow)
42 {
43  LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::DlgEditPoint";
44 
45  // To guarantee the override cursor is always removed, we call removeOverrideCursor here rather than in the code that
46  // allocates this DlgEditPoint. The digitizeState argument is otherwise unused.
47  digitizeState.removeOverrideCursor();
48 
49  connect (this, SIGNAL (signalSetOverrideCursor (QCursor)), &mainWindow, SLOT (slotSetOverrideCursor (QCursor)));
50 
51  QVBoxLayout *layout = new QVBoxLayout;
52  setLayout (layout);
53 
54  setCursor (QCursor (Qt::ArrowCursor));
55  setModal(true);
56  setWindowTitle (tr ("Edit Axis Point"));
57 
58  createCoords (layout);
59  createOkCancel (layout);
60 
61  initializeGraphCoordinates (xInitialValue,
62  yInitialValue,
63  transformation);
64 
65  updateControls ();
66 }
67 
68 DlgEditPoint::~DlgEditPoint()
69 {
70  LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::~DlgEditPoint";
71 
72  emit signalSetOverrideCursor (m_cursorShape);
73 }
74 
75 void DlgEditPoint::createCoords (QVBoxLayout *layoutOuter)
76 {
77  // Constraints on x and y are needed for log scaling
78  bool isConstraintX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG);
79  bool isConstraintY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG);
80  DlgValidatorFactory dlgValidatorFactory;
81  m_validatorGraphX = dlgValidatorFactory.createCartesianOrPolarWithPolarPolar (m_modelCoords.coordScaleXTheta(),
82  isCartesian (),
83  m_modelCoords.coordUnitsX(),
84  m_modelCoords.coordUnitsTheta(),
85  m_modelCoords.coordUnitsDate(),
86  m_modelCoords.coordUnitsTime(),
87  m_modelMainWindow.locale());
88  m_validatorGraphY = dlgValidatorFactory.createCartesianOrPolarWithNonPolarPolar (m_modelCoords.coordScaleYRadius(),
89  isCartesian (),
90  m_modelCoords.coordUnitsY(),
91  m_modelCoords.coordUnitsRadius(),
92  m_modelCoords.coordUnitsDate(),
93  m_modelCoords.coordUnitsTime(),
94  m_modelMainWindow.locale());
95 
96  // Label, with guidance in terms of legal ranges and units
97  QString description = QString ("Graph Coordinates (%1, %2)%3%4%5%6%7%8 as (%9, %10):")
98  .arg (nameXTheta ())
99  .arg (nameYRadius ())
100  .arg (isConstraintX || isConstraintY ? " with " : "")
101  .arg (isConstraintX ? QString (nameXTheta ()) : "")
102  .arg (isConstraintX ? " > 0" : "")
103  .arg (isConstraintX && isConstraintY ? " and " : "")
104  .arg ( isConstraintY ? QString (nameYRadius ()) : "")
105  .arg ( isConstraintY ? " > 0" : "")
106  .arg (unitsType (IS_X_THETA))
107  .arg (unitsType (IS_NOT_X_THETA));
108  QGroupBox *panel = new QGroupBox (description, this);
109  layoutOuter->addWidget (panel);
110 
111  QHBoxLayout *layout = new QHBoxLayout (panel);
112  panel->setLayout (layout);
113 
114  // Row
115  QLabel *labelGraphParLeft = new QLabel (tr ("("), this);
116  layout->addWidget(labelGraphParLeft, 0);
117 
118  m_editGraphX = new QLineEdit;
119  m_editGraphX->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
120  m_editGraphX->setAlignment (ALIGNMENT);
121  m_editGraphX->setValidator (m_validatorGraphX);
122  // setStatusTip does not work for modal dialogs
123  m_editGraphX->setWhatsThis (tr ("Enter the first graph coordinate of the axis point.\n\n"
124  "For cartesian plots this is X. For polar plots this is the radius R."));
125  layout->addWidget(m_editGraphX, 0);
126  connect (m_editGraphX, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
127 
128  QLabel *labelGraphComma = new QLabel (tr (", "), this);
129  layout->addWidget(labelGraphComma, 0);
130 
131  m_editGraphY = new QLineEdit;
132  m_editGraphY->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
133  m_editGraphY->setAlignment (ALIGNMENT);
134  m_editGraphY->setValidator (m_validatorGraphY);
135  // setStatusTip does not work for modal dialogs
136  m_editGraphY->setWhatsThis (tr ("Enter the second graph coordinate of the axis point.\n\n"
137  "For cartesian plots this is Y. For plot plots this is the angle Theta."));
138  layout->addWidget(m_editGraphY, 0);
139  connect (m_editGraphY, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
140 
141  QLabel *labelGraphParRight = new QLabel (tr (")"), this);
142  layout->addWidget(labelGraphParRight, 0);
143 }
144 
145 void DlgEditPoint::createOkCancel (QVBoxLayout *layoutOuter)
146 {
147  QWidget *panel = new QWidget (this);
148  layoutOuter->addWidget (panel, 0, Qt::AlignCenter);
149 
150  QHBoxLayout *layout = new QHBoxLayout (panel);
151  panel->setLayout (layout);
152 
153  m_btnOk = new QPushButton (tr ("Ok"), this);
154  layout->addWidget(m_btnOk);
155  connect (m_btnOk, SIGNAL (released ()), this, SLOT (accept ()));
156 
157  m_btnCancel = new QPushButton (tr ("Cancel"), this);
158  layout->addWidget(m_btnCancel);
159  connect (m_btnCancel, SIGNAL (released ()), this, SLOT (reject ()));
160 }
161 
162 void DlgEditPoint::initializeGraphCoordinates (const double *xInitialValue,
163  const double *yInitialValue,
164  const Transformation &transformation)
165 {
166  LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPoint::initializeGraphCoordinates";
167 
168  QString xTheta, yRadius;
169  if ((xInitialValue != 0) &&
170  (yInitialValue != 0)) {
171 
172  FormatCoordsUnits format;
173  format.unformattedToFormatted (*xInitialValue,
174  *yInitialValue,
175  m_modelCoords,
176  m_modelMainWindow,
177  xTheta,
178  yRadius,
179  transformation);
180  }
181 
182  m_editGraphX->setText (xTheta);
183  m_editGraphY->setText (yRadius);
184 }
185 
186 bool DlgEditPoint::isCartesian () const
187 {
188  return (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN);
189 }
190 
191 QChar DlgEditPoint::nameXTheta () const
192 {
193  return (isCartesian () ? QChar ('X') : THETA);
194 }
195 
196 QChar DlgEditPoint::nameYRadius () const
197 {
198  return (isCartesian () ? QChar ('Y') : QChar ('R'));
199 }
200 
201 QPointF DlgEditPoint::posGraph () const
202 {
203  double xTheta, yRadius;
204 
205  FormatCoordsUnits format;
206 
207  format.formattedToUnformatted (m_editGraphX->text(),
208  m_editGraphY->text(),
209  m_modelCoords,
210  m_modelMainWindow,
211  xTheta,
212  yRadius);
213 
214  return QPointF (xTheta,
215  yRadius);
216 }
217 
218 void DlgEditPoint::slotTextChanged (const QString &)
219 {
220  updateControls ();
221 }
222 
223 QString DlgEditPoint::unitsType (bool isXTheta) const
224 {
225  if (isCartesian ()) {
226  if (isXTheta) {
227  return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsX());
228  } else {
229  return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsY());
230  }
231  } else {
232  if (isXTheta) {
233  return coordUnitsPolarThetaToBriefType (m_modelCoords.coordUnitsTheta());
234  } else {
235  return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsRadius());
236  }
237  }
238 }
239 
240 void DlgEditPoint::updateControls ()
241 {
242  // Check for not empty (which allows single minus sign) and for valid number (which prevents single minus sign)
243  QString textX = m_editGraphX->text();
244  QString textY = m_editGraphY->text();
245  int posX, posY;
246  m_btnOk->setEnabled (!textX.isEmpty () &&
247  !textY.isEmpty () &&
248  (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable) &&
249  (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable));
250 }
251 
DlgEditPoint(MainWindow &mainWindow, DigitizeStateAbstractBase &digitizeState, const DocumentModelCoords &modelCoords, const MainWindowModel &modelMainWindow, 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...
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.
virtual QValidator::State validate(QString &input, int &pos) const =0
Validate according to the numeric format specific to the leaf class.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
CoordUnitsNonPolarTheta coordUnitsRadius() const
Get method for radius units.
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...
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...
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 and CmdSettingsMainWindow.
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...
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.
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:66
CoordUnitsPolarTheta coordUnitsTheta() const
Get method for theta unit.