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