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