Engauge Digitizer  2
DlgSettingsCoords.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 "CallbackBoundingRects.h"
8 #include "CmdMediator.h"
9 #include "CmdSettingsCoords.h"
10 #include "CoordUnitsDate.h"
11 #include "CoordUnitsTime.h"
12 #include "DlgSettingsCoords.h"
13 #include "DlgValidatorAbstract.h"
14 #include "DlgValidatorFactory.h"
15 #include "DocumentModelCoords.h"
16 #include "EngaugeAssert.h"
17 #include "Logger.h"
18 #include "MainWindow.h"
19 #include <math.h>
20 #include <QComboBox>
21 #include <QDebug>
22 #include <QDoubleValidator>
23 #include <QGraphicsRectItem>
24 #include <QGridLayout>
25 #include <QGroupBox>
26 #include <QGraphicsScene>
27 #include <QLabel>
28 #include <QLineEdit>
29 #include <QPalette>
30 #include <QRadioButton>
31 #include <QStackedWidget>
32 #include <QVBoxLayout>
33 #include "Transformation.h"
34 #include "ViewPreview.h"
35 
36 const QString OVERRIDDEN_VALUE(""); // Values are overridden in updateControls
37 
38 const int COLUMN_0 = 0;
39 const int COLUMN_1 = 1;
40 
41 const int STEPS_PER_CYCLE = 4; // Repeat STEPS_PER_CYLE-1 unhighlighted steps plus 1 highlighted step in each cycle
42 const int STEPS_CYCLE_COUNT = 4; // Repeat one highlighted step + STEPS_UNHIGHLIGHTED_PER_HIGHLIGHTED steps this many times
43 const int NUM_COORD_STEPS = 1 + STEPS_PER_CYCLE * STEPS_CYCLE_COUNT;
44 
45 const int MAX_WIDTH_EDIT_ORIGIN_RADIUS = 140;
46 
47 const int CARTESIAN_COORD_MAX = 100;
48 const int CARTESIAN_COORD_MIN = -100;
49 const double CARTESIAN_COORD_STEP = (CARTESIAN_COORD_MAX - CARTESIAN_COORD_MIN) / (NUM_COORD_STEPS - 1.0);
50 
51 const int POLAR_RADIUS = CARTESIAN_COORD_MAX;
52 const double POLAR_STEP = POLAR_RADIUS / (NUM_COORD_STEPS - 1.0);
53 
54 const int POLAR_THETA_MAX = 360;
55 const int POLAR_THETA_MIN = 0;
56 const double POLAR_THETA_STEP = (POLAR_THETA_MAX - POLAR_THETA_MIN) / (NUM_COORD_STEPS - 1.0);
57 
58 const double XCENTER = (CARTESIAN_COORD_MIN + CARTESIAN_COORD_MAX) / 2.0;
59 const double YCENTER = (CARTESIAN_COORD_MIN + CARTESIAN_COORD_MAX) / 2.0;
60 
61 const double LINE_WIDTH_THIN = 0.0;
62 const double LINE_WIDTH_THICK = 2.0;
63 
64 const double PI = 3.1415926535;
65 const double DEG_2_RAD = PI / 180.0;
66 
67 const int FONT_SIZE = 6;
68 
69 const double POWER_FOR_LOG = 10.0; // Need a larger power (certainly more than e) to make log gradient obvious
70 
72  DlgSettingsAbstractBase (tr ("Coordinates"),
73  "DlgSettingsCoords",
74  mainWindow),
75  m_btnCartesian (0),
76  m_btnPolar (0),
77  m_validatorOriginRadius (0),
78  m_cmbDate (0),
79  m_cmbTime (0),
80  m_scenePreview (0),
81  m_viewPreview (0),
82  m_modelCoordsBefore (0),
83  m_modelCoordsAfter (0)
84 {
85  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::DlgSettingsCoords";
86 
87  QWidget *subPanel = createSubPanel ();
88  finishPanel (subPanel);
89 }
90 
91 DlgSettingsCoords::~DlgSettingsCoords()
92 {
93  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::~DlgSettingsCoords";
94 }
95 
96 void DlgSettingsCoords::annotateAngles (const QFont &defaultFont) {
97 
98  // 0=+x, 1=+y, 2=-x, 3=-y
99  for (int direction = 0; direction < 4; direction++) {
100 
101  QString angle;
102  CoordUnitsPolarTheta thetaUnits = (CoordUnitsPolarTheta) m_cmbXThetaUnits->currentData().toInt();
103 
104  switch (thetaUnits) {
105  case COORD_UNITS_POLAR_THETA_DEGREES:
106  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES:
107  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS:
108  angle = QString::number (90.0 * direction);
109  break;
110 
111  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW:
112  angle = QString::number (90.0 * direction);
113  if (direction == 1) {
114  angle = "90E";
115  } else if (direction == 3) {
116  angle = "90W";
117  }
118  break;
119 
120  case COORD_UNITS_POLAR_THETA_GRADIANS:
121  angle = QString::number (100.0 * direction);
122  break;
123 
124  case COORD_UNITS_POLAR_THETA_RADIANS:
125  {
126  static QString radiansUnits [] = {"0", "PI / 2", "PI", "3 * PI / 2"};
127  ENGAUGE_ASSERT (direction < 4);
128  angle = radiansUnits [direction];
129  }
130  break;
131 
132  case COORD_UNITS_POLAR_THETA_TURNS:
133  {
134  static QString turnsUnits [] = {"0", "1 / 4", "1 / 2", "3 / 4"};
135  ENGAUGE_ASSERT (direction < 4);
136  angle = turnsUnits [direction];
137  }
138  break;
139 
140  default:
141  break;
142  }
143 
144  QGraphicsTextItem *textAngle = m_scenePreview->addText (angle);
145  textAngle->setFont (QFont (defaultFont.defaultFamily(), FONT_SIZE));
146  double x = 0, y = 0; // Initialized to prevent compiler warning
147  switch (direction) {
148  case 0:
149  x = CARTESIAN_COORD_MAX - textAngle->boundingRect().width ();
150  break;
151  case 1:
152  case 3:
153  x = XCENTER - textAngle->boundingRect().width () / 2.0;
154  break;
155  case 2:
156  x = CARTESIAN_COORD_MIN;
157  break;
158  }
159  switch (direction) {
160  case 0:
161  case 2:
162  y = YCENTER;
163  break;
164  case 1:
165  y = CARTESIAN_COORD_MIN;
166  break;
167  case 3:
168  y = CARTESIAN_COORD_MAX - textAngle->boundingRect().height ();
169  break;
170  }
171 
172  textAngle->setPos (x, y);
173  }
174 }
175 
176 void DlgSettingsCoords::annotateRadiusAtOrigin(const QFont &defaultFont) {
177 
178  QGraphicsTextItem *textRadius = m_scenePreview->addText (m_editOriginRadius->text());
179  textRadius->setFont (QFont (defaultFont.defaultFamily(), FONT_SIZE));
180  textRadius->setPos (XCENTER - textRadius->boundingRect().width () / 2.0,
181  YCENTER);
182 }
183 
184 QRectF DlgSettingsCoords::boundingRectGraph (CmdMediator &cmdMediator,
185  bool &isEmpty) const
186 {
187  CallbackBoundingRects ftor (mainWindow().transformation());
188 
189  Functor2wRet<const QString &, const Point&, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
191 
192  // There may or may one, two or three axis points. Even if all three are not defined (so
193  // transformation is not defined), we can still get coordinates if there are one or two
194  cmdMediator.iterateThroughCurvePointsAxes (ftorWithCallback);
195 
196  // If the transformation is not defined, then there are no graph coordinates to extract
197  // from the graph curves (and probably trigger an assert)
198  if (mainWindow().transformIsDefined()) {
199  cmdMediator.iterateThroughCurvesPointsGraphs (ftorWithCallback);
200  }
201 
202  return ftor.boundingRectGraph(isEmpty);
203 }
204 
205 void DlgSettingsCoords::createDateTime (QGridLayout *layout,
206  int &row)
207 {
208  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createDateTime";
209 
210  QLabel *label = new QLabel(tr ("Date/Time:"));
211  layout->addWidget (label, row, 1);
212 
213  QWidget *widgetCombos = new QWidget;
214  layout->addWidget (widgetCombos, row++, 2);
215  QHBoxLayout *layoutCombos = new QHBoxLayout;
216  widgetCombos->setLayout (layoutCombos);
217 
218  // Put date and time comboboxes into same widget
219  m_cmbDate = new QComboBox;
220  m_cmbDate->setWhatsThis (tr ("Date format to be used for date values, and date portion of mixed date/time values, "
221  "during input and output.\n\n"
222  "Setting the format to an empty value results in just the time portion appearing in output."));
223  connect (m_cmbDate, SIGNAL (activated (const QString &)), this, SLOT (slotDate (const QString &)));
224  layoutCombos->addWidget (m_cmbDate);
225 
226  m_cmbTime = new QComboBox;
227  m_cmbTime->setWhatsThis (tr ("Time format to be used for time values, and time portion of mixed date/time values, "
228  "during input and output.\n\n"
229  "Setting the format to an empty value results in just the date portion appearing in output."));
230  connect (m_cmbTime, SIGNAL (activated (const QString &)), this, SLOT (slotTime (const QString &)));
231  layoutCombos->addWidget (m_cmbTime);
232 }
233 
234 void DlgSettingsCoords::createGroupCoordsType (QGridLayout *layout,
235  int &row)
236 {
237  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createGroupCoordsType";
238 
239  m_boxCoordsType = new QGroupBox(tr ("Coordinates Types"));
240  layout->addWidget (m_boxCoordsType, row++, 1, 1, 2);
241 
242  QVBoxLayout *layoutGroup = new QVBoxLayout (m_boxCoordsType);
243 
244  QString polarButtonText = QString(tr ("Polar") + " (") + THETA + QString(", " + tr ("R") + ")");
245 
246  m_btnCartesian = new QRadioButton (tr ("Cartesian (X, Y)"), m_boxCoordsType);
247  m_btnCartesian->setWhatsThis (QString(tr("Select cartesian coordinates.\n\n"
248  "The X and Y coordinates will be used")));
249  connect (m_btnCartesian, SIGNAL (toggled(bool)), this, SLOT (slotCartesianPolar (bool)));
250  layoutGroup->addWidget (m_btnCartesian);
251 
252  m_btnPolar = new QRadioButton (polarButtonText, m_boxCoordsType);
253  m_btnPolar->setWhatsThis (QString(tr("Select polar coordinates.\n\n"
254  "The Theta and R coordinates will be used.\n\n"
255  "Polar coordinates are not allowed with log scale for Theta")));
256  connect (m_btnPolar, SIGNAL (toggled(bool)), this, SLOT (slotCartesianPolar (bool)));
257  layoutGroup->addWidget (m_btnPolar);
258 }
259 
260 void DlgSettingsCoords::createGroupXTheta (QGridLayout *layout,
261  int &row)
262 {
263  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createGroupXTheta";
264 
265  m_boxXTheta = new QGroupBox(OVERRIDDEN_VALUE);
266  layout->addWidget (m_boxXTheta, row++, 1, 1, 2);
267 
268  QGridLayout *layoutXTheta = new QGridLayout (m_boxXTheta);
269  m_boxXTheta->setLayout (layoutXTheta);
270  int rowGroup = 0;
271 
272  QLabel *labelScale = new QLabel (tr ("Scale:"));
273  layoutXTheta->addWidget (labelScale, rowGroup++, COLUMN_0);
274 
275  m_xThetaLinear = new QRadioButton (tr ("Linear"), m_boxXTheta);
276  m_xThetaLinear->setWhatsThis (QString(tr("Specifies linear scale for the X or Theta coordinate")));
277  connect (m_xThetaLinear, SIGNAL (released ()), this, SLOT (slotXThetaLinear()));
278  layoutXTheta->addWidget (m_xThetaLinear, rowGroup++, COLUMN_0);
279 
280  m_xThetaLog = new QRadioButton (tr ("Log"), m_boxXTheta);
281  m_xThetaLog->setWhatsThis (QString(tr("Specifies logarithmic scale for the X or Theta coordinate.\n\n"
282  "Log scale is not allowed if there are negative coordinates.\n\n"
283  "Log scale is not allowed for the Theta coordinate.")));
284  connect (m_xThetaLog, SIGNAL (released ()), this, SLOT (slotXThetaLog()));
285  layoutXTheta->addWidget (m_xThetaLog, rowGroup++, COLUMN_0);
286 
287  QLabel *labelThetaUnits = new QLabel(tr ("Units:"));
288  layoutXTheta->addWidget (labelThetaUnits, rowGroup++, COLUMN_0);
289 
290  m_cmbXThetaUnits = new QComboBox;
291  connect (m_cmbXThetaUnits, SIGNAL (activated (const QString &)), this, SLOT (slotUnitsXTheta(const QString &))); // activated() ignores code changes
292  layoutXTheta->addWidget (m_cmbXThetaUnits, rowGroup++, COLUMN_0, 1, 2);
293 }
294 
295 void DlgSettingsCoords::createGroupYRadius (QGridLayout *layout,
296  int &row)
297 {
298  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createGroupYRadius";
299 
300  m_boxYRadius = new QGroupBox (OVERRIDDEN_VALUE);
301  layout->addWidget (m_boxYRadius, row++, 1, 1, 2);
302 
303  QGridLayout *layoutYRadius = new QGridLayout (m_boxYRadius);
304  m_boxYRadius->setLayout (layoutYRadius);
305  int rowGroup = 0;
306 
307  QLabel *labelScale = new QLabel (tr ("Scale:"));
308  layoutYRadius->addWidget (labelScale, rowGroup++, COLUMN_0);
309 
310  m_yRadiusLinear = new QRadioButton (tr ("Linear"), m_boxYRadius);
311  m_yRadiusLinear->setWhatsThis (QString(tr("Specifies linear scale for the Y or R coordinate")));
312  connect (m_yRadiusLinear, SIGNAL(released()), this, SLOT (slotYRadiusLinear()));
313  layoutYRadius->addWidget (m_yRadiusLinear, rowGroup++, COLUMN_0);
314 
315  m_yRadiusLog = new QRadioButton (tr ("Log"), m_boxYRadius);
316  m_yRadiusLog->setWhatsThis (QString(tr("Specifies logarithmic scale for the Y or R coordinate\n\n"
317  "Log scale is not allowed if there are negative coordinates.")));
318  connect (m_yRadiusLog, SIGNAL(released ()), this, SLOT (slotYRadiusLog ()));
319  layoutYRadius->addWidget (m_yRadiusLog, rowGroup++, COLUMN_0);
320 
321  QLabel *labelUnits = new QLabel(tr ("Units:"));
322  layoutYRadius->addWidget (labelUnits, rowGroup++, COLUMN_0);
323 
324  m_cmbYRadiusUnits = new QComboBox;
325  connect (m_cmbYRadiusUnits, SIGNAL (activated (const QString &)), this, SLOT (slotUnitsYRadius(const QString &))); // activated() ignores code changes
326  layoutYRadius->addWidget (m_cmbYRadiusUnits, rowGroup++, COLUMN_0, 1, 2);
327 
328  rowGroup = 0;
329  QLabel *labelOriginRadius = new QLabel(tr ("Origin radius value:"));
330  layoutYRadius->addWidget (labelOriginRadius, rowGroup++, COLUMN_1);
331 
332  m_editOriginRadius = new QLineEdit (m_boxYRadius);
333  m_editOriginRadius->setMaximumWidth (MAX_WIDTH_EDIT_ORIGIN_RADIUS);
334  m_editOriginRadius->setWhatsThis (QString(tr("Specify radius value at origin.\n\n"
335  "Normally the radius at the origin is 0, but a nonzero value may be applied in other cases "
336  "(like when the radial units are decibels).")));
337  connect (m_editOriginRadius, SIGNAL (textChanged (const QString &)), this, SLOT (slotPolarOriginRadius(const QString &)));
338  layoutYRadius->addWidget (m_editOriginRadius, rowGroup++, COLUMN_1);
339 }
340 
341 void DlgSettingsCoords::createOptionalSaveDefault (QHBoxLayout * /* layout */)
342 {
343 }
344 
345 void DlgSettingsCoords::createPreview (QGridLayout *layout,
346  int &row)
347 {
348  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createPreview";
349 
350  QLabel *labelPreview = new QLabel (tr ("Preview"));
351  layout->addWidget (labelPreview, row++, 0, 1, 4);
352 
353  m_scenePreview = new QGraphicsScene (this);
354  m_viewPreview = new ViewPreview (m_scenePreview,
355  ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
356  this);
357  m_viewPreview->setWhatsThis (tr ("Preview window that shows how current settings affect the coordinate system."));
358  m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
359  m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
360  m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
361 
362  layout->addWidget (m_viewPreview, row++, 0, 1, 4);
363 }
364 
366 {
367  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createSubPanel";
368 
369  QWidget *subPanel = new QWidget ();
370  QGridLayout *layout = new QGridLayout (subPanel);
371  subPanel->setLayout (layout);
372 
373  layout->setColumnStretch(0, 1); // Empty first column
374  layout->setColumnStretch(1, 0); // Labels
375  layout->setColumnStretch(2, 0); // User controls
376  layout->setColumnStretch(3, 1); // Empty last column
377 
378  int row = 0;
379  createGroupCoordsType(layout, row);
380  createGroupXTheta (layout, row);
381  createGroupYRadius (layout, row);
382  createDateTime (layout, row);
383  createPreview (layout, row);
384 
385  return subPanel;
386 }
387 
388 void DlgSettingsCoords::drawCartesianLinearX ()
389 {
390  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawCartesianLinearX";
391 
392  bool isAxis = true;
393  for (int step = 0; step < NUM_COORD_STEPS; step++) {
394  double x = CARTESIAN_COORD_MIN + step * CARTESIAN_COORD_STEP;
395  QGraphicsLineItem *line = m_scenePreview->addLine (x, CARTESIAN_COORD_MIN, x, CARTESIAN_COORD_MAX);
396  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
397  line->setPen(QPen (QBrush ((isHighlighted ? Qt::gray : Qt::lightGray)),
398  LINE_WIDTH_THIN,
399  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
400  if (isAxis) {
401  line = m_scenePreview->addLine (x, CARTESIAN_COORD_MIN, x, CARTESIAN_COORD_MAX);
402  line->setPen(QPen (QBrush (Qt::black),
403  LINE_WIDTH_THICK));
404  }
405  isAxis = false;
406  }
407 }
408 
409 void DlgSettingsCoords::drawCartesianLinearY ()
410 {
411  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawCartesianLinearY";
412 
413  bool isAxis = true;
414  for (int step = NUM_COORD_STEPS - 1; step >= 0; step--) {
415  double y = CARTESIAN_COORD_MIN + step * CARTESIAN_COORD_STEP;
416  QGraphicsLineItem *line = m_scenePreview->addLine (CARTESIAN_COORD_MIN, y, CARTESIAN_COORD_MAX, y);
417  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
418  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
419  LINE_WIDTH_THIN,
420  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
421  if (isAxis) {
422  line = m_scenePreview->addLine (CARTESIAN_COORD_MIN, y, CARTESIAN_COORD_MAX, y);
423  line->setPen(QPen (QBrush (Qt::black),
424  LINE_WIDTH_THICK));
425  }
426  isAxis = false;
427  }
428 }
429 
430 void DlgSettingsCoords::drawCartesianLogX ()
431 {
432  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawCartesianLogX";
433 
434  bool isAxis = true;
435  for (int step = 0; step < NUM_COORD_STEPS; step++) {
436  double s = (exp (step / (NUM_COORD_STEPS - 1.0)) - 1.0) /
437  (exp (1.0) - 1.0);
438  double x = (1.0 - s) * CARTESIAN_COORD_MIN + s * CARTESIAN_COORD_MAX;
439  QGraphicsLineItem *line = m_scenePreview->addLine (x, CARTESIAN_COORD_MIN, x, CARTESIAN_COORD_MAX);
440  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
441  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
442  LINE_WIDTH_THIN,
443  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
444  if (isAxis) {
445  line = m_scenePreview->addLine (x, CARTESIAN_COORD_MIN, x, CARTESIAN_COORD_MAX);
446  line->setPen(QPen (QBrush (Qt::black),
447  LINE_WIDTH_THICK));
448  }
449  isAxis = false;
450  }
451 }
452 
453 void DlgSettingsCoords::drawCartesianLogY ()
454 {
455  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawCartesianLogY";
456 
457  bool isAxis = true;
458  for (int step = 0; step < NUM_COORD_STEPS; step++) {
459  double s = (pow (POWER_FOR_LOG, step / (NUM_COORD_STEPS - 1.0)) - 1.0) /
460  (pow (POWER_FOR_LOG, 1.0) - 1.0);
461  double y = (1.0 - s) * CARTESIAN_COORD_MAX + s * CARTESIAN_COORD_MIN; // Invert y coordinate (min<->max)
462  QGraphicsLineItem *line = m_scenePreview->addLine (CARTESIAN_COORD_MIN, y, CARTESIAN_COORD_MAX, y);
463  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
464  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
465  LINE_WIDTH_THIN,
466  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
467  if (isAxis) {
468  line = m_scenePreview->addLine (CARTESIAN_COORD_MIN, y, CARTESIAN_COORD_MAX, y);
469  line->setPen(QPen (QBrush (Qt::black),
470  LINE_WIDTH_THICK));
471  }
472  isAxis = false;
473  }
474 }
475 
476 void DlgSettingsCoords::drawPolarLinearRadius ()
477 {
478  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawPolarLinearRadius";
479 
480  for (int step = 0; step < NUM_COORD_STEPS; step++) {
481  double radius = step * POLAR_STEP;
482  QGraphicsEllipseItem *line = m_scenePreview->addEllipse (XCENTER - radius,
483  YCENTER - radius,
484  2.0 * radius,
485  2.0 * radius);
486  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
487  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
488  LINE_WIDTH_THIN,
489  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
490  }
491 }
492 
493 void DlgSettingsCoords::drawPolarLogRadius ()
494 {
495  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawPolarLogRadius";
496 
497  for (int step = 0; step < NUM_COORD_STEPS; step++) {
498  double s = (pow (POWER_FOR_LOG, step / (NUM_COORD_STEPS - 1.0)) - 1.0) /
499  (pow (POWER_FOR_LOG, 1.0) - 1.0);
500  double radius = (s * (NUM_COORD_STEPS - 1.0)) * POLAR_STEP;
501  QGraphicsEllipseItem *line = m_scenePreview->addEllipse (XCENTER - radius,
502  YCENTER - radius,
503  2.0 * radius,
504  2.0 * radius);
505  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
506  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
507  LINE_WIDTH_THIN,
508  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
509  }
510 }
511 
512 void DlgSettingsCoords::drawPolarTheta ()
513 {
514  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawPolarTheta";
515 
516  bool isAxis = true;
517  for (int step = 0; step < NUM_COORD_STEPS; step++) {
518  double theta = POLAR_THETA_MIN + step * POLAR_THETA_STEP;
519  double x = POLAR_RADIUS * cos (theta * DEG_2_RAD);
520  double y = POLAR_RADIUS * sin (theta * DEG_2_RAD);
521  QGraphicsLineItem *line = m_scenePreview->addLine (XCENTER, YCENTER, XCENTER + x, YCENTER + y);
522  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
523  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
524  LINE_WIDTH_THIN,
525  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
526  if (isAxis) {
527  line = m_scenePreview->addLine (XCENTER, YCENTER, XCENTER + x, YCENTER + y);
528  line->setPen(QPen (QBrush (Qt::black),
529  LINE_WIDTH_THICK));
530  }
531  isAxis = false;
532  }
533 }
534 
536 {
537  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::handleOk";
538 
540  cmdMediator ().document(),
541  *m_modelCoordsBefore,
542  *m_modelCoordsAfter);
543  cmdMediator ().push (cmd);
544 
545  hide ();
546 }
547 
549 {
550  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::load";
551 
552  setCmdMediator (cmdMediator);
553 
554  // Remove if coordinates are log so later constraints can be applied
555  bool isEmpty;
556  QRectF rectGraph = boundingRectGraph (cmdMediator,
557  isEmpty);
558  bool xThetaGoesNegative = !isEmpty && (rectGraph.x() <= 0);
559  bool yRGoesNegative = !isEmpty && (rectGraph.y() <= 0);
560  m_xThetaLinear->setEnabled (!xThetaGoesNegative);
561  m_xThetaLog->setEnabled (!xThetaGoesNegative);
562  m_yRadiusLinear->setEnabled (!yRGoesNegative);
563  m_yRadiusLog->setEnabled (!yRGoesNegative);
564 
565  // Flush old data
566  if (m_modelCoordsBefore != 0) {
567  delete m_modelCoordsBefore;
568  }
569  if (m_modelCoordsAfter != 0) {
570  delete m_modelCoordsAfter;
571  }
572 
573  // Save new data
574  m_modelCoordsBefore = new DocumentModelCoords (cmdMediator.document().modelCoords());
575  m_modelCoordsAfter = new DocumentModelCoords (cmdMediator.document().modelCoords());
576 
577  // Populate controls
578  DlgValidatorFactory dlgValidatorFactory;
579  m_validatorOriginRadius = dlgValidatorFactory.createWithNonPolar (m_modelCoordsAfter->coordScaleYRadius(),
580  m_modelCoordsAfter->coordUnitsRadius(),
581  m_modelCoordsAfter->coordUnitsDate(),
582  m_modelCoordsAfter->coordUnitsTime(),
584  m_editOriginRadius->setValidator (m_validatorOriginRadius); // Set before call to setText so validator is defined in updateControls
585  m_editOriginRadius->setText (QString::number (m_modelCoordsAfter->originRadius ()));
586 
587  if (m_modelCoordsAfter->coordsType() == COORDS_TYPE_CARTESIAN) {
588  m_btnCartesian->setChecked (true);
589  } else {
590  m_btnPolar->setChecked (true);
591  }
592 
593  updateCoordUnits(); // Call after checking m_btnCartesian or m_btnPolar
594  loadComboBoxDate();
595  loadComboBoxTime ();
596 
597  m_xThetaLinear->setChecked (m_modelCoordsAfter->coordScaleXTheta() == COORD_SCALE_LINEAR);
598  m_xThetaLog->setChecked (m_modelCoordsAfter->coordScaleXTheta() == COORD_SCALE_LOG);
599  m_yRadiusLinear->setChecked (m_modelCoordsAfter->coordScaleYRadius() == COORD_SCALE_LINEAR);
600  m_yRadiusLog->setChecked (m_modelCoordsAfter->coordScaleYRadius() == COORD_SCALE_LOG);
601 
602  updateControls (); // Probably redundant due to the setChecked just above
603  enableOk (false); // Disable Ok button since there not yet any changes
604  updatePreview();
605 }
606 
607 void DlgSettingsCoords::loadComboBoxDate()
608 {
609  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::loadComboBoxDate";
610 
611  m_cmbDate->clear ();
612 
613  m_cmbDate->addItem (coordUnitsDateToString (COORD_UNITS_DATE_SKIP),
614  QVariant (COORD_UNITS_DATE_SKIP));
615  m_cmbDate->addItem (coordUnitsDateToString (COORD_UNITS_DATE_MONTH_DAY_YEAR),
616  QVariant (COORD_UNITS_DATE_MONTH_DAY_YEAR));
617  m_cmbDate->addItem (coordUnitsDateToString (COORD_UNITS_DATE_DAY_MONTH_YEAR),
618  QVariant (COORD_UNITS_DATE_DAY_MONTH_YEAR));
619  m_cmbDate->addItem (coordUnitsDateToString (COORD_UNITS_DATE_YEAR_MONTH_DAY),
620  QVariant (COORD_UNITS_DATE_YEAR_MONTH_DAY));
621 
622  ENGAUGE_ASSERT (m_cmbDate->count() == NUM_COORD_UNITS_DATE);
623 
624  int index = m_cmbDate->findData (QVariant (m_modelCoordsAfter->coordUnitsDate()));
625  m_cmbDate->setCurrentIndex (index);
626 }
627 
628 void DlgSettingsCoords::loadComboBoxTime()
629 {
630  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::loadComboBoxTime";
631 
632  m_cmbTime->clear ();
633 
634  m_cmbTime->addItem (coordUnitsTimeToString (COORD_UNITS_TIME_SKIP),
635  QVariant (COORD_UNITS_TIME_SKIP));
636  m_cmbTime->addItem (coordUnitsTimeToString (COORD_UNITS_TIME_HOUR_MINUTE),
637  QVariant (COORD_UNITS_TIME_HOUR_MINUTE));
638  m_cmbTime->addItem (coordUnitsTimeToString (COORD_UNITS_TIME_HOUR_MINUTE_SECOND),
639  QVariant (COORD_UNITS_TIME_HOUR_MINUTE_SECOND));
640 
641  ENGAUGE_ASSERT (m_cmbTime->count() == NUM_COORD_UNITS_TIME);
642 
643  int index = m_cmbTime->findData (QVariant (m_modelCoordsAfter->coordUnitsTime()));
644  m_cmbTime->setCurrentIndex (index);
645 }
646 
647 void DlgSettingsCoords::loadComboBoxUnitsNonPolar (QComboBox &cmb,
648  CoordUnitsNonPolarTheta coordUnits)
649 {
650  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::loadComboBoxUnitsNonPolar";
651 
652  cmb.clear();
653 
654  cmb.addItem (coordUnitsNonPolarThetaToString (COORD_UNITS_NON_POLAR_THETA_NUMBER),
655  QVariant (COORD_UNITS_NON_POLAR_THETA_NUMBER));
656  cmb.addItem (coordUnitsNonPolarThetaToString (COORD_UNITS_NON_POLAR_THETA_DATE_TIME),
657  QVariant (COORD_UNITS_NON_POLAR_THETA_DATE_TIME));
658  cmb.addItem (coordUnitsNonPolarThetaToString (COORD_UNITS_NON_POLAR_THETA_DEGREES_MINUTES_SECONDS),
659  QVariant (COORD_UNITS_NON_POLAR_THETA_DEGREES_MINUTES_SECONDS));
660  cmb.addItem (coordUnitsNonPolarThetaToString (COORD_UNITS_NON_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW),
661  QVariant (COORD_UNITS_NON_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW));
662 
663  ENGAUGE_ASSERT (cmb.count() == NUM_COORD_UNITS_NON_POLAR_THETA);
664 
665  cmb.setWhatsThis (QString (tr ("Numbers have the simplest and most general format.\n\n"
666  "Date and time values have date and/or time components.\n\n"
667  "Degrees Minutes Seconds (DDD MM SS.S) format uses two integer number for degrees and minutes, and a real number for "
668  "seconds. There are 60 seconds per minute. During input, spaces must be inserted between the three numbers.")));
669 
670  int index = cmb.findData (coordUnits);
671  cmb.setCurrentIndex (index);
672 }
673 
674 void DlgSettingsCoords::loadComboBoxUnitsPolar (QComboBox &cmb,
675  CoordUnitsPolarTheta coordUnits)
676 {
677  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::loadComboBoxUnitsPolar";
678 
679  cmb.clear();
680 
681  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_DEGREES),
682  QVariant (COORD_UNITS_POLAR_THETA_DEGREES));
683  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES),
684  QVariant (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES));
685  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS),
686  QVariant (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS));
687  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW),
688  QVariant (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW));
689  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_GRADIANS),
690  QVariant (COORD_UNITS_POLAR_THETA_GRADIANS));
691  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_RADIANS),
692  QVariant (COORD_UNITS_POLAR_THETA_RADIANS));
693  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_TURNS),
694  QVariant (COORD_UNITS_POLAR_THETA_TURNS));
695 
696  ENGAUGE_ASSERT (cmb.count() == NUM_COORD_UNITS_POLAR_THETA);
697 
698  cmb.setWhatsThis (QString (tr ("Degrees (DDD.DDDDD) format uses a single real number. One complete revolution is 360 degrees.\n\n"
699  "Degrees Minutes (DDD MM.MMM) format uses one integer number for degrees, and a real number for minutes. There are "
700  "60 minutes per degree. During input, a space must be inserted between the two numbers.\n\n"
701  "Degrees Minutes Seconds (DDD MM SS.S) format uses two integer number for degrees and minutes, and a real number for "
702  "seconds. There are 60 seconds per minute. During input, spaces must be inserted between the three numbers.\n\n"
703  "Gradians format uses a single real number. One complete revolution is 400 gradians.\n\n"
704  "Radians format uses a single real number. One complete revolution is 2*pi radians.\n\n"
705  "Turns format uses a single real number. One complete revolution is one turn.")));
706 
707  int index = cmb.findData (coordUnits);
708  cmb.setCurrentIndex (index);
709 }
710 
711 void DlgSettingsCoords::resetSceneRectangle ()
712 {
713  QRect rect (CARTESIAN_COORD_MIN - CARTESIAN_COORD_STEP / 2.0,
714  CARTESIAN_COORD_MIN - CARTESIAN_COORD_STEP / 2.0,
715  CARTESIAN_COORD_MAX - CARTESIAN_COORD_MIN + CARTESIAN_COORD_STEP,
716  CARTESIAN_COORD_MAX - CARTESIAN_COORD_MIN + CARTESIAN_COORD_STEP);
717 
718  QGraphicsRectItem *itemPerimeter = new QGraphicsRectItem(rect);
719  itemPerimeter->setVisible(false);
720  m_scenePreview->addItem (itemPerimeter);
721  m_viewPreview->centerOn (QPointF (0.0, 0.0));
722 }
723 
724 void DlgSettingsCoords::slotCartesianPolar (bool)
725 {
726  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotCartesian";
727 
728  if (m_btnCartesian->isChecked ()) {
729  m_modelCoordsAfter->setCoordsType (COORDS_TYPE_CARTESIAN);
730  } else {
731  m_modelCoordsAfter->setCoordsType(COORDS_TYPE_POLAR);
732  }
733  updateCoordUnits();
734  updateControls();
735  updatePreview();
736 }
737 
738 void DlgSettingsCoords::slotDate(const QString &)
739 {
740  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotDate";
741 
742  CoordUnitsDate coordUnits = (CoordUnitsDate) m_cmbDate->currentData ().toInt();
743  m_modelCoordsAfter->setCoordUnitsDate(coordUnits);
744  updateControls();
745  updatePreview();
746 }
747 
748 void DlgSettingsCoords::slotPolarOriginRadius(const QString &)
749 {
750  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotPolarOriginRadius";
751 
752  QString numberText = m_editOriginRadius->text();
753 
754  m_modelCoordsAfter->setOriginRadius(numberText.toDouble ());
755  updateControls();
756  updatePreview();
757 }
758 
759 void DlgSettingsCoords::slotTime(const QString &)
760 {
761  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotTime";
762 
763  CoordUnitsTime coordUnits = (CoordUnitsTime) m_cmbTime->currentData ().toInt();
764  m_modelCoordsAfter->setCoordUnitsTime(coordUnits);
765  updateControls();
766  updatePreview();
767 }
768 
769 void DlgSettingsCoords::slotUnitsXTheta(const QString &)
770 {
771  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotUnitsXTheta";
772 
773  if (m_modelCoordsAfter->coordsType() == COORDS_TYPE_CARTESIAN) {
774  CoordUnitsNonPolarTheta coordUnits = (CoordUnitsNonPolarTheta) m_cmbXThetaUnits->currentData ().toInt ();
775  m_modelCoordsAfter->setCoordUnitsX(coordUnits);
776  } else {
777  CoordUnitsPolarTheta coordUnits = (CoordUnitsPolarTheta) m_cmbXThetaUnits->currentData ().toInt ();
778  m_modelCoordsAfter->setCoordUnitsTheta(coordUnits);
779  }
780  updateControls ();
781  updatePreview();
782 }
783 
784 void DlgSettingsCoords::slotUnitsYRadius(const QString &)
785 {
786  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotUnitsYRadius";
787 
788  CoordUnitsNonPolarTheta coordUnits = (CoordUnitsNonPolarTheta) m_cmbYRadiusUnits->currentData ().toInt ();
789  if (m_modelCoordsAfter->coordsType() == COORDS_TYPE_CARTESIAN) {
790  m_modelCoordsAfter->setCoordUnitsY(coordUnits);
791  } else {
792  m_modelCoordsAfter->setCoordUnitsRadius(coordUnits);
793  }
794  updateControls ();
795  updatePreview();
796 }
797 
798 void DlgSettingsCoords::slotXThetaLinear()
799 {
800  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotXThetaLinear";
801 
802  m_modelCoordsAfter->setCoordScaleXTheta(COORD_SCALE_LINEAR);
803  updateControls ();
804  updatePreview();
805 }
806 
807 void DlgSettingsCoords::slotXThetaLog()
808 {
809  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotXThetaLog";
810 
811  m_modelCoordsAfter->setCoordScaleXTheta(COORD_SCALE_LOG);
812  updateControls ();
813  updatePreview();
814 }
815 
816 void DlgSettingsCoords::slotYRadiusLinear()
817 {
818  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotYRadiusLinear";
819 
820  delete m_validatorOriginRadius;
821 
822  DlgValidatorFactory dlgValidatorFactory;
823  m_validatorOriginRadius = dlgValidatorFactory.createWithNonPolar (COORD_SCALE_LINEAR,
824  m_modelCoordsAfter->coordUnitsRadius(),
825  m_modelCoordsAfter->coordUnitsDate(),
826  m_modelCoordsAfter->coordUnitsTime(),
828  m_editOriginRadius->setValidator (m_validatorOriginRadius);
829 
830  m_modelCoordsAfter->setCoordScaleYRadius((COORD_SCALE_LINEAR));
831  updateControls ();
832  updatePreview();
833 }
834 
835 void DlgSettingsCoords::slotYRadiusLog()
836 {
837  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotYRadiusLog";
838 
839  delete m_validatorOriginRadius;
840 
841  DlgValidatorFactory dlgValidatorFactory;
842  m_validatorOriginRadius = dlgValidatorFactory.createWithNonPolar (COORD_SCALE_LOG,
843  m_modelCoordsAfter->coordUnitsRadius(),
844  m_modelCoordsAfter->coordUnitsDate(),
845  m_modelCoordsAfter->coordUnitsTime(),
847  m_editOriginRadius->setValidator (m_validatorOriginRadius);
848 
849  m_modelCoordsAfter->setCoordScaleYRadius(COORD_SCALE_LOG);
850  updateControls ();
851  updatePreview();
852 }
853 
854 void DlgSettingsCoords::updateControls ()
855 {
856  // LOG4CPP_INFO_S is below
857 
858  QString textOriginRadius = m_editOriginRadius->text();
859  int posOriginRadius = 0;
860 
861  bool goodOriginRadius = true; // Cartesian coordinates do not use origin radius
862  if (m_editOriginRadius->isEnabled ()) {
863 
864  // Origin radius must be greater than zero
865  goodOriginRadius = (m_validatorOriginRadius->validate (textOriginRadius,
866  posOriginRadius) == QValidator::Acceptable);
867  }
868 
869  enableOk (goodOriginRadius);
870 
871  m_boxCoordsType->setEnabled (!m_xThetaLog->isChecked ());
872 
873  m_xThetaLinear->setEnabled (!m_btnPolar->isChecked ());
874  m_xThetaLog->setEnabled (!m_btnPolar->isChecked ());
875  if (m_btnCartesian->isChecked()) {
876  m_yRadiusLinear->setEnabled (true);
877  m_yRadiusLog->setEnabled (true);
878  } else {
879 
880  // Use temporary validator to see if current origin radius would be correct in OTHER linear/log mode
881  DlgValidatorFactory dlgValidatorFactory;
882  DlgValidatorAbstract *dlg = dlgValidatorFactory.createWithNonPolar (m_yRadiusLinear->isChecked () ? COORD_SCALE_LOG : COORD_SCALE_LINEAR,
883  m_modelCoordsAfter->coordUnitsRadius(),
884  m_modelCoordsAfter->coordUnitsDate(),
885  m_modelCoordsAfter->coordUnitsTime(),
887  int posOriginRadiusOther;
888  bool goodOriginRadiusOther = (dlg->validate (textOriginRadius, posOriginRadiusOther) == QValidator::Acceptable);
889 
890  delete dlg; // Deallocate
891 
892  m_yRadiusLinear->setEnabled (goodOriginRadius && goodOriginRadiusOther);
893  m_yRadiusLog->setEnabled (goodOriginRadius && goodOriginRadiusOther);
894  }
895  m_editOriginRadius->setEnabled (m_btnPolar->isChecked ());
896 
897  QString captionXTheta = (m_btnCartesian->isChecked () ?
898  QString (tr ("X")) :
899  THETA) + QString (" %1")
900  .arg (tr ("Coordinates"));
901  QString captionYRadius = (m_btnCartesian->isChecked () ?
902  QString (tr ("Y")) :
903  QString (tr ("R"))) + QString (" %1")
904  .arg (tr ("Coordinates"));
905 
906  if (m_boxXTheta->title() != captionXTheta) {
907  m_boxXTheta->setTitle (captionXTheta);
908  }
909 
910  if (m_boxYRadius->title () != captionYRadius) {
911  m_boxYRadius->setTitle (captionYRadius);
912  }
913 
914  bool enableDateTime;
915  if (m_btnCartesian->isChecked()) {
916  enableDateTime = (((CoordUnitsNonPolarTheta) m_cmbXThetaUnits->currentData ().toInt() == COORD_UNITS_NON_POLAR_THETA_DATE_TIME) ||
917  ((CoordUnitsNonPolarTheta) m_cmbYRadiusUnits->currentData ().toInt() == COORD_UNITS_NON_POLAR_THETA_DATE_TIME));
918  } else {
919  enableDateTime = ((CoordUnitsNonPolarTheta) m_cmbYRadiusUnits->currentData ().toInt() == COORD_UNITS_NON_POLAR_THETA_DATE_TIME);
920  }
921  m_cmbDate->setEnabled (enableDateTime);
922  m_cmbTime->setEnabled (enableDateTime);
923 
924  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::updateControls"
925  << " textOriginRadius=" << textOriginRadius.toLatin1().data()
926  << " goodOriginRadius=" << (goodOriginRadius ? "true" : "false")
927  << " originRadius=" << posOriginRadius
928  << " btnPolarChecked=" << (m_btnPolar->isChecked() ? "true" : "false")
929  << " enableDateTime=" << (enableDateTime ? "true" : "false");
930 }
931 
932 void DlgSettingsCoords::updateCoordUnits()
933 {
934  // X and Y units
935  if (m_btnCartesian->isChecked()) {
936  loadComboBoxUnitsNonPolar (*m_cmbXThetaUnits,
937  m_modelCoordsAfter->coordUnitsX());
938  loadComboBoxUnitsNonPolar (*m_cmbYRadiusUnits,
939  m_modelCoordsAfter->coordUnitsY());
940  } else {
941  loadComboBoxUnitsPolar (*m_cmbXThetaUnits,
942  m_modelCoordsAfter->coordUnitsTheta());
943  loadComboBoxUnitsNonPolar (*m_cmbYRadiusUnits,
944  m_modelCoordsAfter->coordUnitsRadius());
945  }
946 }
947 
948 void DlgSettingsCoords::updatePreview()
949 {
950  m_scenePreview->clear();
951 
952  // General approach
953  // 1) Axis lines are extra thick, but since they sometimes disappear as the preview window is rescaled, we keep the
954  // constant-pixel line under each axis line
955  // 2) Every STEPS_UNHIGHLIGHTED_PER_HIGHLIGHTED out of STEPS_UNHIGHLIGHTED_PER_HIGHLIGHTED+1 lines are dashed to make
956  // them more subtle
957 
958  if (m_btnCartesian->isChecked()) {
959 
960  // Cartesian
961  if (m_xThetaLinear->isChecked()) {
962  drawCartesianLinearX ();
963  } else {
964  drawCartesianLogX ();
965  }
966 
967  if (m_yRadiusLinear->isChecked()) {
968  drawCartesianLinearY ();
969  } else {
970  drawCartesianLogY ();
971  }
972 
973  } else {
974 
975  // Polar
976  drawPolarTheta ();
977  if (m_yRadiusLinear->isChecked()) {
978  drawPolarLinearRadius ();
979  } else {
980  drawPolarLogRadius ();
981  }
982 
983  QFont defaultFont;
984  annotateRadiusAtOrigin (defaultFont);
985  annotateAngles (defaultFont);
986  }
987 
988  resetSceneRectangle();
989 }
void setCoordUnitsTime(CoordUnitsTime coordUnits)
Set method for time units.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
void setCoordUnitsDate(CoordUnitsDate coordUnits)
Set method for date units.
CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void setCoordUnitsY(CoordUnitsNonPolarTheta coordUnits)
Set method for y units.
virtual QValidator::State validate(QString &input, int &pos) const =0
Validate according to the numeric format specific to the leaf class.
void setCoordUnitsX(CoordUnitsNonPolarTheta coordUnits)
Set method for x units.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
double originRadius() const
Get method for origin radius in polar mode.
void setCoordScaleYRadius(CoordScale coordScale)
Set method for linear/log scale on y/radius.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:665
CoordUnitsNonPolarTheta coordUnitsRadius() const
Get method for radius units.
Abstract validator for all numeric formats.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
CoordUnitsTime coordUnitsTime() const
Get method for time format when used.
Command for DlgSettingsCoords.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Definition: ViewPreview.h:14
CoordUnitsNonPolarTheta coordUnitsY() const
Get method for x units.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
QRectF boundingRectGraph(bool &isEmpty) const
Graph coordinate bounding rectangle.
void setCoordUnitsTheta(CoordUnitsPolarTheta coordUnits)
Set method for theta units.
CoordsType coordsType() const
Get method for coordinates type.
CoordUnitsNonPolarTheta coordUnitsX() const
Get method for x units.
Model for DlgSettingsCoords and CmdSettingsCoords.
void setOriginRadius(double originRadius)
Set method for origin radius in polar mode.
CoordUnitsDate coordUnitsDate() const
Get method for date format when used.
void setCoordUnitsRadius(CoordUnitsNonPolarTheta coordUnits)
Set method for radius units.
void finishPanel(QWidget *subPanel)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
static int MINIMUM_PREVIEW_HEIGHT
Dialog layout constant that guarantees preview has sufficent room.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
DlgValidatorAbstract * createWithNonPolar(CoordScale coordScale, CoordUnitsNonPolarTheta coordUnits, CoordUnitsDate coordUnitsDate, CoordUnitsTime coordUnitsTime, const QLocale &locale) const
Factory method for generating validators when cartesian/polar case handling is handled externally...
Command queue stack.
Definition: CmdMediator.h:23
Abstract base class for all Settings dialogs.
Validator factory.
void iterateThroughCurvesPointsGraphs(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for all the graphs curves.
Definition: CmdMediator.cpp:97
void iterateThroughCurvePointsAxes(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for the single axes curve.
Definition: CmdMediator.cpp:87
QLocale locale() const
Get method for locale.
Callback for computing the bounding rectangles of the screen and graph coordinates of the points in t...
MainWindow & mainWindow()
Get method for MainWindow.
virtual void handleOk()
Process slotOk.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:83
MainWindowModel modelMainWindow() const
Get method for main window model.
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
void setCoordScaleXTheta(CoordScale coordScale)
Set method for linear/log scale on x/theta.
DlgSettingsCoords(MainWindow &mainWindow)
Single constructor.
CoordUnitsPolarTheta coordUnitsTheta() const
Get method for theta unit.
void setCoordsType(CoordsType coordsType)
Set method for coordinates type.