Engauge Digitizer  2
MainWindow.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 "BackgroundImage.h"
8 #include "BackgroundStateContext.h"
9 #include "img/bannerapp_16.xpm"
10 #include "img/bannerapp_32.xpm"
11 #include "img/bannerapp_64.xpm"
12 #include "img/bannerapp_128.xpm"
13 #include "img/bannerapp_256.xpm"
14 #include "ChecklistGuide.h"
15 #include "ChecklistGuideWizard.h"
16 #include "CmdCopy.h"
17 #include "CmdCut.h"
18 #include "CmdDelete.h"
19 #include "CmdMediator.h"
20 #include "CmdSelectCoordSystem.h"
21 #include "CmdStackShadow.h"
22 #include "ColorFilter.h"
23 #include "Curve.h"
24 #include "DataKey.h"
25 #include "DigitizeStateContext.h"
26 #include "DigitAxis.xpm"
27 #include "DigitColorPicker.xpm"
28 #include "DigitCurve.xpm"
29 #include "DigitPointMatch.xpm"
30 #include "DigitScale.xpm"
31 #include "DigitSegment.xpm"
32 #include "DigitSelect.xpm"
33 #include "DlgAbout.h"
34 #include "DlgErrorReportLocal.h"
35 #include "DlgErrorReportNetworking.h"
36 #include "DlgImportAdvanced.h"
37 #include "DlgRequiresTransform.h"
38 #include "DlgSettingsAxesChecker.h"
39 #include "DlgSettingsColorFilter.h"
40 #include "DlgSettingsCoords.h"
41 #include "DlgSettingsCurveAddRemove.h"
42 #include "DlgSettingsCurveProperties.h"
43 #include "DlgSettingsDigitizeCurve.h"
44 #include "DlgSettingsExportFormat.h"
45 #include "DlgSettingsGeneral.h"
46 #include "DlgSettingsGridDisplay.h"
47 #include "DlgSettingsGridRemoval.h"
48 #include "DlgSettingsMainWindow.h"
49 #include "DlgSettingsPointMatch.h"
50 #include "DlgSettingsSegments.h"
51 #include "DocumentSerialize.h"
52 #include "EngaugeAssert.h"
53 #include "EnumsToQt.h"
54 #include "ExportImageForRegression.h"
55 #include "ExportToFile.h"
56 #include "FileCmdScript.h"
57 #include "FittingCurve.h"
58 #include "FittingWindow.h"
59 #include "GeometryWindow.h"
60 #include "Ghosts.h"
61 #include "GraphicsItemsExtractor.h"
62 #include "GraphicsItemType.h"
63 #include "GraphicsScene.h"
64 #include "GraphicsView.h"
65 #include "GridLineFactory.h"
66 #include "GridLineLimiter.h"
67 #include "HelpWindow.h"
68 #ifdef ENGAUGE_JPEG2000
69 #include "Jpeg2000.h"
70 #endif // ENGAUGE_JPEG2000
71 #include "LoadFileInfo.h"
72 #ifdef NETWORKING
73 #include "LoadImageFromUrl.h"
74 #endif
75 #include "Logger.h"
76 #include "MainTitleBarFormat.h"
77 #include "MainWindow.h"
78 #ifdef NETWORKING
79 #include "NetworkClient.h"
80 #endif
81 #include "NonPdf.h"
82 #ifdef ENGAUGE_PDF
83 #include "Pdf.h"
84 #endif // ENGAUGE_PDF
85 #include "PdfResolution.h"
86 #include <QAction>
87 #include <QApplication>
88 #include <QCloseEvent>
89 #include <QComboBox>
90 #include <QDebug>
91 #include <QDesktopServices>
92 #include <QDockWidget>
93 #include <QDomDocument>
94 #include <QKeyEvent>
95 #include <QFileDialog>
96 #include <QFileInfo>
97 #include <QGraphicsLineItem>
98 #include <QImageReader>
99 #include <QKeyEvent>
100 #include <QKeySequence>
101 #include <QLabel>
102 #include <QMenu>
103 #include <QMenuBar>
104 #include <QMessageBox>
105 #include <QMouseEvent>
106 #include <QPrintDialog>
107 #include <QPrinter>
108 #include <QSettings>
109 #include <QTextStream>
110 #include <QtHelp>
111 #include <QTimer>
112 #include <QToolBar>
113 #include <QToolButton>
114 #include "QtToString.h"
115 #include <QVBoxLayout>
116 #include <QWhatsThis>
117 #include <QXmlStreamReader>
118 #include <QXmlStreamWriter>
119 #include "ScaleBarAxisPointsUnite.h"
120 #include "Settings.h"
121 #include "StatusBar.h"
122 #include "TransformationStateContext.h"
123 #include "TutorialDlg.h"
124 #include "Version.h"
125 #include "ViewPointStyle.h"
126 #include "ViewSegmentFilter.h"
127 #include "ZoomFactor.h"
128 #include "ZoomFactorInitial.h"
129 
130 const QString EMPTY_FILENAME ("");
131 const char *ENGAUGE_FILENAME_DESCRIPTION = "Engauge Document";
132 const QString ENGAUGE_FILENAME_EXTENSION ("dig");
133 const int REGRESSION_INTERVAL = 400; // Milliseconds
134 const unsigned int MAX_RECENT_FILE_LIST_SIZE = 8;
135 
136 MainWindow::MainWindow(const QString &errorReportFile,
137  const QString &fileCmdScriptFile,
138  bool isRegressionTest,
139  bool isGnuplot,
140  bool isReset,
141  QStringList loadStartupFiles,
142  QWidget *parent) :
143  QMainWindow(parent),
144  m_isDocumentExported (false),
145  m_engaugeFile (EMPTY_FILENAME),
146  m_currentFile (EMPTY_FILENAME),
147  m_layout (0),
148  m_scene (0),
149  m_view (0),
150  m_loadImageFromUrl (0),
151  m_cmdMediator (0),
152  m_digitizeStateContext (0),
153  m_transformationStateContext (0),
154  m_backgroundStateContext (0),
155  m_networkClient (0),
156  m_isGnuplot (isGnuplot),
157  m_ghosts (0),
158  m_timerRegressionErrorReport(0),
159  m_fileCmdScript (0),
160  m_isErrorReportRegressionTest (isRegressionTest),
161  m_timerRegressionFileCmdScript(0),
162  m_fittingCurve (0)
163 {
164  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::MainWindow"
165  << " curDir=" << QDir::currentPath().toLatin1().data();
166 
167 #if defined(OSX_DEBUG) || defined(OSX_RELEASE)
168  qApp->setApplicationName ("Engauge Digitizer");
169  qApp->setOrganizationDomain ("Mark Mitchell");
170 #endif
171 
173 
174  m_startupDirectory = QDir::currentPath();
175 
176  setCurrentFile ("");
177  createIcons();
178  setWindowFlags (Qt::WindowContextHelpButtonHint | windowFlags ()); // Add help to default buttons
179  setWindowTitle (engaugeWindowTitle ());
180 
181  createCentralWidget();
182  createActions ();
183  createStatusBar ();
184  createMenus ();
185  createToolBars ();
186  createDockableWidgets ();
187  createHelpWindow ();
188  createTutorial ();
189  createScene ();
190  createNetwork ();
191  createLoadImageFromUrl ();
192  createStateContextBackground ();
193  createStateContextDigitize ();
194  createStateContextTransformation ();
195  createSettingsDialogs ();
196  createCommandStackShadow ();
197  createZoomMap ();
198  updateControls ();
199 
200  settingsRead (isReset); // This changes the current directory when not regression testing
201  setCurrentFile ("");
202  setUnifiedTitleAndToolBarOnMac(true);
203 
204  installEventFilter(this);
205 
206  // Start regression scripting if appropriate. Regression scripts assume current directory is the original
207  // current directory, so we temporarily reset the current directory
208  QString originalPath = QDir::currentPath();
209  QDir::setCurrent (m_startupDirectory);
210  if (!errorReportFile.isEmpty()) {
211  loadErrorReportFile(errorReportFile);
212  if (m_isErrorReportRegressionTest) {
213  startRegressionTestErrorReport(errorReportFile);
214  }
215  } else if (!fileCmdScriptFile.isEmpty()) {
216  m_fileCmdScript = new FileCmdScript (fileCmdScriptFile);
217  startRegressionTestFileCmdScript();
218  } else {
219 
220  // Save file names for later, after gui becomes available. The file names are dropped if error report file is specified
221  // since only one of the two modes is available at any time, for simplicity
222  m_loadStartupFiles = loadStartupFiles;
223  }
224  QDir::setCurrent (originalPath);
225 }
226 
227 MainWindow::~MainWindow()
228 {
229 }
230 
231 void MainWindow::addDockWindow (QDockWidget *dockWidget,
232  QSettings &settings,
233  const QString &settingsTokenArea,
234  const QString &settingsTokenGeometry,
235  Qt::DockWidgetArea dockWidgetArea)
236 {
237  // Checklist guide is docked or undocked. Default is docked so it does not get overlooked by the user (which
238  // can happen if it opens elsewhere). The user may not know it can be undocked, but at least can resize or
239  // hide it if he/she needs more room for the main window.
240  const bool DOCKED_EQUALS_NOT_FLOATING = false;
241  Qt::DockWidgetArea area = (Qt::DockWidgetArea) settings.value (settingsTokenArea,
242  Qt::NoDockWidgetArea).toInt();
243 
244  if (area == Qt::NoDockWidgetArea) {
245 
246  addDockWidget (dockWidgetArea,
247  dockWidget); // Add on the right to prevent error message, then immediately make undocked
248  dockWidget->setFloating(DOCKED_EQUALS_NOT_FLOATING);
249  if (settings.contains (settingsTokenGeometry)) {
250  dockWidget->restoreGeometry (settings.value (settingsTokenGeometry).toByteArray());
251  }
252 
253  } else {
254 
255  addDockWidget (area,
256  dockWidget);
257 
258  }
259 }
260 
261 void MainWindow::applyZoomFactorAfterLoad()
262 {
263  ZoomFactor zoomFactor;
264  ZoomFactorInitial zoomFactorInitial = m_modelMainWindow.zoomFactorInitial();
265 
266  if (m_zoomMap.contains (zoomFactorInitial)) {
267  zoomFactor = m_zoomMap [zoomFactorInitial];
268  } else if (zoomFactorInitial == ZOOM_INITIAL_PREVIOUS) {
269  zoomFactor = currentZoomFactor ();
270  } else {
271  ENGAUGE_ASSERT (false);
272  zoomFactor = currentZoomFactor();
273  }
274 
275  slotViewZoom (zoomFactor);
276 }
277 
278 void MainWindow::closeEvent(QCloseEvent *event)
279 {
280  if (maybeSave()) {
281  settingsWrite ();
282  event->accept ();
283  } else {
284  event->ignore ();
285  }
286 }
287 
289 {
290  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileClose";
291 
292  setWindowModified (false); // Prevent popup query asking if changes should be saved
293  slotFileClose();
294 }
295 
296 void MainWindow::cmdFileExport(const QString &fileName)
297 {
298  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileExport";
299 
300  ExportToFile exportStrategy;
301  fileExport(fileName,
302  exportStrategy);
303 }
304 
305 void MainWindow::cmdFileImport(const QString &fileName)
306 {
307  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileImport";
308 
309  m_regressionFile = exportFilenameFromInputFilename (fileName);
310  fileImport (fileName,
311  IMPORT_TYPE_SIMPLE);
312 }
313 
314 void MainWindow::cmdFileOpen(const QString &fileName)
315 {
316  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileOpen";
317 
318  m_regressionFile = exportFilenameFromInputFilename (fileName);
319  loadDocumentFile(fileName);
320 }
321 
323 {
324  // We do not check m_cmdMediator with ENGAUGE_CHECK_PTR since calling code is expected to deal with null pointer at startup
325  return m_cmdMediator;
326 }
327 
328 void MainWindow::createActions()
329 {
330  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActions";
331 
332  createActionsFile ();
333  createActionsEdit ();
334  createActionsDigitize ();
335  createActionsView ();
336  createActionsSettings ();
337  createActionsHelp ();
338 }
339 
340 void MainWindow::createActionsDigitize ()
341 {
342  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsDigitize";
343 
344  QPixmap pixmapAxis (DigitAxis_xpm);
345  QPixmap pixmapCurve (DigitCurve_xpm);
346  QPixmap pixmapColorPicker (DigitColorPicker_xpm);
347  QPixmap pixmapPointMatch (DigitPointMatch_xpm);
348  QPixmap pixmapScale (DigitScale_xpm);
349  QPixmap pixmapSegment (DigitSegment_xpm);
350  QPixmap pixmapSelect (DigitSelect_xpm);
351 
352  QIcon iconAxis (pixmapAxis);
353  QIcon iconCurve (pixmapCurve);
354  QIcon iconColorPicker (pixmapColorPicker);
355  QIcon iconPointMatch (pixmapPointMatch);
356  QIcon iconScale (pixmapScale);
357  QIcon iconSegment (pixmapSegment);
358  QIcon iconSelect (pixmapSelect);
359 
360  m_actionDigitizeSelect = new QAction (iconSelect, tr ("Select Tool"), this);
361  m_actionDigitizeSelect->setShortcut (QKeySequence (tr ("Shift+F2")));
362  m_actionDigitizeSelect->setCheckable (true);
363  m_actionDigitizeSelect->setStatusTip (tr ("Select points on screen."));
364  m_actionDigitizeSelect->setWhatsThis (tr ("Select\n\n"
365  "Select points on the screen."));
366  connect (m_actionDigitizeSelect, SIGNAL (triggered ()), this, SLOT (slotDigitizeSelect ()));
367 
368  m_actionDigitizeAxis = new QAction (iconAxis, tr ("Axis Point Tool"), this);
369  m_actionDigitizeAxis->setShortcut (QKeySequence (tr ("Shift+F3")));
370  m_actionDigitizeAxis->setCheckable (true);
371  m_actionDigitizeAxis->setStatusTip (tr ("Digitize axis points for a graph."));
372  m_actionDigitizeAxis->setWhatsThis (tr ("Digitize Axis Point\n\n"
373  "Digitizes an axis point for a graph by placing a new point at the cursor "
374  "after a mouse click. The coordinates of the axis point are then "
375  "entered. In a graph, three axis points are required to define "
376  "the graph coordinates."));
377  connect (m_actionDigitizeAxis, SIGNAL (triggered ()), this, SLOT (slotDigitizeAxis ()));
378 
379  m_actionDigitizeScale = new QAction (iconScale, tr ("Scale Bar Tool"), this);
380  m_actionDigitizeScale->setShortcut (QKeySequence (tr ("Shift+F8")));
381  m_actionDigitizeScale->setCheckable (true);
382  m_actionDigitizeScale->setStatusTip (tr ("Digitize scale bar for a map."));
383  m_actionDigitizeScale->setWhatsThis (tr ("Digitize Scale Bar\n\n"
384  "Digitize a scale bar for a map by clicking and dragging. The length of the "
385  "scale bar is then entered. In a map, the two endpoints of the scale "
386  "bar define the distances in graph coordinates.\n\n"
387  "Maps must be imported using Import (Advanced)."));
388  connect (m_actionDigitizeScale, SIGNAL (triggered ()), this, SLOT (slotDigitizeScale ()));
389 
390  m_actionDigitizeCurve = new QAction (iconCurve, tr ("Curve Point Tool"), this);
391  m_actionDigitizeCurve->setShortcut (QKeySequence (tr ("Shift+F4")));
392  m_actionDigitizeCurve->setCheckable (true);
393  m_actionDigitizeCurve->setStatusTip (tr ("Digitize curve points."));
394  m_actionDigitizeCurve->setWhatsThis (tr ("Digitize Curve Point\n\n"
395  "Digitizes a curve point by placing a new point at the cursor "
396  "after a mouse click. Use this mode to digitize points along curves "
397  "one by one.\n\n"
398  "New points will be assigned to the currently selected curve."));
399  connect (m_actionDigitizeCurve, SIGNAL (triggered ()), this, SLOT (slotDigitizeCurve ()));
400 
401  m_actionDigitizePointMatch = new QAction (iconPointMatch, tr ("Point Match Tool"), this);
402  m_actionDigitizePointMatch->setShortcut (QKeySequence (tr ("Shift+F5")));
403  m_actionDigitizePointMatch->setCheckable (true);
404  m_actionDigitizePointMatch->setStatusTip (tr ("Digitize curve points in a point plot by matching a point."));
405  m_actionDigitizePointMatch->setWhatsThis (tr ("Digitize Curve Points by Point Matching\n\n"
406  "Digitizes curve points in a point plot by finding points that match a sample point. The process "
407  "starts by selecting a representative sample point.\n\n"
408  "New points will be assigned to the currently selected curve."));
409  connect (m_actionDigitizePointMatch, SIGNAL (triggered ()), this, SLOT (slotDigitizePointMatch ()));
410 
411  m_actionDigitizeColorPicker = new QAction (iconColorPicker, tr ("Color Picker Tool"), this);
412  m_actionDigitizeColorPicker->setShortcut (QKeySequence (tr ("Shift+F6")));
413  m_actionDigitizeColorPicker->setCheckable (true);
414  m_actionDigitizeColorPicker->setStatusTip (tr ("Select color settings for filtering in Segment Fill mode."));
415  m_actionDigitizeColorPicker->setWhatsThis (tr ("Select color settings for Segment Fill filtering\n\n"
416  "Select a pixel along the currently selected curve. That pixel and its neighbors will "
417  "define the filter settings (color, brightness, and so on) of the currently selected curve "
418  "while in Segment Fill mode."));
419  connect (m_actionDigitizeColorPicker, SIGNAL (triggered ()), this, SLOT (slotDigitizeColorPicker ()));
420 
421  m_actionDigitizeSegment = new QAction (iconSegment, tr ("Segment Fill Tool"), this);
422  m_actionDigitizeSegment->setShortcut (QKeySequence (tr ("Shift+F7")));
423  m_actionDigitizeSegment->setCheckable (true);
424  m_actionDigitizeSegment->setStatusTip (tr ("Digitize curve points along a segment of a curve."));
425  m_actionDigitizeSegment->setWhatsThis (tr ("Digitize Curve Points With Segment Fill\n\n"
426  "Digitizes curve points by placing new points along the highlighted "
427  "segment under the cursor. Use this mode to quickly digitize multiple points along a "
428  "curve with a single click.\n\n"
429  "New points will be assigned to the currently selected curve."));
430  connect (m_actionDigitizeSegment, SIGNAL (triggered ()), this, SLOT (slotDigitizeSegment ()));
431 
432  m_groupDigitize = new QActionGroup (this);
433  m_groupDigitize->addAction (m_actionDigitizeSelect);
434  m_groupDigitize->addAction (m_actionDigitizeAxis);
435  m_groupDigitize->addAction (m_actionDigitizeScale);
436  m_groupDigitize->addAction (m_actionDigitizeCurve);
437  m_groupDigitize->addAction (m_actionDigitizePointMatch);
438  m_groupDigitize->addAction (m_actionDigitizeColorPicker);
439  m_groupDigitize->addAction (m_actionDigitizeSegment);
440 }
441 
442 void MainWindow::createActionsEdit ()
443 {
444  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsEdit";
445 
446  m_actionEditUndo = new QAction(tr ("&Undo"), this);
447  m_actionEditUndo->setShortcut (QKeySequence::Undo);
448  m_actionEditUndo->setStatusTip (tr ("Undo the last operation."));
449  m_actionEditUndo->setWhatsThis (tr ("Undo\n\n"
450  "Undo the last operation."));
451  // connect is applied when CmdMediator appears
452 
453  m_actionEditRedo = new QAction(tr ("&Redo"), this);
454  m_actionEditRedo->setShortcut (QKeySequence::Redo);
455  m_actionEditRedo->setStatusTip (tr ("Redo the last operation."));
456  m_actionEditRedo->setWhatsThis (tr ("Redo\n\n"
457  "Redo the last operation."));
458  // connect is applied when CmdMediator appears
459 
460  m_actionEditCut = new QAction (tr ("Cut"), this);
461  m_actionEditCut->setShortcut (QKeySequence::Cut);
462  m_actionEditCut->setStatusTip (tr ("Cuts the selected points and copies them to the clipboard."));
463  m_actionEditCut->setWhatsThis (tr ("Cut\n\n"
464  "Cuts the selected points and copies them to the clipboard."));
465  connect (m_actionEditCut, SIGNAL (triggered ()), this, SLOT (slotEditCut ()));
466 
467  m_actionEditCopy = new QAction (tr ("Copy"), this);
468  m_actionEditCopy->setShortcut (QKeySequence::Copy);
469  m_actionEditCopy->setStatusTip (tr ("Copies the selected points to the clipboard."));
470  m_actionEditCopy->setWhatsThis (tr ("Copy\n\n"
471  "Copies the selected points to the clipboard."));
472  connect (m_actionEditCopy, SIGNAL (triggered ()), this, SLOT (slotEditCopy ()));
473 
474  m_actionEditPaste = new QAction (tr ("Paste"), this);
475  m_actionEditPaste->setShortcut (QKeySequence::Paste);
476  m_actionEditPaste->setStatusTip (tr ("Pastes the selected points from the clipboard."));
477  m_actionEditPaste->setWhatsThis (tr ("Paste\n\n"
478  "Pastes the selected points from the clipboard. They will be assigned to the current curve."));
479  connect (m_actionEditPaste, SIGNAL (triggered ()), this, SLOT (slotEditPaste ()));
480 
481  m_actionEditDelete = new QAction (tr ("Delete"), this);
482  m_actionEditDelete->setShortcut (QKeySequence::Delete);
483  m_actionEditDelete->setStatusTip (tr ("Deletes the selected points, after copying them to the clipboard."));
484  m_actionEditDelete->setWhatsThis (tr ("Delete\n\n"
485  "Deletes the selected points, after copying them to the clipboard."));
486  connect (m_actionEditDelete, SIGNAL (triggered ()), this, SLOT (slotEditDelete ()));
487 
488  m_actionEditPasteAsNew = new QAction (tr ("Paste As New"), this);
489  m_actionEditPasteAsNew->setStatusTip (tr ("Pastes an image from the clipboard."));
490  m_actionEditPasteAsNew->setWhatsThis (tr ("Paste as New\n\n"
491  "Creates a new document by pasting an image from the clipboard."));
492  connect (m_actionEditPasteAsNew, SIGNAL (triggered ()), this, SLOT (slotEditPasteAsNew ()));
493 
494  m_actionEditPasteAsNewAdvanced = new QAction (tr ("Paste As New (Advanced)..."), this);
495  m_actionEditPasteAsNewAdvanced->setStatusTip (tr ("Pastes an image from the clipboard, in advanced mode."));
496  m_actionEditPasteAsNewAdvanced->setWhatsThis (tr ("Paste as New (Advanced)\n\n"
497  "Creates a new document by pasting an image from the clipboard, in advanced mode."));
498  connect (m_actionEditPasteAsNewAdvanced, SIGNAL (triggered ()), this, SLOT (slotEditPasteAsNewAdvanced ()));
499 }
500 
501 void MainWindow::createActionsFile ()
502 {
503  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsFile";
504 
505  m_actionImport = new QAction(tr ("&Import..."), this);
506  m_actionImport->setShortcut (tr ("Ctrl+I"));
507  m_actionImport->setStatusTip (tr ("Creates a new document by importing an simple image."));
508  m_actionImport->setWhatsThis (tr ("Import Image\n\n"
509  "Creates a new document by importing an image with a single coordinate system, "
510  "and axes both coordinates known.\n\n"
511  "For more complicated images with multiple coordinate systems, "
512  "and/or floating axes, Import (Advanced) is used instead."));
513  connect (m_actionImport, SIGNAL (triggered ()), this, SLOT (slotFileImport ()));
514 
515  m_actionImportAdvanced = new QAction(tr ("Import (Advanced)..."), this);
516  m_actionImportAdvanced->setStatusTip (tr ("Creates a new document by importing an image with support for advanced feaures."));
517  m_actionImportAdvanced->setWhatsThis (tr ("Import (Advanced)\n\n"
518  "Creates a new document by importing an image with support for advanced feaures. In "
519  "advanced mode, there can be multiple coordinate systems and/or floating axes."));
520  connect (m_actionImportAdvanced, SIGNAL (triggered ()), this, SLOT (slotFileImportAdvanced ()));
521 
522  m_actionImportImageReplace = new QAction (tr ("Import (Image Replace)..."), this);
523  m_actionImportImageReplace->setStatusTip (tr ("Imports a new image into the current document, replacing the existing image."));
524  m_actionImportImageReplace->setWhatsThis (tr ("Import (Image Replace)\n\n"
525  "Imports a new image into the current document. The existing image is replaced, "
526  "and all curves in the document are preserved. This operation is useful for applying "
527  "the axis points and other settings from an existing document to a different image."));
528  connect (m_actionImportImageReplace, SIGNAL (triggered ()), this, SLOT (slotFileImportImageReplace ()));
529 
530  m_actionOpen = new QAction(tr ("&Open..."), this);
531  m_actionOpen->setShortcut (QKeySequence::Open);
532  m_actionOpen->setStatusTip (tr ("Opens an existing document."));
533  m_actionOpen->setWhatsThis (tr ("Open Document\n\n"
534  "Opens an existing document."));
535  connect (m_actionOpen, SIGNAL (triggered ()), this, SLOT (slotFileOpen ()));
536 
537 #ifndef OSX_RELEASE
538  for (unsigned int i = 0; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
539  QAction *recentFileAction = new QAction (this);
540  recentFileAction->setVisible (true);
541  connect (recentFileAction, SIGNAL (triggered ()), this, SLOT (slotRecentFileAction ()));
542  m_actionRecentFiles.append (recentFileAction);
543  }
544 #endif
545 
546  m_actionClose = new QAction(tr ("&Close"), this);
547  m_actionClose->setShortcut (QKeySequence::Close);
548  m_actionClose->setStatusTip (tr ("Closes the open document."));
549  m_actionClose->setWhatsThis (tr ("Close Document\n\n"
550  "Closes the open document."));
551  connect (m_actionClose, SIGNAL (triggered ()), this, SLOT (slotFileClose ()));
552 
553  m_actionSave = new QAction(tr ("&Save"), this);
554  m_actionSave->setShortcut (QKeySequence::Save);
555  m_actionSave->setStatusTip (tr ("Saves the current document."));
556  m_actionSave->setWhatsThis (tr ("Save Document\n\n"
557  "Saves the current document."));
558  connect (m_actionSave, SIGNAL (triggered ()), this, SLOT (slotFileSave ()));
559 
560  m_actionSaveAs = new QAction(tr ("Save As..."), this);
561  m_actionSaveAs->setShortcut (QKeySequence::SaveAs);
562  m_actionSaveAs->setStatusTip (tr ("Saves the current document under a new filename."));
563  m_actionSaveAs->setWhatsThis (tr ("Save Document As\n\n"
564  "Saves the current document under a new filename."));
565  connect (m_actionSaveAs, SIGNAL (triggered ()), this, SLOT (slotFileSaveAs ()));
566 
567  m_actionExport = new QAction (tr ("Export..."), this);
568  m_actionExport->setShortcut (tr ("Ctrl+E"));
569  m_actionExport->setStatusTip (tr ("Exports the current document into a text file."));
570  m_actionExport->setWhatsThis (tr ("Export Document\n\n"
571  "Exports the current document into a text file."));
572  connect (m_actionExport, SIGNAL (triggered ()), this, SLOT (slotFileExport ()));
573 
574  m_actionPrint = new QAction (tr ("&Print..."), this);
575  m_actionPrint->setShortcut (QKeySequence::Print);
576  m_actionPrint->setStatusTip (tr ("Print the current document."));
577  m_actionPrint->setWhatsThis (tr ("Print Document\n\n"
578  "Print the current document to a printer or file."));
579  connect (m_actionPrint, SIGNAL (triggered ()), this, SLOT (slotFilePrint ()));
580 
581  m_actionExit = new QAction(tr ("&Exit"), this);
582  m_actionExit->setShortcut (QKeySequence::Quit);
583  m_actionExit->setStatusTip (tr ("Quits the application."));
584  m_actionExit->setWhatsThis (tr ("Exit\n\n"
585  "Quits the application."));
586  connect (m_actionExit, SIGNAL (triggered ()), this, SLOT (close ()));
587 }
588 
589 void MainWindow::createActionsHelp ()
590 {
591  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsHelp";
592 
593  m_actionHelpChecklistGuideWizard = new QAction (tr ("Checklist Guide Wizard"), this);
594  m_actionHelpChecklistGuideWizard->setCheckable (true);
595  m_actionHelpChecklistGuideWizard->setStatusTip (tr ("Open Checklist Guide Wizard during import to define digitizing steps"));
596  m_actionHelpChecklistGuideWizard->setWhatsThis (tr ("Checklist Guide Wizard\n\n"
597  "Use Checklist Guide Wizard during import to generate a checklist of steps "
598  "for the imported document"));
599 
600  m_actionHelpWhatsThis = QWhatsThis::createAction(this);
601  m_actionHelpWhatsThis->setShortcut (QKeySequence::WhatsThis);
602 
603  m_actionHelpTutorial = new QAction (tr ("Tutorial"), this);
604  m_actionHelpTutorial->setStatusTip (tr ("Play tutorial showing steps for digitizing curves"));
605  m_actionHelpTutorial->setWhatsThis (tr ("Tutorial\n\n"
606  "Play tutorial showing steps for digitizing points from curves drawn with lines "
607  "and/or point"));
608  connect (m_actionHelpTutorial, SIGNAL (triggered ()), this, SLOT (slotHelpTutorial()));
609 
610 #ifndef OSX_RELEASE
611  m_actionHelpHelp = new QAction (tr ("Help"), this);
612  m_actionHelpHelp->setShortcut (QKeySequence::HelpContents);
613  m_actionHelpHelp->setStatusTip (tr ("Help documentation"));
614  m_actionHelpHelp->setWhatsThis (tr ("Help Documentation\n\n"
615  "Searchable help documentation"));
616  // This action gets connected directly to the QDockWidget when that is created
617 #endif
618 
619  m_actionHelpAbout = new QAction(tr ("About Engauge"), this);
620  m_actionHelpAbout->setStatusTip (tr ("About the application."));
621  m_actionHelpAbout->setWhatsThis (tr ("About Engauge\n\nAbout the application."));
622  connect (m_actionHelpAbout, SIGNAL (triggered ()), this, SLOT (slotHelpAbout ()));
623 }
624 
625 void MainWindow::createActionsSettings ()
626 {
627  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsSettings";
628 
629  m_actionSettingsCoords = new QAction (tr ("Coordinates..."), this);
630  m_actionSettingsCoords->setStatusTip (tr ("Edit Coordinate settings."));
631  m_actionSettingsCoords->setWhatsThis (tr ("Coordinate Settings\n\n"
632  "Coordinate settings determine how the graph coordinates are mapped to the pixels in the image"));
633  connect (m_actionSettingsCoords, SIGNAL (triggered ()), this, SLOT (slotSettingsCoords ()));
634 
635  m_actionSettingsCurveAddRemove = new QAction (tr ("Add/Remove Curve..."), this);
636  m_actionSettingsCurveAddRemove->setStatusTip (tr ("Add or Remove Curves."));
637  m_actionSettingsCurveAddRemove->setWhatsThis (tr ("Add/Remove Curve\n\n"
638  "Add/Remove Curve settings control which curves are included in the current document"));
639  connect (m_actionSettingsCurveAddRemove, SIGNAL (triggered ()), this, SLOT (slotSettingsCurveAddRemove ()));
640 
641  m_actionSettingsCurveProperties = new QAction (tr ("Curve Properties..."), this);
642  m_actionSettingsCurveProperties->setStatusTip (tr ("Edit Curve Properties settings."));
643  m_actionSettingsCurveProperties->setWhatsThis (tr ("Curve Properties Settings\n\n"
644  "Curves properties settings determine how each curve appears"));
645  connect (m_actionSettingsCurveProperties, SIGNAL (triggered ()), this, SLOT (slotSettingsCurveProperties ()));
646 
647  m_actionSettingsDigitizeCurve = new QAction (tr ("Digitize Curve..."), this);
648  m_actionSettingsDigitizeCurve->setStatusTip (tr ("Edit Digitize Axis and Graph Curve settings."));
649  m_actionSettingsDigitizeCurve->setWhatsThis (tr ("Digitize Axis and Graph Curve Settings\n\n"
650  "Digitize Curve settings determine how points are digitized in Digitize Axis Point and "
651  "Digitize Graph Point modes"));
652  connect (m_actionSettingsDigitizeCurve, SIGNAL (triggered ()), this, SLOT (slotSettingsDigitizeCurve ()));
653 
654  m_actionSettingsExport = new QAction (tr ("Export Format..."), this);
655  m_actionSettingsExport->setStatusTip (tr ("Edit Export Format settings."));
656  m_actionSettingsExport->setWhatsThis (tr ("Export Format Settings\n\n"
657  "Export format settings affect how exported files are formatted"));
658  connect (m_actionSettingsExport, SIGNAL (triggered ()), this, SLOT (slotSettingsExportFormat ()));
659 
660  m_actionSettingsColorFilter = new QAction (tr ("Color Filter..."), this);
661  m_actionSettingsColorFilter->setStatusTip (tr ("Edit Color Filter settings."));
662  m_actionSettingsColorFilter->setWhatsThis (tr ("Color Filter Settings\n\n"
663  "Color filtering simplifies the graphs for easier Point Matching and Segment Filling"));
664  connect (m_actionSettingsColorFilter, SIGNAL (triggered ()), this, SLOT (slotSettingsColorFilter ()));
665 
666  m_actionSettingsAxesChecker = new QAction (tr ("Axes Checker..."), this);
667  m_actionSettingsAxesChecker->setStatusTip (tr ("Edit Axes Checker settings."));
668  m_actionSettingsAxesChecker->setWhatsThis (tr ("Axes Checker Settings\n\n"
669  "Axes checker can reveal any axis point mistakes, which are otherwise hard to find."));
670  connect (m_actionSettingsAxesChecker, SIGNAL (triggered ()), this, SLOT (slotSettingsAxesChecker ()));
671 
672  m_actionSettingsGridDisplay = new QAction (tr ("Grid Line Display..."), this);
673  m_actionSettingsGridDisplay->setStatusTip (tr ("Edit Grid Line Display settings."));
674  m_actionSettingsGridDisplay->setWhatsThis (tr ("Grid Line Display Settings\n\n"
675  "Grid lines displayed on the graph can provide more accuracy than the Axis Checker, for distorted graphs. "
676  "In a distorted graph, the grid lines can be used to adjust the axis points for more accuracy in different regions."));
677  connect (m_actionSettingsGridDisplay, SIGNAL (triggered ()), this, SLOT (slotSettingsGridDisplay ()));
678 
679  m_actionSettingsGridRemoval = new QAction (tr ("Grid Line Removal..."), this);
680  m_actionSettingsGridRemoval->setStatusTip (tr ("Edit Grid Line Removal settings."));
681  m_actionSettingsGridRemoval->setWhatsThis (tr ("Grid Line Removal Settings\n\n"
682  "Grid line removal isolates curve lines for easier Point Matching and Segment Filling, when "
683  "Color Filtering is not able to separate grid lines from curve lines."));
684  connect (m_actionSettingsGridRemoval, SIGNAL (triggered ()), this, SLOT (slotSettingsGridRemoval ()));
685 
686  m_actionSettingsPointMatch = new QAction (tr ("Point Match..."), this);
687  m_actionSettingsPointMatch->setStatusTip (tr ("Edit Point Match settings."));
688  m_actionSettingsPointMatch->setWhatsThis (tr ("Point Match Settings\n\n"
689  "Point match settings determine how points are matched while in Point Match mode"));
690  connect (m_actionSettingsPointMatch, SIGNAL (triggered ()), this, SLOT (slotSettingsPointMatch ()));
691 
692  m_actionSettingsSegments = new QAction (tr ("Segment Fill..."), this);
693  m_actionSettingsSegments->setStatusTip (tr ("Edit Segment Fill settings."));
694  m_actionSettingsSegments->setWhatsThis (tr ("Segment Fill Settings\n\n"
695  "Segment fill settings determine how points are generated in the Segment Fill mode"));
696  connect (m_actionSettingsSegments, SIGNAL (triggered ()), this, SLOT (slotSettingsSegments ()));
697 
698  m_actionSettingsGeneral = new QAction (tr ("General..."), this);
699  m_actionSettingsGeneral->setStatusTip (tr ("Edit General settings."));
700  m_actionSettingsGeneral->setWhatsThis (tr ("General Settings\n\n"
701  "General settings are document-specific settings that affect multiple modes. For example, the cursor size setting affects "
702  "both Color Picker and Point Match modes"));
703  connect (m_actionSettingsGeneral, SIGNAL (triggered ()), this, SLOT (slotSettingsGeneral ()));
704 
705  m_actionSettingsMainWindow = new QAction (tr ("Main Window..."), this);
706  m_actionSettingsMainWindow->setEnabled (true);
707  m_actionSettingsMainWindow->setStatusTip (tr ("Edit Main Window settings."));
708  m_actionSettingsMainWindow->setWhatsThis (tr ("Main Window Settings\n\n"
709  "Main window settings affect the user interface and are not specific to any document"));
710  connect (m_actionSettingsMainWindow, SIGNAL (triggered ()), this, SLOT (slotSettingsMainWindow ()));
711 }
712 
713 void MainWindow::createActionsView ()
714 {
715  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsView";
716 
717  m_actionViewBackground = new QAction (tr ("Background Toolbar"), this);
718  m_actionViewBackground->setCheckable (true);
719  m_actionViewBackground->setChecked (true);
720  m_actionViewBackground->setStatusTip (tr ("Show or hide the background toolbar."));
721  m_actionViewBackground->setWhatsThis (tr ("View Background ToolBar\n\n"
722  "Show or hide the background toolbar"));
723  connect (m_actionViewBackground, SIGNAL (triggered ()), this, SLOT (slotViewToolBarBackground ()));
724 
725  m_actionViewChecklistGuide = new QAction (tr ("Checklist Guide Toolbar"), this);
726  m_actionViewChecklistGuide->setCheckable (true);
727  m_actionViewChecklistGuide->setChecked (false);
728  m_actionViewChecklistGuide->setStatusTip (tr ("Show or hide the checklist guide."));
729  m_actionViewChecklistGuide->setWhatsThis (tr ("View Checklist Guide\n\n"
730  "Show or hide the checklist guide"));
731  connect (m_actionViewChecklistGuide, SIGNAL (changed ()), this, SLOT (slotViewToolBarChecklistGuide()));
732 
733  m_actionViewFittingWindow = new QAction (tr ("Curve Fitting Window"), this);
734  m_actionViewFittingWindow->setCheckable (true);
735  m_actionViewFittingWindow->setChecked (false);
736  m_actionViewFittingWindow->setStatusTip (tr ("Show or hide the curve fitting window."));
737  m_actionViewFittingWindow->setWhatsThis (tr ("View Curve Fitting Window\n\n"
738  "Show or hide the curve fitting window"));
739  connect (m_actionViewFittingWindow, SIGNAL (changed ()), this, SLOT (slotViewToolBarFittingWindow()));
740 
741  m_actionViewGeometryWindow = new QAction (tr ("Geometry Window"), this);
742  m_actionViewGeometryWindow->setCheckable (true);
743  m_actionViewGeometryWindow->setChecked (false);
744  m_actionViewGeometryWindow->setStatusTip (tr ("Show or hide the geometry window."));
745  m_actionViewGeometryWindow->setWhatsThis (tr ("View Geometry Window\n\n"
746  "Show or hide the geometry window"));
747  connect (m_actionViewGeometryWindow, SIGNAL (changed ()), this, SLOT (slotViewToolBarGeometryWindow()));
748 
749  m_actionViewDigitize = new QAction (tr ("Digitizing Tools Toolbar"), this);
750  m_actionViewDigitize->setCheckable (true);
751  m_actionViewDigitize->setChecked (true);
752  m_actionViewDigitize->setStatusTip (tr ("Show or hide the digitizing tools toolbar."));
753  m_actionViewDigitize->setWhatsThis (tr ("View Digitizing Tools ToolBar\n\n"
754  "Show or hide the digitizing tools toolbar"));
755  connect (m_actionViewDigitize, SIGNAL (triggered ()), this, SLOT (slotViewToolBarDigitize()));
756 
757  m_actionViewSettingsViews = new QAction (tr ("Settings Views Toolbar"), this);
758  m_actionViewSettingsViews->setCheckable (true);
759  m_actionViewSettingsViews->setChecked (true);
760  m_actionViewSettingsViews->setStatusTip (tr ("Show or hide the settings views toolbar."));
761  m_actionViewSettingsViews->setWhatsThis (tr ("View Settings Views ToolBar\n\n"
762  "Show or hide the settings views toolbar. These views graphically show the "
763  "most important settings."));
764  connect (m_actionViewSettingsViews, SIGNAL (triggered ()), this, SLOT (slotViewToolBarSettingsViews()));
765 
766  m_actionViewCoordSystem = new QAction (tr ("Coordinate System Toolbar"), this);
767  m_actionViewCoordSystem->setCheckable (true);
768  m_actionViewCoordSystem->setChecked (false);
769  m_actionViewCoordSystem->setStatusTip (tr ("Show or hide the coordinate system toolbar."));
770  m_actionViewCoordSystem->setWhatsThis (tr ("View Coordinate Systems ToolBar\n\n"
771  "Show or hide the coordinate system selection toolbar. This toolbar is used "
772  "to select the current coordinate system when the document has multiple "
773  "coordinate systems. This toolbar is also used to view and print all coordinate "
774  "systems.\n\n"
775  "This toolbar is disabled when there is only one coordinate system."));
776  connect (m_actionViewCoordSystem, SIGNAL (triggered ()), this, SLOT (slotViewToolBarCoordSystem()));
777 
778  m_actionViewToolTips = new QAction (tr ("Tool Tips"), this);
779  m_actionViewToolTips->setCheckable (true);
780  m_actionViewToolTips->setChecked (true);
781  m_actionViewToolTips->setStatusTip (tr ("Show or hide the tool tips."));
782  m_actionViewToolTips->setWhatsThis (tr ("View Tool Tips\n\n"
783  "Show or hide the tool tips"));
784  connect (m_actionViewToolTips, SIGNAL (triggered ()), this, SLOT (slotViewToolTips()));
785 
786  m_actionViewGridLines = new QAction (tr ("Grid Lines"), this);
787  m_actionViewGridLines->setCheckable (true);
788  m_actionViewGridLines->setChecked (false);
789  m_actionViewGridLines->setStatusTip (tr ("Show or hide grid lines."));
790  m_actionViewGridLines->setWhatsThis (tr ("View Grid Lines\n\n"
791  "Show or hide grid lines that are added for accurate adjustments of the axes points, "
792  "which can improve accuracy in distorted graphs"));
793  connect (m_actionViewGridLines, SIGNAL (triggered ()), this, SLOT (slotViewGridLines()));
794 
795  m_actionViewBackgroundNone = new QAction (tr ("No Background"), this);
796  m_actionViewBackgroundNone->setCheckable (true);
797  m_actionViewBackgroundNone->setStatusTip (tr ("Do not show the image underneath the points."));
798  m_actionViewBackgroundNone->setWhatsThis (tr ("No Background\n\n"
799  "No image is shown so points are easier to see"));
800 
801  m_actionViewBackgroundOriginal = new QAction (tr ("Show Original Image"), this);
802  m_actionViewBackgroundOriginal->setCheckable (true);
803  m_actionViewBackgroundOriginal->setStatusTip (tr ("Show the original image underneath the points."));
804  m_actionViewBackgroundOriginal->setWhatsThis (tr ("Show Original Image\n\n"
805  "Show the original image underneath the points"));
806 
807  m_actionViewBackgroundFiltered = new QAction (tr ("Show Filtered Image"), this);
808  m_actionViewBackgroundFiltered->setCheckable (true);
809  m_actionViewBackgroundFiltered->setChecked (true);
810  m_actionViewBackgroundFiltered->setStatusTip (tr ("Show the filtered image underneath the points."));
811  m_actionViewBackgroundFiltered->setWhatsThis (tr ("Show Filtered Image\n\n"
812  "Show the filtered image underneath the points.\n\n"
813  "The filtered image is created from the original image according to the "
814  "Filter preferences so unimportant information is hidden and important "
815  "information is emphasized"));
816 
817  m_actionViewCurvesNone = new QAction (tr ("Hide All Curves"), this);
818  m_actionViewCurvesNone->setCheckable (true);
819  m_actionViewCurvesNone->setStatusTip (tr ("Hide all digitized curves."));
820  m_actionViewCurvesNone->setWhatsThis (tr ("Hide All Curves\n\n"
821  "No axis points or digitized graph curves are shown so the image is easier to see."));
822 
823  m_actionViewCurvesSelected = new QAction (tr ("Show Selected Curve"), this);
824  m_actionViewCurvesSelected->setCheckable (true);
825  m_actionViewCurvesSelected->setStatusTip (tr ("Show only the currently selected curve."));
826  m_actionViewCurvesSelected->setWhatsThis (tr ("Show Selected Curve\n\n"
827  "Show only the digitized points and line that belong to the currently selected curve."));
828 
829  m_actionViewCurvesAll = new QAction (tr ("Show All Curves"), this);
830  m_actionViewCurvesAll->setCheckable (true);
831  m_actionViewCurvesAll->setChecked (true);
832  m_actionViewCurvesAll->setStatusTip (tr ("Show all curves."));
833  m_actionViewCurvesAll->setWhatsThis (tr ("Show All Curves\n\n"
834  "Show all digitized axis points and graph curves"));
835 
836  m_groupBackground = new QActionGroup(this);
837  m_groupBackground->addAction (m_actionViewBackgroundNone);
838  m_groupBackground->addAction (m_actionViewBackgroundOriginal);
839  m_groupBackground->addAction (m_actionViewBackgroundFiltered);
840  connect (m_groupBackground, SIGNAL(triggered (QAction*)), this, SLOT (slotViewGroupBackground(QAction*)));
841 
842  m_groupCurves = new QActionGroup(this);
843  m_groupCurves->addAction (m_actionViewCurvesNone);
844  m_groupCurves->addAction (m_actionViewCurvesSelected);
845  m_groupCurves->addAction (m_actionViewCurvesAll);
846  connect (m_groupCurves, SIGNAL(triggered (QAction*)), this, SLOT (slotViewGroupCurves(QAction*)));
847 
848  m_actionStatusNever = new QAction (tr ("Hide Always"), this);
849  m_actionStatusNever->setCheckable(true);
850  m_actionStatusNever->setStatusTip (tr ("Always hide the status bar."));
851  m_actionStatusNever->setWhatsThis (tr ("Hide the status bar. No temporary status or feedback messages will appear."));
852 
853  m_actionStatusTemporary = new QAction (tr ("Show Temporary Messages"), this);
854  m_actionStatusTemporary->setCheckable(true);
855  m_actionStatusTemporary->setStatusTip (tr ("Hide the status bar except when display temporary messages."));
856  m_actionStatusTemporary->setWhatsThis (tr ("Hide the status bar, except when displaying temporary status and feedback messages."));
857 
858  m_actionStatusAlways = new QAction (tr ("Show Always"), this);
859  m_actionStatusAlways->setCheckable(true);
860  m_actionStatusAlways->setStatusTip (tr ("Always show the status bar."));
861  m_actionStatusAlways->setWhatsThis (tr ("Show the status bar. Besides displaying temporary status and feedback messages, "
862  "the status bar also displays information about the cursor position."));
863 
864  m_groupStatus = new QActionGroup(this);
865  m_groupStatus->addAction (m_actionStatusNever);
866  m_groupStatus->addAction (m_actionStatusTemporary);
867  m_groupStatus->addAction (m_actionStatusAlways);
868  connect (m_groupStatus, SIGNAL (triggered (QAction*)), this, SLOT (slotViewGroupStatus(QAction*)));
869 
870  m_actionZoomOut = new QAction (tr ("Zoom Out"), this);
871  m_actionZoomOut->setStatusTip (tr ("Zoom out"));
872  // setShortCut is called by updateSettingsMainWindow
873  connect (m_actionZoomOut, SIGNAL (triggered ()), this, SLOT (slotViewZoomOut ()));
874 
875  m_actionZoomIn = new QAction (tr ("Zoom In"), this);
876  m_actionZoomIn->setStatusTip (tr ("Zoom in"));
877  // setShortCut is called by updateSettingsMainWindow
878  connect (m_actionZoomIn, SIGNAL (triggered ()), this, SLOT (slotViewZoomIn ()));
879 
880  m_actionZoom16To1 = new QAction (tr ("16:1 (1600%)"), this);
881  m_actionZoom16To1->setCheckable (true);
882  m_actionZoom16To1->setStatusTip (tr ("Zoom 16:1"));
883  connect (m_actionZoom16To1, SIGNAL (triggered ()), this, SLOT (slotViewZoom16To1 ()));
884 
885  m_actionZoom8To1 = new QAction (tr ("8:1 (800%)"), this);
886  m_actionZoom8To1->setCheckable (true);
887  m_actionZoom8To1->setStatusTip (tr ("Zoom 8:1"));
888  connect (m_actionZoom8To1, SIGNAL (triggered ()), this, SLOT (slotViewZoom8To1 ()));
889 
890  m_actionZoom4To1 = new QAction (tr ("4:1 (400%)"), this);
891  m_actionZoom4To1->setCheckable (true);
892  m_actionZoom4To1->setStatusTip (tr ("Zoom 4:1"));
893  connect (m_actionZoom4To1, SIGNAL (triggered ()), this, SLOT (slotViewZoom4To1 ()));
894 
895  m_actionZoom2To1 = new QAction (tr ("2:1 (200%)"), this);
896  m_actionZoom2To1->setCheckable (true);
897  m_actionZoom2To1->setStatusTip (tr ("Zoom 2:1"));
898  connect (m_actionZoom2To1, SIGNAL (triggered ()), this, SLOT (slotViewZoom2To1 ()));
899 
900  m_actionZoom1To1 = new QAction (tr ("1:1 (100%)"), this);
901  m_actionZoom1To1->setCheckable (true);
902  m_actionZoom1To1->setChecked (true);
903  m_actionZoom1To1->setStatusTip (tr ("Zoom 1:1"));
904  connect (m_actionZoom1To1, SIGNAL (triggered ()), this, SLOT (slotViewZoom1To1 ()));
905 
906  m_actionZoom1To2 = new QAction (tr ("1:2 (50%)"), this);
907  m_actionZoom1To2->setCheckable (true);
908  m_actionZoom1To2->setStatusTip (tr ("Zoom 1:2"));
909  connect (m_actionZoom1To2, SIGNAL (triggered ()), this, SLOT (slotViewZoom1To2 ()));
910 
911  m_actionZoom1To4 = new QAction (tr ("1:4 (25%)"), this);
912  m_actionZoom1To4->setCheckable (true);
913  m_actionZoom1To4->setStatusTip (tr ("Zoom 1:4"));
914  connect (m_actionZoom1To4, SIGNAL (triggered ()), this, SLOT (slotViewZoom1To4 ()));
915 
916  m_actionZoom1To8 = new QAction (tr ("1:8 (12.5%)"), this);
917  m_actionZoom1To8->setCheckable (true);
918  m_actionZoom1To8->setStatusTip (tr ("Zoom 1:8"));
919  connect (m_actionZoom1To8, SIGNAL (triggered ()), this, SLOT (slotViewZoom1To8 ()));
920 
921  m_actionZoom1To16 = new QAction (tr ("1:16 (6.25%)"), this);
922  m_actionZoom1To16->setCheckable (true);
923  m_actionZoom1To16->setStatusTip (tr ("Zoom 1:16"));
924  connect (m_actionZoom1To16, SIGNAL (triggered ()), this, SLOT (slotViewZoom1To16 ()));
925 
926  m_actionZoomFill = new QAction (tr ("Fill"), this);
927  m_actionZoomFill->setCheckable (true);
928  m_actionZoomFill->setStatusTip (tr ("Zoom with stretching to fill window"));
929  connect (m_actionZoomFill, SIGNAL (triggered ()), this, SLOT (slotViewZoomFill ()));
930 
931  m_groupZoom = new QActionGroup (this);
932  m_groupZoom->addAction (m_actionZoom16To1);
933  m_groupZoom->addAction (m_actionZoom8To1);
934  m_groupZoom->addAction (m_actionZoom4To1);
935  m_groupZoom->addAction (m_actionZoom2To1);
936  m_groupZoom->addAction (m_actionZoom1To1);
937  m_groupZoom->addAction (m_actionZoom1To2);
938  m_groupZoom->addAction (m_actionZoom1To4);
939  m_groupZoom->addAction (m_actionZoom1To8);
940  m_groupZoom->addAction (m_actionZoom1To16);
941  m_groupZoom->addAction (m_actionZoomFill);
942 }
943 
944 void MainWindow::createCentralWidget ()
945 {
946  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createCentralWidget";
947 
948  QWidget *widget = new QWidget;
949  setCentralWidget (widget);
950  m_layout = new QVBoxLayout;
951  widget->setLayout (m_layout);
952 }
953 
954 void MainWindow::createCommandStackShadow ()
955 {
956  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createCommandStackShadow";
957 
958  m_cmdStackShadow = new CmdStackShadow;
959 }
960 
961 void MainWindow::createDockableWidgets ()
962 {
963  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createDockableWidgets";
964 
965  // Checklist guide starts out hidden. It will be positioned in settingsRead
966  m_dockChecklistGuide = new ChecklistGuide (this);
967  connect (m_dockChecklistGuide, SIGNAL (signalChecklistClosed()), this, SLOT (slotChecklistClosed()));
968 
969  // Fitting window starts out hidden since there is nothing to show initially. It will be positioned in settingsRead
970  m_dockFittingWindow = new FittingWindow (this);
971  connect (m_dockFittingWindow, SIGNAL (signalFittingWindowClosed()),
972  this, SLOT (slotFittingWindowClosed()));
973  connect (m_dockFittingWindow, SIGNAL (signalCurveFit(FittingCurveCoefficients, double, double, bool, bool)),
974  this, SLOT (slotFittingWindowCurveFit(FittingCurveCoefficients, double, double, bool, bool)));
975 
976  // Geometry window starts out hidden since there is nothing to show initially. It will be positioned in settingsRead
977  m_dockGeometryWindow = new GeometryWindow (this);
978  connect (m_dockGeometryWindow, SIGNAL (signalGeometryWindowClosed()),
979  this, SLOT (slotGeometryWindowClosed()));
980 
981 }
982 
983 void MainWindow::createHelpWindow ()
984 {
985  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createHelpWindow";
986 
987 #ifndef OSX_RELEASE
988  m_helpWindow = new HelpWindow (this);
989  m_helpWindow->hide ();
990  addDockWidget (Qt::RightDockWidgetArea,
991  m_helpWindow); // Dock area is required by addDockWidget but immediately overridden in next line
992  m_helpWindow->setFloating (true);
993 
994  connect (m_actionHelpHelp, SIGNAL (triggered ()), m_helpWindow, SLOT (show ()));
995 #endif
996 }
997 
998 void MainWindow::createIcons()
999 {
1000  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createIcons";
1001 
1002  QIcon icon;
1003  QPixmap icon16 (bannerapp_16);
1004  QPixmap icon32 (bannerapp_32);
1005  QPixmap icon64 (bannerapp_64);
1006  QPixmap icon128 (bannerapp_128);
1007  QPixmap icon256 (bannerapp_256);
1008 
1009  icon.addPixmap (icon16);
1010  icon.addPixmap (icon32);
1011  icon.addPixmap (icon64);
1012  icon.addPixmap (icon128);
1013  icon.addPixmap (icon256);
1014 
1015  setWindowIcon (icon);
1016 }
1017 
1018 void MainWindow::createLoadImageFromUrl ()
1019 {
1020 #ifdef NETWORKING
1021  m_loadImageFromUrl = new LoadImageFromUrl (*this);
1022 #endif
1023 }
1024 
1025 void MainWindow::createMenus()
1026 {
1027  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createMenus";
1028 
1029  m_menuFile = menuBar()->addMenu(tr("&File"));
1030  m_menuFile->addAction (m_actionImport);
1031  m_menuFile->addAction (m_actionImportAdvanced);
1032  m_menuFile->addAction (m_actionImportImageReplace);
1033  m_menuFile->addAction (m_actionOpen);
1034 #ifndef OSX_RELEASE
1035  m_menuFileOpenRecent = new QMenu (tr ("Open &Recent"));
1036  for (unsigned int i = 0; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
1037  m_menuFileOpenRecent->addAction (m_actionRecentFiles.at (i));
1038  }
1039  m_menuFile->addMenu (m_menuFileOpenRecent);
1040 #endif
1041  m_menuFile->addAction (m_actionClose);
1042  m_menuFile->insertSeparator (m_actionSave);
1043  m_menuFile->addAction (m_actionSave);
1044  m_menuFile->addAction (m_actionSaveAs);
1045  m_menuFile->addAction (m_actionExport);
1046  m_menuFile->insertSeparator (m_actionPrint);
1047  m_menuFile->addAction (m_actionPrint);
1048  m_menuFile->insertSeparator (m_actionExit);
1049  m_menuFile->addAction (m_actionExit);
1050 
1051  m_menuEdit = menuBar()->addMenu(tr("&Edit"));
1052  connect (m_menuEdit, SIGNAL (aboutToShow ()), this, SLOT (slotEditMenu ()));
1053  m_menuEdit->addAction (m_actionEditUndo);
1054  m_menuEdit->addAction (m_actionEditRedo);
1055  m_menuEdit->insertSeparator (m_actionEditCut);
1056  m_menuEdit->addAction (m_actionEditCut);
1057  m_menuEdit->addAction (m_actionEditCopy);
1058  m_menuEdit->addAction (m_actionEditPaste);
1059  m_menuEdit->addAction (m_actionEditDelete);
1060  m_menuEdit->insertSeparator (m_actionEditPasteAsNew);
1061  m_menuEdit->addAction (m_actionEditPasteAsNew);
1062  m_menuEdit->addAction (m_actionEditPasteAsNewAdvanced);
1063 
1064  m_menuDigitize = menuBar()->addMenu(tr("Digitize"));
1065  m_menuDigitize->addAction (m_actionDigitizeSelect);
1066  m_menuDigitize->addAction (m_actionDigitizeAxis);
1067  m_menuDigitize->addAction (m_actionDigitizeScale);
1068  m_menuDigitize->addAction (m_actionDigitizeCurve);
1069  m_menuDigitize->addAction (m_actionDigitizePointMatch);
1070  m_menuDigitize->addAction (m_actionDigitizeColorPicker);
1071  m_menuDigitize->addAction (m_actionDigitizeSegment);
1072 
1073  m_menuView = menuBar()->addMenu(tr("View"));
1074  m_menuView->addAction (m_actionViewBackground);
1075  m_menuView->addAction (m_actionViewDigitize);
1076  m_menuView->addAction (m_actionViewChecklistGuide);
1077  m_menuView->addAction (m_actionViewFittingWindow);
1078  m_menuView->addAction (m_actionViewGeometryWindow);
1079  m_menuView->addAction (m_actionViewSettingsViews);
1080  m_menuView->addAction (m_actionViewCoordSystem);
1081  m_menuView->insertSeparator (m_actionViewToolTips);
1082  m_menuView->addAction (m_actionViewToolTips);
1083  m_menuView->addAction (m_actionViewGridLines);
1084  m_menuView->insertSeparator (m_actionViewBackgroundNone);
1085  m_menuViewBackground = new QMenu (tr ("Background"));
1086  m_menuViewBackground->addAction (m_actionViewBackgroundNone);
1087  m_menuViewBackground->addAction (m_actionViewBackgroundOriginal);
1088  m_menuViewBackground->addAction (m_actionViewBackgroundFiltered);
1089  m_menuView->addMenu (m_menuViewBackground);
1090  m_menuViewCurves = new QMenu (tr ("Curves"));
1091  m_menuViewCurves->addAction (m_actionViewCurvesNone);
1092  m_menuViewCurves->addAction (m_actionViewCurvesSelected);
1093  m_menuViewCurves->addAction (m_actionViewCurvesAll);
1094  m_menuView->addMenu (m_menuViewCurves);
1095  m_menuViewStatus = new QMenu (tr ("Status Bar"));
1096  m_menuViewStatus->addAction (m_actionStatusNever);
1097  m_menuViewStatus->addAction (m_actionStatusTemporary);
1098  m_menuViewStatus->addAction (m_actionStatusAlways);
1099  m_menuView->addMenu (m_menuViewStatus);
1100  m_menuViewZoom = new QMenu (tr ("Zoom"));
1101  m_menuViewZoom->addAction (m_actionZoomOut);
1102  m_menuViewZoom->addAction (m_actionZoomIn);
1103  m_menuViewZoom->insertSeparator (m_actionZoom16To1);
1104  m_menuViewZoom->addAction (m_actionZoom16To1);
1105  m_menuViewZoom->addAction (m_actionZoom8To1);
1106  m_menuViewZoom->addAction (m_actionZoom4To1);
1107  m_menuViewZoom->addAction (m_actionZoom2To1);
1108  m_menuViewZoom->addAction (m_actionZoom1To1);
1109  m_menuViewZoom->addAction (m_actionZoom1To2);
1110  m_menuViewZoom->addAction (m_actionZoom1To4);
1111  m_menuViewZoom->addAction (m_actionZoom1To8);
1112  m_menuViewZoom->addAction (m_actionZoom1To16);
1113  m_menuViewZoom->addAction (m_actionZoomFill);
1114  m_menuView->addMenu (m_menuViewZoom);
1115 
1116  m_menuSettings = menuBar()->addMenu(tr ("Settings"));
1117  m_menuSettings->addAction (m_actionSettingsCoords);
1118  m_menuSettings->addAction (m_actionSettingsCurveAddRemove);
1119  m_menuSettings->addAction (m_actionSettingsCurveProperties);
1120  m_menuSettings->addAction (m_actionSettingsDigitizeCurve);
1121  m_menuSettings->addAction (m_actionSettingsExport);
1122  m_menuSettings->addAction (m_actionSettingsColorFilter);
1123  m_menuSettings->addAction (m_actionSettingsAxesChecker);
1124  m_menuSettings->addAction (m_actionSettingsGridDisplay);
1125  m_menuSettings->addAction (m_actionSettingsGridRemoval);
1126  m_menuSettings->addAction (m_actionSettingsPointMatch);
1127  m_menuSettings->addAction (m_actionSettingsSegments);
1128  m_menuSettings->insertSeparator (m_actionSettingsGeneral);
1129  m_menuSettings->addAction (m_actionSettingsGeneral);
1130  m_menuSettings->addAction (m_actionSettingsMainWindow);
1131 
1132  m_menuHelp = menuBar()->addMenu(tr("&Help"));
1133  m_menuHelp->addAction (m_actionHelpChecklistGuideWizard);
1134  m_menuHelp->insertSeparator(m_actionHelpWhatsThis);
1135  m_menuHelp->addAction (m_actionHelpWhatsThis);
1136  m_menuHelp->addAction (m_actionHelpTutorial);
1137 #ifndef OSX_RELEASE
1138  m_menuHelp->addAction (m_actionHelpHelp);
1139 #endif
1140  m_menuHelp->addAction (m_actionHelpAbout);
1141 
1142  updateRecentFileList();
1143 }
1144 
1145 void MainWindow::createNetwork ()
1146 {
1147  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createNetwork";
1148 
1149 #ifdef NETWORKING
1150  m_networkClient = new NetworkClient (this);
1151 #endif
1152 }
1153 
1154 void MainWindow::createSettingsDialogs ()
1155 {
1156  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createSettingsDialogs";
1157 
1158  m_dlgSettingsCoords = new DlgSettingsCoords (*this);
1159  m_dlgSettingsCurveAddRemove = new DlgSettingsCurveAddRemove (*this);
1160  m_dlgSettingsCurveProperties = new DlgSettingsCurveProperties (*this);
1161  m_dlgSettingsDigitizeCurve = new DlgSettingsDigitizeCurve (*this);
1162  m_dlgSettingsExportFormat = new DlgSettingsExportFormat (*this);
1163  m_dlgSettingsColorFilter = new DlgSettingsColorFilter (*this);
1164  m_dlgSettingsAxesChecker = new DlgSettingsAxesChecker (*this);
1165  m_dlgSettingsGridDisplay = new DlgSettingsGridDisplay (*this);
1166  m_dlgSettingsGridRemoval = new DlgSettingsGridRemoval (*this);
1167  m_dlgSettingsPointMatch = new DlgSettingsPointMatch (*this);
1168  m_dlgSettingsSegments = new DlgSettingsSegments (*this);
1169  m_dlgSettingsGeneral = new DlgSettingsGeneral (*this);
1170  m_dlgSettingsMainWindow = new DlgSettingsMainWindow (*this);
1171 
1172  m_dlgSettingsCoords->setVisible (false);
1173  m_dlgSettingsCurveAddRemove->setVisible (false);
1174  m_dlgSettingsCurveProperties->setVisible (false);
1175  m_dlgSettingsDigitizeCurve->setVisible (false);
1176  m_dlgSettingsExportFormat->setVisible (false);
1177  m_dlgSettingsColorFilter->setVisible (false);
1178  m_dlgSettingsAxesChecker->setVisible (false);
1179  m_dlgSettingsGridDisplay->setVisible (false);
1180  m_dlgSettingsGridRemoval->setVisible (false);
1181  m_dlgSettingsPointMatch->setVisible (false);
1182  m_dlgSettingsSegments->setVisible (false);
1183  m_dlgSettingsGeneral->setVisible (false);
1184  m_dlgSettingsMainWindow->setVisible (false);
1185 }
1186 
1187 void MainWindow::createScene ()
1188 {
1189  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createScene";
1190 
1191  m_scene = new GraphicsScene (this);
1192  m_view = new GraphicsView (m_scene, *this);
1193  m_layout->addWidget (m_view);
1194 }
1195 
1196 void MainWindow::createStateContextBackground ()
1197 {
1198  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createStateContextBackground";
1199 
1200  m_backgroundStateContext = new BackgroundStateContext (*this);
1201 }
1202 
1203 void MainWindow::createStateContextDigitize ()
1204 {
1205  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createStateContextDigitize";
1206 
1207  m_digitizeStateContext = new DigitizeStateContext (*this,
1208  *m_view,
1209  m_isGnuplot);
1210 }
1211 
1212 void MainWindow::createStateContextTransformation ()
1213 {
1214  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createStateContextTransformation";
1215 
1216  ENGAUGE_CHECK_PTR (m_scene);
1217 
1218  m_transformationStateContext = new TransformationStateContext (*m_scene,
1219  m_isGnuplot);
1220 }
1221 
1222 void MainWindow::createStatusBar ()
1223 {
1224  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createStatusBar";
1225 
1226  m_statusBar = new StatusBar (*statusBar ());
1227  connect (this, SIGNAL (signalZoom(int)), m_statusBar, SLOT (slotZoom(int)));
1228  connect (m_statusBar, SIGNAL (signalZoom (int)), this, SLOT (slotViewZoom (int)));
1229 }
1230 
1231 void MainWindow::createToolBars ()
1232 {
1233  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createToolBars";
1234 
1235  const int VIEW_SIZE = 22;
1236 
1237  // Background toolbar widgets
1238  m_cmbBackground = new QComboBox ();
1239  m_cmbBackground->setEnabled (false);
1240  m_cmbBackground->setStatusTip (tr ("Select background image"));
1241  m_cmbBackground->setWhatsThis (tr ("Selected Background\n\n"
1242  "Select background image:\n"
1243  "1) No background which highlights points\n"
1244  "2) Original image which shows everything\n"
1245  "3) Filtered image which highlights important details"));
1246  m_cmbBackground->addItem (tr ("No background"), QVariant (BACKGROUND_IMAGE_NONE));
1247  m_cmbBackground->addItem (tr ("Original image"), QVariant (BACKGROUND_IMAGE_ORIGINAL));
1248  m_cmbBackground->addItem (tr ("Filtered image"), QVariant (BACKGROUND_IMAGE_FILTERED));
1249  // selectBackgroundOriginal needs currentIndexChanged
1250  connect (m_cmbBackground, SIGNAL (currentIndexChanged (int)), this, SLOT (slotCmbBackground (int)));
1251 
1252  // Background toolbar
1253  m_toolBackground = new QToolBar (tr ("Background"), this);
1254  m_toolBackground->addWidget (m_cmbBackground);
1255  addToolBar (m_toolBackground);
1256 
1257  // Digitize toolbar widgets that are not created elsewhere
1258  m_cmbCurve = new QComboBox ();
1259  m_cmbCurve->setEnabled (false);
1260  m_cmbCurve->setMinimumWidth (180);
1261  m_cmbCurve->setStatusTip (tr ("Select curve for new points."));
1262  m_cmbCurve->setWhatsThis (tr ("Selected Curve Name\n\n"
1263  "Select curve for any new points. Every point belongs to one curve.\n\n"
1264  "This can be changed while in Curve Point, Point Match, Color Picker or Segment Fill mode."));
1265  connect (m_cmbCurve, SIGNAL (activated (int)), this, SLOT (slotCmbCurve (int))); // activated() ignores code changes
1266 
1267  // Digitize toolbar
1268  m_toolDigitize = new QToolBar (tr ("Drawing"), this);
1269  m_toolDigitize->addAction (m_actionDigitizeSelect);
1270  m_toolDigitize->insertSeparator (m_actionDigitizeAxis);
1271  m_toolDigitize->addAction (m_actionDigitizeAxis);
1272  m_toolDigitize->addAction (m_actionDigitizeScale);
1273  m_toolDigitize->insertSeparator (m_actionDigitizeCurve);
1274  m_toolDigitize->addAction (m_actionDigitizeCurve);
1275  m_toolDigitize->addAction (m_actionDigitizePointMatch);
1276  m_toolDigitize->addAction (m_actionDigitizeColorPicker);
1277  m_toolDigitize->addAction (m_actionDigitizeSegment);
1278  m_toolDigitize->addWidget (m_cmbCurve);
1279  addToolBar (m_toolDigitize);
1280 
1281  // Views toolbar widgets
1282  m_viewPointStyle = new ViewPointStyle();
1283  m_viewPointStyle->setMinimumSize(VIEW_SIZE, VIEW_SIZE);
1284  m_viewPointStyle->setMaximumSize(VIEW_SIZE, VIEW_SIZE);
1285  m_viewPointStyle->setStatusTip (tr ("Points style for the currently selected curve"));
1286  m_viewPointStyle->setWhatsThis (tr ("Points Style\n\n"
1287  "Points style for the currently selected curve. The points style is only "
1288  "displayed in this toolbar. To change the points style, "
1289  "use the Curve Properties dialog."));
1290 
1291  m_viewSegmentFilter = new ViewSegmentFilter();
1292  m_viewSegmentFilter->setMinimumSize(VIEW_SIZE, VIEW_SIZE);
1293  m_viewSegmentFilter->setMaximumSize(VIEW_SIZE, VIEW_SIZE);
1294  m_viewSegmentFilter->setStatusTip (tr ("View of filter for current curve in Segment Fill mode"));
1295  m_viewSegmentFilter->setWhatsThis (tr ("Segment Fill Filter\n\n"
1296  "View of filter for the current curve in Segment Fill mode. The filter settings are only "
1297  "displayed in this toolbar. To changed the filter settings, "
1298  "use the Color Picker mode or the Filter Settings dialog."));
1299 
1300  // Settings views toolbar
1301  m_toolSettingsViews = new QToolBar (tr ("Views"), this);
1302  m_toolSettingsViews->addWidget (m_viewPointStyle);
1303  m_toolSettingsViews->addWidget (new QLabel (" ")); // A hack, but this works to put some space between the adjacent widgets
1304  m_toolSettingsViews->addWidget (m_viewSegmentFilter);
1305  addToolBar (m_toolSettingsViews);
1306 
1307  // Coordinate system toolbar
1308  m_cmbCoordSystem = new QComboBox;
1309  m_cmbCoordSystem->setEnabled (false);
1310  m_cmbCoordSystem->setStatusTip (tr ("Currently selected coordinate system"));
1311  m_cmbCoordSystem->setWhatsThis (tr ("Selected Coordinate System\n\n"
1312  "Currently selected coordinate system. This is used to switch between coordinate systems "
1313  "in documents with multiple coordinate systems"));
1314  connect (m_cmbCoordSystem, SIGNAL (activated (int)), this, SLOT (slotCmbCoordSystem (int)));
1315 
1316  m_btnShowAll = new QPushButton(QIcon(":/engauge/img/icon_show_all.png"), "");
1317  m_btnShowAll->setEnabled (false);
1318  m_btnShowAll->setAcceptDrops(false);
1319  m_btnShowAll->setStatusTip (tr ("Show all coordinate systems"));
1320  m_btnShowAll->setWhatsThis (tr ("Show All Coordinate Systems\n\n"
1321  "When pressed and held, this button shows all digitized points and lines for all coordinate systems."));
1322  connect (m_btnShowAll, SIGNAL (pressed ()), this, SLOT (slotBtnShowAllPressed ()));
1323  connect (m_btnShowAll, SIGNAL (released ()), this, SLOT (slotBtnShowAllReleased ()));
1324 
1325  m_btnPrintAll = new QPushButton(QIcon(":/engauge/img/icon_print_all.png"), "");
1326  m_btnPrintAll->setEnabled (false);
1327  m_btnPrintAll->setAcceptDrops(false);
1328  m_btnPrintAll->setStatusTip (tr ("Print all coordinate systems"));
1329  m_btnPrintAll->setWhatsThis (tr ("Print All Coordinate Systems\n\n"
1330  "When pressed, this button Prints all digitized points and lines for all coordinate systems."));
1331  connect (m_btnPrintAll, SIGNAL (pressed ()), this, SLOT (slotBtnPrintAll ()));
1332 
1333  m_toolCoordSystem = new QToolBar (tr ("Coordinate System"), this);
1334  m_toolCoordSystem->addWidget (m_cmbCoordSystem);
1335  m_toolCoordSystem->addWidget (m_btnShowAll);
1336  m_toolCoordSystem->addWidget (m_btnPrintAll);
1337  addToolBar (m_toolCoordSystem);
1338 }
1339 
1340 void MainWindow::createTutorial ()
1341 {
1342  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createTutorial";
1343 
1344  m_tutorialDlg = new TutorialDlg (this);
1345  m_tutorialDlg->setModal (true);
1346  m_tutorialDlg->setMinimumSize (500, 400);
1347  m_tutorialDlg->hide();
1348 }
1349 
1350 void MainWindow::createZoomMap ()
1351 {
1352  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createZoomMap";
1353 
1354  m_zoomMap [ZOOM_INITIAL_16_TO_1] = ZOOM_16_TO_1;
1355  m_zoomMap [ZOOM_INITIAL_8_TO_1] = ZOOM_8_TO_1;
1356  m_zoomMap [ZOOM_INITIAL_4_TO_1] = ZOOM_4_TO_1;
1357  m_zoomMap [ZOOM_INITIAL_2_TO_1] = ZOOM_2_TO_1;
1358  m_zoomMap [ZOOM_INITIAL_1_TO_1] = ZOOM_1_TO_1;
1359  m_zoomMap [ZOOM_INITIAL_1_TO_2] = ZOOM_1_TO_2;
1360  m_zoomMap [ZOOM_INITIAL_1_TO_4] = ZOOM_1_TO_4;
1361  m_zoomMap [ZOOM_INITIAL_1_TO_8] = ZOOM_1_TO_8;
1362  m_zoomMap [ZOOM_INITIAL_1_TO_16] = ZOOM_1_TO_16;
1363  m_zoomMap [ZOOM_INITIAL_FILL] = ZOOM_FILL;
1364 }
1365 
1366 ZoomFactor MainWindow::currentZoomFactor () const
1367 {
1368  if (m_actionZoom1To1->isChecked()) {
1369  return ZOOM_1_TO_1;
1370  } else if (m_actionZoom1To2->isChecked()) {
1371  return ZOOM_1_TO_2;
1372  } else if (m_actionZoom1To4->isChecked()) {
1373  return ZOOM_1_TO_4;
1374  } else if (m_actionZoom1To8->isChecked()) {
1375  return ZOOM_1_TO_8;
1376  } else if (m_actionZoom1To16->isChecked()) {
1377  return ZOOM_1_TO_16;
1378  } else if (m_actionZoom2To1->isChecked()) {
1379  return ZOOM_2_TO_1;
1380  } else if (m_actionZoom4To1->isChecked()) {
1381  return ZOOM_4_TO_1;
1382  } else if (m_actionZoom8To1->isChecked()) {
1383  return ZOOM_8_TO_1;
1384  } else if (m_actionZoom16To1->isChecked()) {
1385  return ZOOM_16_TO_1;
1386  } else if (m_actionZoomFill->isChecked()) {
1387  return ZOOM_FILL;
1388  } else {
1389  ENGAUGE_ASSERT (false);
1390  return ZOOM_1_TO_1;
1391  }
1392 }
1393 bool MainWindow::eventFilter(QObject *target, QEvent *event)
1394 {
1395  if (event->type () == QEvent::KeyPress) {
1396 
1397  QKeyEvent *eventKeyPress = (QKeyEvent *) event;
1398 
1399  // Special shortcuts. All of these are probably only useful for debugging and/or regression testing
1400  if ((eventKeyPress->key() == Qt::Key_E) &&
1401  ((eventKeyPress->modifiers() & Qt::ShiftModifier) != 0) &&
1402  ((eventKeyPress->modifiers() & Qt::ControlModifier) != 0)) {
1403 
1404  saveErrorReportFileAndExit ("Shift+Control+E",
1405  __FILE__,
1406  __LINE__,
1407  "userTriggered");
1408 
1409  }
1410  }
1411 
1412  return QObject::eventFilter (target, event);
1413 }
1414 
1415 #ifndef OSX_RELEASE
1416 void MainWindow::exportAllCoordinateSystemsAfterRegressionTests()
1417 {
1418  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::exportAllCoordinateSystemsAfterRegressionTests curDir=" << QDir::currentPath().toLatin1().data();
1419 
1420  // Output the regression test results. One file is output for every coordinate system
1421  for (CoordSystemIndex index = 0; index < m_cmdMediator->document().coordSystemCount(); index++) {
1422 
1423  updateCoordSystem (index); // Switch to the specified coordinate system
1424 
1425  QString regressionFile = QString ("%1_%2")
1426  .arg (m_regressionFile)
1427  .arg (index + 1); // Append the coordinate system index
1428 
1429  // Normally we just export to a file, but when regression testing the export will fail since coordinates are not defined. To
1430  // get an export file when regression testing, we just output the image size
1431  if (m_isErrorReportRegressionTest && !m_transformation.transformIsDefined()) {
1432 
1433  ExportImageForRegression exportStrategy (m_cmdMediator->pixmap ());
1434  exportStrategy.fileExport (regressionFile);
1435 
1436  } else {
1437 
1438  ExportToFile exportStrategy;
1439 
1440  fileExport (regressionFile,
1441  exportStrategy);
1442  }
1443  }
1444 }
1445 #endif
1446 
1447 QString MainWindow::exportFilenameFromInputFilename (const QString &fileName) const
1448 {
1449  QString outFileName = fileName;
1450 
1451  outFileName = outFileName.replace (".xml", ".csv_actual"); // Applies when extension is xml
1452  outFileName = outFileName.replace (".dig", ".csv_actual"); // Applies when extension is dig
1453  outFileName = outFileName.replace (".pdf", ".csv_actual"); // Applies when extension is pdf
1454 
1455  return outFileName;
1456 }
1457 
1458 void MainWindow::fileExport(const QString &fileName,
1459  ExportToFile exportStrategy)
1460 {
1461  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileExport"
1462  << " curDir=" << QDir::currentPath().toLatin1().data()
1463  << " fileName=" << fileName.toLatin1().data();
1464 
1465  QFile file (fileName);
1466  if (file.open(QIODevice::WriteOnly)) {
1467 
1468  QTextStream str (&file);
1469 
1470  DocumentModelExportFormat modelExportFormat = modelExportOverride (m_cmdMediator->document().modelExport(),
1471  exportStrategy,
1472  fileName);
1473  exportStrategy.exportToFile (modelExportFormat,
1474  m_cmdMediator->document(),
1475  m_modelMainWindow,
1476  transformation (),
1477  str);
1478 
1479  updateChecklistGuide ();
1480  m_statusBar->showTemporaryMessage("File saved");
1481 
1482  } else {
1483 
1484  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::fileExport"
1485  << " file=" << fileName.toLatin1().data()
1486  << " curDir=" << QDir::currentPath().toLatin1().data();
1487  QMessageBox::critical (0,
1488  engaugeWindowTitle(),
1489  tr ("Unable to export to file ") + fileName);
1490  }
1491 }
1492 
1493 void MainWindow::fileImport (const QString &fileName,
1494  ImportType importType)
1495 {
1496  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileImport"
1497  << " fileName=" << fileName.toLatin1 ().data ()
1498  << " curDir=" << QDir::currentPath().toLatin1().data()
1499  << " importType=" << importType;
1500 
1501  QString originalFileOld = m_originalFile;
1502  bool originalFileWasImported = m_originalFileWasImported;
1503 
1504  m_originalFile = fileName; // Make this available for logging in case an error occurs during the load
1505  m_originalFileWasImported = true;
1506 
1507  if (importType == IMPORT_TYPE_ADVANCED) {
1508 
1509  // Remove any existing points, axes checker(s) and such from the previous Document so they do not appear in setupAfterLoadNewDocument
1510  // when previewing for IMAGE_TYPE_ADVANCED
1511  slotFileClose();
1512 
1513  // Restore the background just closed by slotFileClose. This is required so when the image is loaded for preview, it will appear
1514  m_backgroundStateContext->setBackgroundImage(BACKGROUND_IMAGE_ORIGINAL);
1515  }
1516 
1517  QImage image;
1518  bool loaded = false;
1519 
1520 #ifdef ENGAUGE_JPEG2000
1521  Jpeg2000 jpeg2000;
1522  loaded = jpeg2000.load (fileName,
1523  image);
1524 #endif // ENGAUGE_JPEG2000
1525 
1526 #ifdef ENGAUGE_PDF
1527  if (!loaded) {
1528 
1529  Pdf pdf;
1530  PdfReturn pdfReturn = pdf.load (fileName,
1531  image,
1532  m_modelMainWindow.pdfResolution(),
1533  m_modelMainWindow.importCropping(),
1534  m_isErrorReportRegressionTest);
1535  if (pdfReturn == PDF_RETURN_CANCELED) {
1536 
1537  // User canceled so exit immediately
1538  return;
1539 
1540  }
1541 
1542  loaded = (pdfReturn == PDF_RETURN_SUCCESS);
1543  }
1544 #endif // ENGAUGE_PDF
1545 
1546  if (!loaded) {
1547  NonPdf nonPdf;
1548  NonPdfReturn nonPdfReturn = nonPdf.load (fileName,
1549  image,
1550  m_modelMainWindow.importCropping(),
1551  m_isErrorReportRegressionTest);
1552  if (nonPdfReturn == NON_PDF_RETURN_CANCELED) {
1553 
1554  // User canceled so exit immediately
1555  return;
1556 
1557  }
1558 
1559  loaded = (nonPdfReturn == NON_PDF_RETURN_SUCCESS);
1560  }
1561 
1562  if (!loaded) {
1563  QString msg = QString("%1 %2 %3 %4.")
1564  .arg (tr ("Cannot read file"))
1565  .arg (fileName)
1566  .arg (tr ("from directory"))
1567  .arg (QDir::currentPath());
1568  QMessageBox::warning (this,
1569  engaugeWindowTitle(),
1570  msg);
1571 
1572  // Reset
1573  m_originalFile = originalFileOld;
1574  m_originalFileWasImported = originalFileWasImported;
1575 
1576  } else {
1577 
1578  loaded = loadImage (fileName,
1579  image,
1580  importType);
1581 
1582  if (!loaded) {
1583 
1584  // Failed
1585  if (importType == IMPORT_TYPE_ADVANCED) {
1586 
1587  // User cancelled after another file was imported so it could be previewed. In anticipation of the loading-for-preview,
1588  // we closed the current Document at the top of this method so we cannot reload. So, the only option is to close again
1589  // so the half-imported current Document is removed
1590  slotFileClose();
1591 
1592  } else {
1593 
1594  // Reset
1595  m_originalFile = originalFileOld;
1596  m_originalFileWasImported = originalFileWasImported;
1597  }
1598  }
1599  }
1600 }
1601 
1602 void MainWindow::fileImportWithPrompts (ImportType importType)
1603 {
1604  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileImportWithPrompts"
1605  << " importType=" << importType;
1606 
1607  // Skip maybeSave method for IMPORT_TYPE_REPLACE_IMAGE since open file dialog is enough to allow user to cancel the operation, and
1608  // since no information is lost in that case
1609  bool okToContinue = true;
1610  if (importType != IMPORT_TYPE_IMAGE_REPLACE) {
1611  okToContinue = maybeSave ();
1612  }
1613 
1614  if (okToContinue) {
1615 
1616  QString filter;
1617  QTextStream str (&filter);
1618 
1619  // Compile a list of supported formats into a filter
1620  QList<QByteArray>::const_iterator itr;
1621  QList<QByteArray> supportedImageFormats = QImageReader::supportedImageFormats();
1622  QStringList supportedImageFormatStrings;
1623  for (itr = supportedImageFormats.begin (); itr != supportedImageFormats.end (); itr++) {
1624  QByteArray arr = *itr;
1625  QString extensionAsWildcard = QString ("*.%1").arg (QString (arr));
1626  supportedImageFormatStrings << extensionAsWildcard;
1627  }
1628 #ifdef ENGAUGE_JPEG2000
1629  Jpeg2000 jpeg2000;
1630  supportedImageFormatStrings << jpeg2000.supportedImageWildcards();
1631 #endif // ENGAUGE_JPEG2000
1632 
1633 #ifdef ENGAUGE_PDF
1634  supportedImageFormatStrings << "*.pdf";
1635 #endif // ENGAUGE_PDF
1636 
1637  supportedImageFormatStrings.sort();
1638 
1639  str << "Image Files (" << supportedImageFormatStrings.join (" ") << ")";
1640 
1641  // Allow selection of files with strange suffixes in case the file extension was changed. Since
1642  // the default is the first filter, we add this afterwards (it is the off-nominal case)
1643  str << ";; All Files (*.*)";
1644 
1645  QString fileName = QFileDialog::getOpenFileName (this,
1646  tr("Import Image"),
1647  QDir::currentPath (),
1648  filter);
1649  if (!fileName.isEmpty ()) {
1650 
1651  // We import the file BEFORE asking the number of coordinate systems, so user can see how many there are
1652  fileImport (fileName,
1653  importType);
1654  }
1655  }
1656 }
1657 
1658 void MainWindow::filePaste (ImportType importType)
1659 {
1660  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::filePaste"
1661  << " importType=" << importType;
1662 
1663  QString originalFileOld = m_originalFile;
1664  bool originalFileWasImported = m_originalFileWasImported;
1665 
1666  QString fileName ("clipboard");
1667  m_originalFile = fileName; // Make this available for logging in case an error occurs during the load
1668  m_originalFileWasImported = true;
1669 
1670  if (importType == IMPORT_TYPE_ADVANCED) {
1671 
1672  // Remove any existing points, axes checker(s) and such from the previous Document so they do not appear in setupAfterLoadNewDocument
1673  // when previewing for IMAGE_TYPE_ADVANCED
1674  slotFileClose();
1675 
1676  // Restore the background just closed by slotFileClose. This is required so when the image is loaded for preview, it will appear
1677  m_backgroundStateContext->setBackgroundImage(BACKGROUND_IMAGE_ORIGINAL);
1678  }
1679 
1680  // An image was in the clipboard when this method was called but it may have disappeared
1681  QImage image = QApplication::clipboard()->image();
1682 
1683  bool loaded = false;
1684  if (!loaded) {
1685  loaded = !image.isNull();
1686  }
1687 
1688  if (!loaded) {
1689  QMessageBox::warning (this,
1690  engaugeWindowTitle(),
1691  QString("%1 %2 %3 %4.")
1692  .arg (tr ("Cannot read file"))
1693  .arg (fileName)
1694  .arg (tr ("from directory"))
1695  .arg (QDir::currentPath ()));
1696 
1697  // Reset
1698  m_originalFile = originalFileOld;
1699  m_originalFileWasImported = originalFileWasImported;
1700 
1701  } else {
1702 
1703  loaded = loadImage (fileName,
1704  image,
1705  importType);
1706 
1707  if (!loaded) {
1708 
1709  // Failed
1710  if (importType == IMPORT_TYPE_ADVANCED) {
1711 
1712  // User cancelled after another file was imported so it could be previewed. In anticipation of the loading-for-preview,
1713  // we closed the current Document at the top of this method so we cannot reload. So, the only option is to close again
1714  // so the half-imported current Document is removed
1715  slotFileClose();
1716 
1717  } else {
1718 
1719  // Reset
1720  m_originalFile = originalFileOld;
1721  m_originalFileWasImported = originalFileWasImported;
1722  }
1723  }
1724  }
1725 }
1726 
1727 void MainWindow::ghostsCreate ()
1728 {
1729  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::ghostsCreate";
1730 
1731  ENGAUGE_ASSERT (m_ghosts == 0);
1732  m_ghosts = new Ghosts (m_cmdMediator->document().coordSystemIndex());
1733 
1734  for (unsigned int index = 0; index < m_cmdMediator->document().coordSystemCount(); index++) {
1735 
1736  // Skip this coordinate system if it is the selected coordinate system since it will be displayed anyway, so no ghosts are required
1737  if (index != m_ghosts->coordSystemIndexToBeRestored ()) {
1738 
1739  updateCoordSystem (index);
1740 
1741  // Take a snapshot of the graphics items
1742  m_ghosts->captureGraphicsItems (*m_scene);
1743  }
1744  }
1745 
1746  // Restore the coordinate system that was originally selected, so its points/lines are visible
1748 
1749  // Make visible ghosts
1750  m_ghosts->createGhosts (*m_scene);
1751 }
1752 
1753 void MainWindow::ghostsDestroy ()
1754 {
1755  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::ghostsDestroy";
1756 
1757  ENGAUGE_CHECK_PTR (m_ghosts);
1758 
1759  m_ghosts->destroyGhosts(*m_scene);
1760 
1761  delete m_ghosts;
1762  m_ghosts = 0;
1763 }
1764 
1766 {
1767  return m_backgroundStateContext->imageForCurveState();
1768 }
1769 
1771 {
1772  return m_isGnuplot;
1773 }
1774 
1775 void MainWindow::loadCoordSystemListFromCmdMediator ()
1776 {
1777  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadCoordSystemListFromCmdMediator";
1778 
1779  m_cmbCoordSystem->clear();
1780 
1781  unsigned int numberCoordSystem = m_cmdMediator->document().coordSystemCount();
1782 
1783  for (unsigned int i = 0; i < numberCoordSystem; i++) {
1784  int index1Based = i + 1;
1785  m_cmbCoordSystem->addItem (QString::number (index1Based),
1786  QVariant (i));
1787  }
1788 
1789  // Always start with the first entry selected
1790  m_cmbCoordSystem->setCurrentIndex (0);
1791 
1792  // Disable the controls if there is only one entry. Hopefully the user will not even notice it, thus simplifying the interface
1793  bool enable = (m_cmbCoordSystem->count() > 1);
1794  m_cmbCoordSystem->setEnabled (enable);
1795  m_btnShowAll->setEnabled (enable);
1796  m_btnPrintAll->setEnabled (enable);
1797 }
1798 
1799 void MainWindow::loadCurveListFromCmdMediator ()
1800 {
1801  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadCurveListFromCmdMediator";
1802 
1803  m_cmbCurve->clear ();
1804  QStringList curvesGraphsNames = m_cmdMediator->curvesGraphsNames ();
1805  QStringList::iterator itr;
1806  for (itr = curvesGraphsNames.begin (); itr != curvesGraphsNames.end (); itr++) {
1807 
1808  QString curvesGraphName = *itr;
1809  m_cmbCurve->addItem (curvesGraphName);
1810  }
1811 
1812  // Select the curve that is associated with the current coordinate system
1813  m_cmbCurve->setCurrentText (m_cmdMediator->selectedCurveName ());
1814 }
1815 
1816 void MainWindow::loadDocumentFile (const QString &fileName)
1817 {
1818  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadDocumentFile fileName=" << fileName.toLatin1 ().data ();
1819 
1820  QApplication::setOverrideCursor(Qt::WaitCursor);
1821  CmdMediator *cmdMediator = new CmdMediator (*this,
1822  fileName);
1823 
1824  if (cmdMediator->successfulRead ()) {
1825 
1826  setCurrentPathFromFile (fileName);
1827  rebuildRecentFileListForCurrentFile(fileName);
1828  m_currentFile = fileName; // This enables the FileSaveAs menu option
1829 
1830  if (m_cmdMediator != 0) {
1831  delete m_cmdMediator;
1832  m_cmdMediator = 0;
1833  }
1834 
1835  m_cmdMediator = cmdMediator;
1836  setupAfterLoadNewDocument (fileName,
1837  "File opened",
1838  IMPORT_TYPE_SIMPLE);
1839 
1840  // Start select mode
1841  m_actionDigitizeSelect->setChecked (true); // We assume user wants to first select existing stuff
1842  slotDigitizeSelect(); // Trigger transition so cursor gets updated immediately
1843 
1844  m_engaugeFile = fileName;
1845  m_originalFile = fileName; // This is needed by updateAfterCommand below if an error report is generated
1846  m_originalFileWasImported = false;
1847 
1848  updateGridLines ();
1849  updateAfterCommand (); // Enable Save button now that m_engaugeFile is set
1850 
1851  QApplication::restoreOverrideCursor();
1852 
1853  } else {
1854 
1855  QApplication::restoreOverrideCursor();
1856 
1857  QMessageBox::warning (this,
1858  engaugeWindowTitle(),
1859  QString("%1 %2 %3 %4:\n%5.")
1860  .arg (tr ("Cannot read file"))
1861  .arg (fileName)
1862  .arg (tr ("from directory"))
1863  .arg (QDir::currentPath ())
1864  .arg(cmdMediator->reasonForUnsuccessfulRead ()));
1865  delete cmdMediator;
1866 
1867  }
1868 }
1869 
1870 void MainWindow::loadErrorReportFile(const QString &errorReportFile)
1871 {
1872  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadErrorReportFile"
1873  << " file=" << errorReportFile.toLatin1().data();
1874 
1875  QFile file (errorReportFile);
1876  if (!file.exists()) {
1877  // Convert path from relative to absolute so file-not-found errors are easier to fix
1878  QFileInfo fileInfo (errorReportFile);
1879 
1880  QMessageBox::critical (this,
1881  engaugeWindowTitle(),
1882  tr ("File not found:") + " " + fileInfo.absoluteFilePath());
1883  exit (-1);
1884  }
1885 
1886  // Open the error report file as if it was a regular Document file
1887  QXmlStreamReader reader (&file);
1888  file.open(QIODevice::ReadOnly | QIODevice::Text);
1889  m_cmdMediator = new CmdMediator(*this,
1890  errorReportFile);
1891 
1892  // Load the commands into the shadow command stack
1893  m_cmdStackShadow->loadCommands (*this,
1894  m_cmdMediator->document(),
1895  reader);
1896  file.close();
1897 
1898  setupAfterLoadNewDocument (errorReportFile,
1899  "Error report opened",
1900  IMPORT_TYPE_SIMPLE);
1901 
1902  // Start select mode
1903  m_actionDigitizeSelect->setChecked (true); // We assume user wants to first select existing stuff
1904  slotDigitizeSelect(); // Trigger transition so cursor gets updated immediately
1905 
1906  updateAfterCommand ();
1907 }
1908 
1909 bool MainWindow::loadImage (const QString &fileName,
1910  const QImage &image,
1911  ImportType importType)
1912 {
1913  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImage"
1914  << " fileName=" << fileName.toLatin1 ().data ()
1915  << " importType=" << importType;
1916 
1917  bool success;
1918  if (importType == IMPORT_TYPE_IMAGE_REPLACE) {
1919  success = loadImageReplacingImage (fileName,
1920  image,
1921  importType);
1922  } else {
1923  success = loadImageNewDocument (fileName,
1924  image,
1925  importType);
1926  }
1927 
1928  return success;
1929 }
1930 
1931 bool MainWindow::loadImageNewDocument (const QString &fileName,
1932  const QImage &image,
1933  ImportType importType)
1934 {
1935  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImageNewDocument"
1936  << " fileName=" << fileName.toLatin1 ().data ()
1937  << " importType=" << importType;
1938 
1939  ENGAUGE_ASSERT (importType != IMPORT_TYPE_IMAGE_REPLACE);
1940 
1941  QApplication::setOverrideCursor(Qt::WaitCursor);
1942  CmdMediator *cmdMediator = new CmdMediator (*this,
1943  image);
1944  QApplication::restoreOverrideCursor();
1945 
1946  setCurrentPathFromFile (fileName);
1947  // We do not call rebuildRecentFileListForCurrentFile for an image file, so only proper Engauge document files appear in the recent file list
1948  m_engaugeFile = EMPTY_FILENAME; // Forces first Save to be treated as Save As
1949 
1950  if (m_cmdMediator != 0) {
1951  delete m_cmdMediator;
1952  m_cmdMediator = 0;
1953  }
1954 
1955  m_cmdMediator = cmdMediator;
1956  bool accepted = setupAfterLoadNewDocument (fileName,
1957  tr ("File imported"),
1958  importType);
1959 
1960  if (accepted) {
1961 
1962  // Show the wizard if user selected it and we are not running a script
1963  if (m_actionHelpChecklistGuideWizard->isChecked () &&
1964  (m_fileCmdScript == 0)) {
1965 
1966  // Show wizard
1967  ChecklistGuideWizard *wizard = new ChecklistGuideWizard (*this,
1968  m_cmdMediator->document().coordSystemCount());
1969  if (wizard->exec() == QDialog::Accepted) {
1970 
1971  for (CoordSystemIndex coordSystemIndex = 0; coordSystemIndex < m_cmdMediator->document().coordSystemCount(); coordSystemIndex++) {
1972 
1973  // Populate the checklist guide
1974  m_dockChecklistGuide->setTemplateHtml (wizard->templateHtml(coordSystemIndex),
1975  wizard->curveNames(coordSystemIndex));
1976 
1977  // Update Document
1978  CurvesGraphs curvesGraphs;
1979  wizard->populateCurvesGraphs (coordSystemIndex,
1980  curvesGraphs);
1981  m_cmdMediator->document().setCurvesGraphs(curvesGraphs);
1982  }
1983 
1984  // Unhide the checklist guide
1985  m_actionViewChecklistGuide->setChecked (true);
1986 
1987  // Update the curve dropdown
1988  loadCurveListFromCmdMediator();
1989 
1990  // Update the CoordSystem dropdown
1991  loadCoordSystemListFromCmdMediator();
1992  }
1993  delete wizard;
1994  }
1995 
1996  // Start axis mode
1997  m_actionDigitizeAxis->setChecked (true); // We assume user first wants to digitize axis points
1998 
1999  // Trigger transition so cursor gets updated immediately
2000  if (modeMap ()) {
2001  slotDigitizeScale ();
2002  } else if (modeGraph ()) {
2003  slotDigitizeAxis ();
2004  }
2005 
2006  updateControls ();
2007  }
2008 
2009  return accepted;
2010 }
2011 
2012 bool MainWindow::loadImageReplacingImage (const QString &fileName,
2013  const QImage &image,
2014  ImportType importType)
2015 {
2016  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImageReplacingImage"
2017  << " fileName=" << fileName.toLatin1 ().data ()
2018  << " importType=" << importType;
2019 
2020  ENGAUGE_ASSERT (importType == IMPORT_TYPE_IMAGE_REPLACE);
2021 
2022  setCurrentPathFromFile (fileName);
2023  // We do not call rebuildRecentFileListForCurrentFile for an image file, so only proper Engauge document files appear in the recent file list
2024  m_engaugeFile = EMPTY_FILENAME; // Forces first Save to be treated as Save As
2025 
2026  ENGAUGE_ASSERT (m_cmdMediator != 0); // Menu option should only be available when a document is currently open
2027 
2028  m_cmdMediator->document().setPixmap (image);
2029 
2030  bool accepted = setupAfterLoadReplacingImage (fileName,
2031  tr ("File imported"),
2032  importType);
2033 
2034  // No checklist guide wizard is displayed when just replacing the image
2035 
2036  return accepted;
2037 }
2038 
2039 void MainWindow::loadInputFileForErrorReport(QDomDocument &domInputFile) const
2040 {
2041  QFile file (m_originalFile);
2042 
2043  // File should be available for opening, if not then the dom will be left empty. We assume it has not been
2044  // modified since opened
2045  if (!file.open (QIODevice::ReadOnly)) {
2046  return;
2047  }
2048 
2049  domInputFile.setContent (&file);
2050  file.close();
2051 }
2052 
2053 void MainWindow::loadToolTips()
2054 {
2055  if (m_actionViewToolTips->isChecked ()) {
2056 
2057  // Show tool tips
2058  m_actionDigitizeSelect->setToolTip (m_actionDigitizeSelect->text());
2059  m_actionDigitizeAxis->setToolTip (m_actionDigitizeAxis->text());
2060  m_actionDigitizeScale->setToolTip (m_actionDigitizeScale->text());
2061  m_actionDigitizeCurve->setToolTip (m_actionDigitizeCurve->text());
2062  m_actionDigitizePointMatch->setToolTip (m_actionDigitizePointMatch->text());
2063  m_actionDigitizeColorPicker->setToolTip (m_actionDigitizeColorPicker->text());
2064  m_actionDigitizeSegment->setToolTip (m_actionDigitizeSegment->text());
2065  m_cmbBackground->setToolTip (tr ("Background image."));
2066  m_cmbCurve->setToolTip (tr ("Currently selected curve."));
2067  m_viewPointStyle->setToolTip (tr ("Point style for currently selected curve."));
2068  m_viewSegmentFilter->setToolTip (tr ("Segment Fill filter for currently selected curve."));
2069 
2070  } else {
2071 
2072  // Remove any previous tool tips
2073  m_actionDigitizeSelect->setToolTip ("");
2074  m_actionDigitizeAxis->setToolTip ("");
2075  m_actionDigitizeScale->setToolTip ("");
2076  m_actionDigitizeCurve->setToolTip ("");
2077  m_actionDigitizePointMatch->setToolTip ("");
2078  m_actionDigitizeColorPicker->setToolTip ("");
2079  m_actionDigitizeSegment->setToolTip ("");
2080  m_cmbBackground->setToolTip ("");
2081  m_cmbCurve->setToolTip ("");
2082  m_viewPointStyle->setToolTip ("");
2083  m_viewSegmentFilter->setToolTip ("");
2084 
2085  }
2086 }
2087 
2088 bool MainWindow::modeGraph () const
2089 {
2090  bool success = false;
2091 
2092  if (m_cmdMediator != 0) {
2093  success = (m_cmdMediator->document().documentAxesPointsRequired() != DOCUMENT_AXES_POINTS_REQUIRED_2);
2094  }
2095 
2096  return success;
2097 }
2098 
2099 bool MainWindow::modeMap () const
2100 {
2101  bool success = false;
2102 
2103  if (m_cmdMediator != 0) {
2104  success = (m_cmdMediator->document().documentAxesPointsRequired() == DOCUMENT_AXES_POINTS_REQUIRED_2);
2105  }
2106 
2107  return success;
2108 }
2109 
2110 bool MainWindow::maybeSave()
2111 {
2112  if (m_cmdMediator != 0) {
2113  if (m_cmdMediator->isModified()) {
2114  QMessageBox::StandardButton ret = QMessageBox::warning (this,
2115  engaugeWindowTitle(),
2116  tr("The document has been modified.\n"
2117  "Do you want to save your changes?"),
2118  QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
2119  if (ret == QMessageBox::Save) {
2120  return slotFileSave();
2121  } else if (ret == QMessageBox::Cancel) {
2122  return false;
2123  }
2124  }
2125  }
2126 
2127  return true;
2128 }
2129 
2130 DocumentModelExportFormat MainWindow::modelExportOverride (const DocumentModelExportFormat &modelExportFormatBefore,
2131  const ExportToFile &exportStrategy,
2132  const QString &fileName) const
2133 {
2134  DocumentModelExportFormat modelExportFormatAfter = modelExportFormatBefore;
2135 
2136  // See if delimiter setting overrides commas/tabs for files with csv/tsv file extensions respectively
2137  if (!modelExportFormatAfter.overrideCsvTsv()) {
2138 
2139  // Extract file extensions
2140  QString csvExtension = QString (".%1")
2141  .arg (exportStrategy.fileExtensionCsv());
2142  QString tsvExtension = QString (".%1")
2143  .arg (exportStrategy.fileExtensionTsv());
2144  QString fileExtensionVersusCsv = fileName.right (csvExtension.size());
2145  QString fileExtensionVersusTsv = fileName.right (tsvExtension.size());
2146 
2147  // Override if CSV or TSV was selected. We cannot use QFileDialog::selectedNameFilter() since that is
2148  // broken in Linux, so we use the file extension
2149  if (csvExtension.compare (fileExtensionVersusCsv, Qt::CaseInsensitive) == 0) {
2150  modelExportFormatAfter.setDelimiter (EXPORT_DELIMITER_COMMA);
2151  } else if (tsvExtension.compare (fileExtensionVersusTsv, Qt::CaseInsensitive) == 0) {
2152  modelExportFormatAfter.setDelimiter (EXPORT_DELIMITER_TAB);
2153  }
2154  }
2155 
2156  return modelExportFormatAfter;
2157 }
2158 
2160 {
2161  return m_modelMainWindow;
2162 }
2163 
2164 void MainWindow::rebuildRecentFileListForCurrentFile(const QString &filePath)
2165 {
2166  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::rebuildRecentFileListForCurrentFile";
2167 
2168  setWindowFilePath (filePath);
2169 
2170  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
2171  QStringList recentFilePaths = settings.value (SETTINGS_RECENT_FILE_LIST).toStringList();
2172  recentFilePaths.removeAll (filePath); // Remove previous instance of the current filePath
2173  recentFilePaths.prepend (filePath); // Insert current filePath at start
2174  while (recentFilePaths.count () > (int) MAX_RECENT_FILE_LIST_SIZE) {
2175  recentFilePaths.removeLast (); // Remove entry since the number of entries exceeds the limit
2176  }
2177  settings.setValue (SETTINGS_RECENT_FILE_LIST, recentFilePaths);
2178 
2179  updateRecentFileList();
2180 }
2181 
2182 void MainWindow::resizeEvent(QResizeEvent * /* event */)
2183 {
2184  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::resizeEvent";
2185 
2186  if (m_actionZoomFill->isChecked ()) {
2187  slotViewZoomFill();
2188  }
2189 }
2190 
2191 bool MainWindow::saveDocumentFile (const QString &fileName)
2192 {
2193  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::saveDocumentFile fileName=" << fileName.toLatin1 ().data ();
2194 
2195  QFile file(fileName);
2196  if (!file.open(QFile::WriteOnly)) {
2197  QMessageBox::warning (this,
2198  engaugeWindowTitle(),
2199  QString ("%1 %2: \n%3.")
2200  .arg(tr ("Cannot write file"))
2201  .arg(fileName)
2202  .arg(file.errorString()));
2203  return false;
2204  }
2205 
2206  rebuildRecentFileListForCurrentFile (fileName);
2207 
2208  QApplication::setOverrideCursor (Qt::WaitCursor);
2209  QXmlStreamWriter writer(&file);
2210  writer.setAutoFormatting(true);
2211  writer.writeStartDocument();
2212  writer.writeDTD("<!DOCTYPE engauge>");
2213  m_cmdMediator->document().saveXml(writer);
2214  writer.writeEndDocument();
2215  QApplication::restoreOverrideCursor ();
2216 
2217  // Notify the undo stack that the current state is now considered "clean". This will automatically trigger a
2218  // signal back to this class that will update the modified marker in the title bar
2219  m_cmdMediator->setClean ();
2220 
2221  setCurrentFile(fileName);
2222  m_engaugeFile = fileName;
2223  updateAfterCommand (); // Enable Save button now that m_engaugeFile is set
2224  m_statusBar->showTemporaryMessage("File saved");
2225 
2226  return true;
2227 }
2228 
2229 void MainWindow::saveErrorReportFileAndExit (const char *context,
2230  const char *file,
2231  int line,
2232  const char *comment) const
2233 {
2234  // Skip if currently performing a regression test - in which case the preferred behavior is to let the current test fail and
2235  // continue on to execute the remaining tests
2236  if ((m_cmdMediator != 0) && !m_isErrorReportRegressionTest) {
2237 
2238  QString report = saveErrorReportFileAndExitXml (context,
2239  file,
2240  line,
2241  comment);
2242 #ifdef NETWORKING
2243  DlgErrorReportNetworking dlg (report);
2244 
2245  // Ask user if report should be uploaded, and if the document is included when it is uploaded
2246  if (dlg.exec() == QDialog::Accepted) {
2247 
2248  // Upload the error report to the server
2249  m_networkClient->uploadErrorReport (dlg.xmlToUpload());
2250  }
2251 #else
2252  DlgErrorReportLocal dlg (report);
2253  dlg.exec();
2254  exit (-1);
2255 #endif
2256  }
2257 }
2258 
2259 QString MainWindow::saveErrorReportFileAndExitXml (const char *context,
2260  const char *file,
2261  int line,
2262  const char *comment) const
2263 {
2264  const bool DEEP_COPY = true;
2265 
2266  QString xmlErrorReport;
2267  QXmlStreamWriter writer (&xmlErrorReport);
2268  writer.setAutoFormatting(true);
2269 
2270  // Entire error report contains metadata, commands and other details
2271  writer.writeStartElement(DOCUMENT_SERIALIZE_ERROR_REPORT);
2272 
2273  // Version
2274  writer.writeStartElement(DOCUMENT_SERIALIZE_APPLICATION);
2275  writer.writeAttribute(DOCUMENT_SERIALIZE_APPLICATION_VERSION_NUMBER, VERSION_NUMBER);
2276  writer.writeEndElement();
2277 
2278  // Document
2279  // Insert snapshot xml into writer stream, by reading from reader stream. Highest level of snapshot is DOCUMENT_SERIALIZE_APPLICATION
2280  QXmlStreamReader reader (m_startingDocumentSnapshot);
2281  while (!reader.atEnd ()) {
2282  reader.readNext ();
2283  if (reader.tokenType() != QXmlStreamReader::StartDocument &&
2284  reader.tokenType() != QXmlStreamReader::EndDocument) {
2285  writer.writeCurrentToken (reader);
2286  }
2287  }
2288 
2289  // Operating system
2290  writer.writeStartElement(DOCUMENT_SERIALIZE_OPERATING_SYSTEM);
2291  writer.writeAttribute(DOCUMENT_SERIALIZE_OPERATING_SYSTEM_ENDIAN, EndianToString (QSysInfo::ByteOrder));
2292  writer.writeAttribute(DOCUMENT_SERIALIZE_OPERATING_SYSTEM_WORD_SIZE, QString::number (QSysInfo::WordSize));
2293  writer.writeEndElement();
2294 
2295  // Placeholder for original file, before the commands in the command stack were applied
2296  writer.writeStartElement(DOCUMENT_SERIALIZE_FILE);
2297  writer.writeAttribute(DOCUMENT_SERIALIZE_FILE_IMPORTED,
2298  m_originalFileWasImported ? DOCUMENT_SERIALIZE_BOOL_TRUE : DOCUMENT_SERIALIZE_BOOL_FALSE);
2299  writer.writeEndElement();
2300 
2301  // Commands
2302  m_cmdMediator->saveXml(writer);
2303 
2304  // Error
2305  writer.writeStartElement(DOCUMENT_SERIALIZE_ERROR);
2306  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_CONTEXT, context);
2307  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_FILE, file);
2308  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_LINE, QString::number (line));
2309  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_COMMENT, comment);
2310  writer.writeEndElement();
2311 
2312  writer.writeEndElement();
2313 
2314  // Put string into DOM
2315  QDomDocument domErrorReport ("ErrorReport");
2316  domErrorReport.setContent (xmlErrorReport);
2317 
2318  // Postprocessing
2319  if (!m_originalFileWasImported) {
2320 
2321  // Insert the original file into its placeholder, by manipulating the source and target xml as DOM documents. Very early
2322  // in the loading process, the original file may not be specified yet (m_originalFile is empty)
2323  QDomDocument domInputFile;
2324  loadInputFileForErrorReport (domInputFile);
2325  QDomDocumentFragment fragmentFileFrom = domErrorReport.createDocumentFragment();
2326  if (!domInputFile.isNull()) {
2327  fragmentFileFrom.appendChild (domErrorReport.importNode (domInputFile.documentElement(), DEEP_COPY));
2328  }
2329  QDomNodeList nodesFileTo = domErrorReport.elementsByTagName (DOCUMENT_SERIALIZE_FILE);
2330  if (nodesFileTo.count () > 0) {
2331  QDomNode nodeFileTo = nodesFileTo.at (0);
2332  nodeFileTo.appendChild (fragmentFileFrom);
2333  }
2334 
2335  // Replace DOCUMENT_SERIALIZE_IMAGE by same node with CDATA removed, since:
2336  // 1) it is very big and working with smaller files, especially in emails, is easier
2337  // 2) removing the image better preserves user's privacy
2338  // 3) having the actual image does not help that much when debugging
2339  QDomNodeList nodesDocument = domErrorReport.elementsByTagName (DOCUMENT_SERIALIZE_DOCUMENT);
2340  for (int i = 0 ; i < nodesDocument.count(); i++) {
2341  QDomNode nodeDocument = nodesDocument.at (i);
2342  QDomElement elemImage = nodeDocument.firstChildElement(DOCUMENT_SERIALIZE_IMAGE);
2343  if (!elemImage.isNull()) {
2344 
2345  // Get old image attributes so we can create an empty document with the same size
2346  if (elemImage.hasAttribute (DOCUMENT_SERIALIZE_IMAGE_WIDTH) &&
2347  elemImage.hasAttribute (DOCUMENT_SERIALIZE_IMAGE_HEIGHT)) {
2348 
2349  int width = elemImage.attribute(DOCUMENT_SERIALIZE_IMAGE_WIDTH).toInt();
2350  int height = elemImage.attribute(DOCUMENT_SERIALIZE_IMAGE_HEIGHT).toInt();
2351 
2352  QDomNode nodeReplacement;
2353  QDomElement elemReplacement = nodeReplacement.toElement();
2354  elemReplacement.setAttribute (DOCUMENT_SERIALIZE_IMAGE_WIDTH, width);
2355  elemReplacement.setAttribute (DOCUMENT_SERIALIZE_IMAGE_HEIGHT, height);
2356 
2357  // Replace with the new and then remove the old
2358  nodeDocument.insertBefore (nodeReplacement,
2359  elemImage);
2360  nodeDocument.removeChild(elemImage);
2361  }
2362  }
2363  }
2364  }
2365 
2366  return domErrorReport.toString();
2367 }
2368 
2369 void MainWindow::saveStartingDocumentSnapshot()
2370 {
2371  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::saveStartingDocumentSnapshot";
2372 
2373  QXmlStreamWriter writer (&m_startingDocumentSnapshot);
2374  writer.setAutoFormatting (true);
2375  m_cmdMediator->document().saveXml (writer);
2376 }
2377 
2379 {
2380  ENGAUGE_CHECK_PTR (m_scene);
2381  return *m_scene;
2382 }
2383 
2384 BackgroundImage MainWindow::selectOriginal(BackgroundImage backgroundImage)
2385 {
2386  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::selectBackgroundOriginal";
2387 
2388  BackgroundImage previousBackground = (BackgroundImage) m_cmbBackground->currentData().toInt();
2389 
2390  int index = m_cmbBackground->findData (backgroundImage);
2391  ENGAUGE_ASSERT (index >= 0);
2392 
2393  m_cmbBackground->setCurrentIndex(index);
2394 
2395  return previousBackground;
2396 }
2397 
2399 {
2400  return m_cmbCurve->currentText ();
2401 }
2402 
2403 void MainWindow::setCurrentFile (const QString &fileName)
2404 {
2405  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setCurrentFile";
2406 
2407  QString fileNameStripped;
2408  if (!fileName.isEmpty()) {
2409 
2410  // Strip out path and file extension
2411  QFileInfo fileInfo (fileName);
2412  fileNameStripped = fileInfo.baseName();
2413  }
2414 
2415  m_currentFile = fileNameStripped;
2416  m_currentFileWithPathAndFileExtension = fileName;
2417 
2418  updateWindowTitle ();
2419 }
2420 
2421 void MainWindow::setCurrentPathFromFile (const QString &fileName)
2422 {
2423  QDir dir = QFileInfo (fileName).absoluteDir();
2424 
2425  if (dir.exists ()) {
2426 
2427  bool success = QDir::setCurrent (dir.absolutePath ()); // Return to chosen directory the next time
2428  ENGAUGE_ASSERT (success);
2429 
2430  } else {
2431 
2432  // File was a url so it is irrelevant to the current directory
2433  }
2434 }
2435 
2436 void MainWindow::setPixmap (const QString &curveSelected,
2437  const QPixmap &pixmap)
2438 {
2439  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setPixmap";
2440 
2441  m_digitizeStateContext->setImageIsLoaded (m_cmdMediator,
2442  true);
2443 
2444  // We cannot reliably use m_cmbCurve->currentText below for the selected curve since that control
2445  // can be pointing to a curve that no longer exists so this method requires curveSelected as an argument
2446  m_backgroundStateContext->setPixmap (m_transformation,
2447  m_cmdMediator->document().modelGridRemoval(),
2448  m_cmdMediator->document().modelColorFilter(),
2449  pixmap,
2450  curveSelected);
2451 }
2452 
2453 void MainWindow::settingsRead (bool isReset)
2454 {
2455  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
2456 
2457  if (isReset) {
2458  // Delete all settings. Default values are specified, later, for each settings as it is loaded
2459  settings.clear ();
2460  }
2461 
2462  settingsReadEnvironment (settings);
2463  settingsReadMainWindow (settings);
2464 }
2465 
2466 void MainWindow::settingsReadEnvironment (QSettings &settings)
2467 {
2468  settings.beginGroup (SETTINGS_GROUP_ENVIRONMENT);
2469  QDir::setCurrent (settings.value (SETTINGS_CURRENT_DIRECTORY,
2470  QDir::currentPath ()).toString ());
2471  settings.endGroup ();
2472 }
2473 
2474 void MainWindow::settingsReadMainWindow (QSettings &settings)
2475 {
2476  settings.beginGroup(SETTINGS_GROUP_MAIN_WINDOW);
2477 
2478  // Main window geometry
2479  resize (settings.value (SETTINGS_SIZE,
2480  QSize (600, 600)).toSize ());
2481  move (settings.value (SETTINGS_POS,
2482  QPoint (200, 200)).toPoint ());
2483 
2484  // Help window geometry
2485 #ifndef OSX_RELEASE
2486  QSize helpSize = settings.value (SETTINGS_HELP_SIZE,
2487  QSize (900, 600)).toSize();
2488  m_helpWindow->resize (helpSize);
2489  if (settings.contains (SETTINGS_HELP_POS)) {
2490  QPoint helpPos = settings.value (SETTINGS_HELP_POS).toPoint();
2491  m_helpWindow->move (helpPos);
2492  }
2493 #endif
2494 
2495  // Checklist guide wizard
2496  m_actionHelpChecklistGuideWizard->setChecked (settings.value (SETTINGS_CHECKLIST_GUIDE_WIZARD,
2497  true).toBool ());
2498 
2499  // Background toolbar visibility
2500  bool viewBackgroundToolBar = settings.value (SETTINGS_VIEW_BACKGROUND_TOOLBAR,
2501  true).toBool ();
2502  m_actionViewBackground->setChecked (viewBackgroundToolBar);
2503  m_toolBackground->setVisible (viewBackgroundToolBar);
2504  BackgroundImage backgroundImage = (BackgroundImage) settings.value (SETTINGS_BACKGROUND_IMAGE,
2505  BACKGROUND_IMAGE_FILTERED).toInt ();
2506  int indexBackground = m_cmbBackground->findData (QVariant (backgroundImage));
2507  m_cmbBackground->setCurrentIndex (indexBackground);
2508 
2509  // Digitize toolbar visibility
2510  bool viewDigitizeToolBar = settings.value (SETTINGS_VIEW_DIGITIZE_TOOLBAR,
2511  true).toBool ();
2512  m_actionViewDigitize->setChecked (viewDigitizeToolBar);
2513  m_toolDigitize->setVisible (viewDigitizeToolBar);
2514 
2515  // Views toolbar visibility
2516  bool viewSettingsViewsToolBar = settings.value (SETTINGS_VIEW_SETTINGS_VIEWS_TOOLBAR,
2517  true).toBool ();
2518  m_actionViewSettingsViews->setChecked (viewSettingsViewsToolBar);
2519  m_toolSettingsViews->setVisible (viewSettingsViewsToolBar);
2520 
2521  // Coordinate system toolbar visibility
2522  bool viewCoordSystemToolbar = settings.value (SETTINGS_VIEW_COORD_SYSTEM_TOOLBAR,
2523  false).toBool ();
2524  m_actionViewCoordSystem->setChecked (viewCoordSystemToolbar);
2525  m_toolCoordSystem->setVisible (viewCoordSystemToolbar);
2526 
2527  // Tooltips visibility
2528  bool viewToolTips = settings.value (SETTINGS_VIEW_TOOL_TIPS,
2529  true).toBool ();
2530  m_actionViewToolTips->setChecked (viewToolTips);
2531  loadToolTips ();
2532 
2533  // Statusbar visibility
2534  StatusBarMode statusBarMode = (StatusBarMode) settings.value (SETTINGS_VIEW_STATUS_BAR,
2535  false).toInt ();
2536  m_statusBar->setStatusBarMode (statusBarMode);
2537  m_actionStatusNever->setChecked (statusBarMode == STATUS_BAR_MODE_NEVER);
2538  m_actionStatusTemporary->setChecked (statusBarMode == STATUS_BAR_MODE_TEMPORARY);
2539  m_actionStatusAlways->setChecked (statusBarMode == STATUS_BAR_MODE_ALWAYS);
2540 
2541  addDockWindow (m_dockChecklistGuide,
2542  settings,
2543  SETTINGS_CHECKLIST_GUIDE_DOCK_AREA,
2544  SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY,
2545  Qt::RightDockWidgetArea);
2546  addDockWindow (m_dockFittingWindow,
2547  settings,
2548  SETTINGS_FITTING_WINDOW_DOCK_AREA,
2549  SETTINGS_FITTING_WINDOW_DOCK_GEOMETRY,
2550  Qt::RightDockWidgetArea);
2551  addDockWindow (m_dockGeometryWindow,
2552  settings,
2553  SETTINGS_GEOMETRY_WINDOW_DOCK_AREA,
2554  SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY,
2555  Qt::RightDockWidgetArea);
2556 
2557  // Main window settings. Preference for initial zoom factor is 100%, rather than fill mode, for issue #25. Some or all
2558  // settings are saved to the application AND saved to m_modelMainWindow for use in DlgSettingsMainWindow. Note that
2559  // TranslatorContainer has previously extracted the locale from the settings
2560  QLocale localeDefault;
2561  QLocale::Language language = (QLocale::Language) settings.value (SETTINGS_LOCALE_LANGUAGE,
2562  QVariant (localeDefault.language())).toInt();
2563  QLocale::Country country = (QLocale::Country) settings.value (SETTINGS_LOCALE_COUNTRY,
2564  QVariant (localeDefault.country())).toInt();
2565  QLocale locale (language,
2566  country);
2567  slotViewZoom ((ZoomFactor) settings.value (SETTINGS_ZOOM_FACTOR,
2568  QVariant (ZOOM_1_TO_1)).toInt());
2569  m_modelMainWindow.setLocale (locale);
2570  m_modelMainWindow.setZoomFactorInitial((ZoomFactorInitial) settings.value (SETTINGS_ZOOM_FACTOR_INITIAL,
2571  QVariant (DEFAULT_ZOOM_FACTOR_INITIAL)).toInt());
2572  m_modelMainWindow.setZoomControl ((ZoomControl) settings.value (SETTINGS_ZOOM_CONTROL,
2573  QVariant (ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)).toInt());
2574  m_modelMainWindow.setMainTitleBarFormat ((MainTitleBarFormat) settings.value (SETTINGS_MAIN_TITLE_BAR_FORMAT,
2575  QVariant (MAIN_TITLE_BAR_FORMAT_PATH)).toInt());
2576  m_modelMainWindow.setPdfResolution (settings.value (SETTINGS_IMPORT_PDF_RESOLUTION,
2577  QVariant (DEFAULT_IMPORT_PDF_RESOLUTION)).toInt ());
2578  m_modelMainWindow.setImportCropping ((ImportCropping) settings.value (SETTINGS_IMPORT_CROPPING,
2579  QVariant (DEFAULT_IMPORT_CROPPING)).toInt ());
2580  m_modelMainWindow.setMaximumGridLines (settings.value (SETTINGS_MAXIMUM_GRID_LINES,
2581  QVariant (DEFAULT_MAXIMUM_GRID_LINES)).toInt ());
2582  m_modelMainWindow.setHighlightOpacity (settings.value (SETTINGS_HIGHLIGHT_OPACITY,
2583  QVariant (DEFAULT_HIGHLIGHT_OPACITY)).toDouble ());
2584  m_modelMainWindow.setSmallDialogs (settings.value (SETTINGS_SMALL_DIALOGS,
2585  QVariant (DEFAULT_SMALL_DIALOGS)).toBool ());
2586  m_modelMainWindow.setDragDropExport (settings.value (SETTINGS_DRAG_DROP_EXPORT,
2587  QVariant (DEFAULT_DRAG_DROP_EXPORT)).toBool ());
2588 
2590  updateSmallDialogs();
2591 
2592  settings.endGroup();
2593 }
2594 
2595 void MainWindow::settingsWrite ()
2596 {
2597  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
2598 
2599  settings.beginGroup (SETTINGS_GROUP_ENVIRONMENT);
2600  settings.setValue (SETTINGS_CURRENT_DIRECTORY, QDir::currentPath ());
2601  settings.endGroup ();
2602 
2603  settings.beginGroup (SETTINGS_GROUP_MAIN_WINDOW);
2604  settings.setValue (SETTINGS_SIZE, size ());
2605  settings.setValue (SETTINGS_POS, pos ());
2606 #ifndef OSX_RELEASE
2607  settings.setValue (SETTINGS_HELP_SIZE, m_helpWindow->size());
2608  settings.setValue (SETTINGS_HELP_POS, m_helpWindow->pos ());
2609 #endif
2610  if (m_dockChecklistGuide->isFloating()) {
2611 
2612  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, Qt::NoDockWidgetArea);
2613  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY, m_dockChecklistGuide->saveGeometry ());
2614 
2615  } else {
2616 
2617  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, dockWidgetArea (m_dockChecklistGuide));
2618 
2619  }
2620  if (m_dockFittingWindow->isFloating()) {
2621 
2622  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_AREA, Qt::NoDockWidgetArea);
2623  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_GEOMETRY, m_dockFittingWindow->saveGeometry());
2624  } else {
2625 
2626  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_AREA, dockWidgetArea (m_dockFittingWindow));
2627  }
2628  if (m_dockGeometryWindow->isFloating()) {
2629 
2630  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, Qt::NoDockWidgetArea);
2631  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY, m_dockGeometryWindow->saveGeometry ());
2632 
2633  } else {
2634 
2635  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, dockWidgetArea (m_dockGeometryWindow));
2636 
2637  }
2638  settings.setValue (SETTINGS_BACKGROUND_IMAGE, m_cmbBackground->currentData().toInt());
2639  settings.setValue (SETTINGS_CHECKLIST_GUIDE_WIZARD, m_actionHelpChecklistGuideWizard->isChecked ());
2640  settings.setValue (SETTINGS_DRAG_DROP_EXPORT, m_modelMainWindow.dragDropExport ());
2641  settings.setValue (SETTINGS_HIGHLIGHT_OPACITY, m_modelMainWindow.highlightOpacity());
2642  settings.setValue (SETTINGS_IMPORT_CROPPING, m_modelMainWindow.importCropping());
2643  settings.setValue (SETTINGS_IMPORT_PDF_RESOLUTION, m_modelMainWindow.pdfResolution ());
2644  settings.setValue (SETTINGS_LOCALE_LANGUAGE, m_modelMainWindow.locale().language());
2645  settings.setValue (SETTINGS_LOCALE_COUNTRY, m_modelMainWindow.locale().country());
2646  settings.setValue (SETTINGS_MAIN_TITLE_BAR_FORMAT, m_modelMainWindow.mainTitleBarFormat());
2647  settings.setValue (SETTINGS_MAXIMUM_GRID_LINES, m_modelMainWindow.maximumGridLines());
2648  settings.setValue (SETTINGS_SMALL_DIALOGS, m_modelMainWindow.smallDialogs());
2649  settings.setValue (SETTINGS_VIEW_BACKGROUND_TOOLBAR, m_actionViewBackground->isChecked());
2650  settings.setValue (SETTINGS_VIEW_DIGITIZE_TOOLBAR, m_actionViewDigitize->isChecked ());
2651  settings.setValue (SETTINGS_VIEW_STATUS_BAR, m_statusBar->statusBarMode ());
2652  settings.setValue (SETTINGS_VIEW_SETTINGS_VIEWS_TOOLBAR, m_actionViewSettingsViews->isChecked ());
2653  settings.setValue (SETTINGS_VIEW_COORD_SYSTEM_TOOLBAR, m_actionViewCoordSystem->isChecked ());
2654  settings.setValue (SETTINGS_VIEW_TOOL_TIPS, m_actionViewToolTips->isChecked ());
2655  settings.setValue (SETTINGS_ZOOM_CONTROL, m_modelMainWindow.zoomControl());
2656  settings.setValue (SETTINGS_ZOOM_FACTOR, currentZoomFactor ());
2657  settings.setValue (SETTINGS_ZOOM_FACTOR_INITIAL, m_modelMainWindow.zoomFactorInitial());
2658  settings.endGroup ();
2659 }
2660 
2661 bool MainWindow::setupAfterLoadNewDocument (const QString &fileName,
2662  const QString &temporaryMessage ,
2663  ImportType importType)
2664 {
2665  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setupAfterLoadNewDocument"
2666  << " file=" << fileName.toLatin1().data()
2667  << " message=" << temporaryMessage.toLatin1().data()
2668  << " importType=" << importType;
2669 
2670  // The steps in this method should theoretically be a superset of the steps in setupAfterLoadNewDocument. Therefore, any
2671  // changes to this method should be considered for application to the other method also
2672 
2673  const QString EMPTY_CURVE_NAME_TO_SKIP_BACKGROUND_PROCESSING; // For bootstrapping the preview
2674 
2675  // At this point the code assumes CmdMediator for the NEW Document is already stored in m_cmdMediator
2676 
2677  m_digitizeStateContext->resetOnLoad (m_cmdMediator); // Before setPixmap
2678  m_backgroundStateContext->setCurveSelected (m_transformation,
2679  m_cmdMediator->document().modelGridRemoval(),
2680  m_cmdMediator->document().modelColorFilter(),
2681  EMPTY_CURVE_NAME_TO_SKIP_BACKGROUND_PROCESSING); // Before setPixmap
2682  setPixmap (m_cmdMediator->document().curvesGraphsNames().first(),
2683  m_cmdMediator->pixmap ()); // Set background immediately so it is visible as a preview when any dialogs are displayed
2684 
2685  // Image is visible now so the user can refer to it when we ask for the number of coordinate systems. Note that the Document
2686  // may already have multiple CoordSystem if user loaded a file that had multiple CoordSystem entries
2687  if (importType == IMPORT_TYPE_ADVANCED) {
2688 
2689  applyZoomFactorAfterLoad(); // Apply the currently selected zoom factor
2690 
2691  DlgImportAdvanced dlgImportAdvanced (*this);
2692  dlgImportAdvanced.exec();
2693 
2694  if (dlgImportAdvanced.result() == QDialog::Rejected) {
2695  return false;
2696  }
2697 
2698  int numberCoordSystem = dlgImportAdvanced.numberCoordSystem();
2699  m_cmdMediator->document().addCoordSystems (numberCoordSystem - 1);
2700  m_cmdMediator->setDocumentAxesPointsRequired (dlgImportAdvanced.documentAxesPointsRequired());
2701  }
2702 
2703  m_transformation.resetOnLoad();
2704  m_transformationStateContext->resetOnLoad();
2705  m_scene->resetOnLoad();
2706 
2707  connect (m_actionEditUndo, SIGNAL (triggered ()), m_cmdMediator, SLOT (undo ()));
2708  connect (m_actionEditUndo, SIGNAL (triggered ()), m_cmdStackShadow, SLOT (slotUndo ()));
2709  connect (m_actionEditRedo, SIGNAL (triggered ()), m_cmdMediator, SLOT (redo ())); // No effect until CmdMediator::undo and CmdStackShadow::slotUndo get called
2710  connect (m_actionEditRedo, SIGNAL (triggered ()), m_cmdStackShadow, SLOT (slotRedo ())); // No effect after CmdMediator::undo and CmdStackShadow::slotUndo get called
2711  connect (m_cmdMediator, SIGNAL (canRedoChanged(bool)), this, SLOT (slotCanRedoChanged (bool)));
2712  connect (m_cmdMediator, SIGNAL (canUndoChanged(bool)), this, SLOT (slotCanUndoChanged (bool)));
2713  connect (m_cmdMediator, SIGNAL (redoTextChanged (const QString &)), this, SLOT (slotRedoTextChanged (const QString &)));
2714  connect (m_cmdMediator, SIGNAL (undoTextChanged (const QString &)), this, SLOT (slotUndoTextChanged (const QString &)));
2715  loadCurveListFromCmdMediator ();
2716  loadCoordSystemListFromCmdMediator ();
2718 
2719  m_isDocumentExported = false;
2720 
2721  // Background must be set (by setPixmap) before slotViewZoomFill which relies on the background. At this point
2722  // the transformation is undefined (unless the code is changed) so grid removal will not work
2723  // but updateTransformationAndItsDependencies will call this again to fix that issue. Note that the selected
2724  // curve name was set (by setCurveSelected) earlier before the call to setPixmap
2725  m_backgroundStateContext->setCurveSelected (m_transformation,
2726  m_cmdMediator->document().modelGridRemoval(),
2727  m_cmdMediator->document().modelColorFilter(),
2728  m_cmbCurve->currentText ());
2729  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) m_cmbBackground->currentIndex ());
2730 
2731  applyZoomFactorAfterLoad(); // Zoom factor must be reapplied after background image is set, to have any effect
2732 
2733  setCurrentFile(fileName);
2734  m_statusBar->showTemporaryMessage (temporaryMessage);
2735  m_statusBar->wakeUp ();
2736 
2737  saveStartingDocumentSnapshot();
2738 
2739  updateAfterCommand(); // Replace stale points by points in new Document
2740 
2741  return true;
2742 }
2743 
2744 bool MainWindow::setupAfterLoadReplacingImage (const QString &fileName,
2745  const QString &temporaryMessage ,
2746  ImportType importType)
2747 {
2748  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setupAfterLoadReplacingImage"
2749  << " file=" << fileName.toLatin1().data()
2750  << " message=" << temporaryMessage.toLatin1().data()
2751  << " importType=" << importType;
2752 
2753  // The steps in this method should theoretically be just a subset of the steps in setupAfterLoadNewDocument
2754 
2755  // After this point there should be no commands in CmdMediator, since we effectively have a new document
2756  m_cmdMediator->clear();
2757 
2758  setPixmap (m_cmdMediator->document().curvesGraphsNames().first(),
2759  m_cmdMediator->pixmap ()); // Set background immediately so it is visible as a preview when any dialogs are displayed
2760 
2761  m_isDocumentExported = false;
2762 
2763  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) m_cmbBackground->currentIndex ());
2764 
2765  applyZoomFactorAfterLoad(); // Zoom factor must be reapplied after background image is set, to have any effect
2766 
2767  setCurrentFile(fileName);
2768  m_statusBar->showTemporaryMessage (temporaryMessage);
2769  m_statusBar->wakeUp ();
2770 
2771  saveStartingDocumentSnapshot();
2772 
2773  updateAfterCommand(); // Replace stale points by points in new Document
2774 
2775  return true;
2776 }
2777 
2778 void MainWindow::showEvent (QShowEvent *event)
2779 {
2780  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::showEvent"
2781  << " files=" << m_loadStartupFiles.join (",").toLatin1().data();
2782 
2783  QMainWindow::showEvent (event);
2784 
2785  if (m_loadStartupFiles.count() > 0) {
2786 
2787  m_timerLoadStartupFiles = new QTimer;
2788  m_timerLoadStartupFiles->setSingleShot (true);
2789  connect (m_timerLoadStartupFiles, SIGNAL (timeout ()), this, SLOT (slotLoadStartupFiles ()));
2790  m_timerLoadStartupFiles->start (0); // Zero delay still waits until execution finishes and gui is available
2791 
2792  }
2793 }
2794 
2795 void MainWindow::showTemporaryMessage (const QString &temporaryMessage)
2796 {
2797  m_statusBar->showTemporaryMessage (temporaryMessage);
2798 }
2799 
2800 void MainWindow::slotBtnPrintAll ()
2801 {
2802  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnPrintAll";
2803 
2804  ghostsCreate ();
2805 
2806  QPrinter printer (QPrinter::HighResolution);
2807  QPrintDialog dlg (&printer, this);
2808  if (dlg.exec() == QDialog::Accepted) {
2809  QPainter painter (&printer);
2810  m_view->render (&painter);
2811  painter.end();
2812  }
2813 
2814  ghostsDestroy ();
2815 }
2816 
2817 void MainWindow::slotBtnShowAllPressed ()
2818 {
2819  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnShowAllPressed";
2820 
2821  // Start of press-release sequence
2822  ghostsCreate ();
2823 }
2824 
2825 void MainWindow::slotBtnShowAllReleased ()
2826 {
2827  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnShowAllReleased";
2828 
2829  // End of press-release sequence
2830  ghostsDestroy ();
2831 }
2832 
2833 void MainWindow::slotCanRedoChanged (bool canRedo)
2834 {
2835  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotCanRedoChanged";
2836 
2837  m_actionEditRedo->setEnabled (canRedo || m_cmdStackShadow->canRedo());
2838 }
2839 
2840 void MainWindow::slotCanUndoChanged (bool canUndo)
2841 {
2842  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotCanUndoChanged";
2843 
2844  m_actionEditUndo->setEnabled (canUndo);
2845 }
2846 
2847 void MainWindow::slotChecklistClosed()
2848 {
2849  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotChecklistClosed";
2850 
2851  m_actionViewChecklistGuide->setChecked (false);
2852 }
2853 
2854 void MainWindow::slotCleanChanged(bool clean)
2855 {
2856  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCleanChanged";
2857 
2858  setWindowModified (!clean);
2859 }
2860 
2861 void MainWindow::slotCmbBackground(int currentIndex)
2862 {
2863  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbBackground";
2864 
2865  switch (currentIndex) {
2866  case BACKGROUND_IMAGE_NONE:
2867  if (!m_actionViewBackgroundNone->isChecked()) {
2868  m_actionViewBackgroundNone->toggle();
2869  }
2870  break;
2871 
2872  case BACKGROUND_IMAGE_ORIGINAL:
2873  if (!m_actionViewBackgroundOriginal->isChecked ()) {
2874  m_actionViewBackgroundOriginal->toggle();
2875  }
2876  break;
2877 
2878  case BACKGROUND_IMAGE_FILTERED:
2879  if (!m_actionViewBackgroundFiltered->isChecked ()) {
2880  m_actionViewBackgroundFiltered->toggle();
2881  }
2882  break;
2883  }
2884 
2885  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) currentIndex);
2886 }
2887 
2888 void MainWindow::slotCmbCoordSystem(int index)
2889 {
2890  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbCoordSystem";
2891 
2892  CmdSelectCoordSystem *cmd = new CmdSelectCoordSystem (*this,
2893  m_cmdMediator->document(),
2894  index);
2895 
2896  m_cmdMediator->push (cmd);
2897 }
2898 
2899 void MainWindow::slotCmbCurve(int /* index */)
2900 {
2901  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbCurve";
2902 
2903  m_backgroundStateContext->setCurveSelected (m_transformation,
2904  m_cmdMediator->document().modelGridRemoval(),
2905  m_cmdMediator->document().modelColorFilter(),
2906  m_cmbCurve->currentText ());
2907  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
2908  m_cmdMediator->setSelectedCurveName (m_cmbCurve->currentText ()); // Save for next time current coordinate system returns
2909 
2910  updateViewedCurves();
2912  updateFittingWindow();
2913  updateGeometryWindow();
2914 }
2915 
2916 void MainWindow::slotContextMenuEventAxis (QString pointIdentifier)
2917 {
2918  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventAxis point=" << pointIdentifier.toLatin1 ().data ();
2919 
2920  m_digitizeStateContext->handleContextMenuEventAxis (m_cmdMediator,
2921  pointIdentifier);
2922 }
2923 
2924 void MainWindow::slotContextMenuEventGraph (QStringList pointIdentifiers)
2925 {
2926  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventGraph point=" << pointIdentifiers.join(",").toLatin1 ().data ();
2927 
2928  m_digitizeStateContext->handleContextMenuEventGraph (m_cmdMediator,
2929  pointIdentifiers);
2930 }
2931 
2932 void MainWindow::slotDigitizeAxis ()
2933 {
2934  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeAxis";
2935 
2936  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2937  DIGITIZE_STATE_AXIS);
2938  m_cmbCurve->setEnabled (false); // Graph curve is irrelevant in this mode
2939  m_viewPointStyle->setEnabled (true); // Point style is important in this mode
2940  m_viewSegmentFilter->setEnabled (true); // Filtering is important in this mode
2941 }
2942 
2943 void MainWindow::slotDigitizeColorPicker ()
2944 {
2945  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeColorPicker";
2946 
2947  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2948  DIGITIZE_STATE_COLOR_PICKER);
2949  m_cmbCurve->setEnabled (true);
2950  m_viewPointStyle->setEnabled (true);
2951  m_viewSegmentFilter->setEnabled (true);
2952 }
2953 
2954 void MainWindow::slotDigitizeCurve ()
2955 {
2956  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeCurve";
2957 
2958  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2959  DIGITIZE_STATE_CURVE);
2960  m_cmbCurve->setEnabled (true);
2961  m_viewPointStyle->setEnabled (true);
2962  m_viewSegmentFilter->setEnabled (true);
2963 }
2964 
2965 void MainWindow::slotDigitizePointMatch ()
2966 {
2967  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizePointMatch";
2968 
2969  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2970  DIGITIZE_STATE_POINT_MATCH);
2971  m_cmbCurve->setEnabled (true);
2972  m_viewPointStyle->setEnabled (true);
2973  m_viewSegmentFilter->setEnabled (true);
2974 }
2975 
2976 void MainWindow::slotDigitizeScale ()
2977 {
2978  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeScale";
2979 
2980  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2981  DIGITIZE_STATE_SCALE);
2982  m_cmbCurve->setEnabled (false);
2983  m_viewPointStyle->setEnabled (false);
2984  m_viewSegmentFilter->setEnabled (false);
2985 }
2986 
2987 void MainWindow::slotDigitizeSegment ()
2988 {
2989  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeSegment";
2990 
2991  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2992  DIGITIZE_STATE_SEGMENT);
2993  m_cmbCurve->setEnabled (true);
2994  m_viewPointStyle->setEnabled (true);
2995  m_viewSegmentFilter->setEnabled (true);
2996 }
2997 
2998 void MainWindow::slotDigitizeSelect ()
2999 {
3000  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeSelect";
3001 
3002  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3003  DIGITIZE_STATE_SELECT);
3004  m_cmbCurve->setEnabled (false);
3005  m_viewPointStyle->setEnabled (false);
3006  m_viewSegmentFilter->setEnabled (false);
3007 }
3008 
3009 void MainWindow::slotEditCopy ()
3010 {
3011  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCopy";
3012 
3013  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
3014  bool tableFittingIsActive, tableFittingIsCopyable;
3015  bool tableGeometryIsActive, tableGeometryIsCopyable;
3016  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
3017  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
3018 
3019  if (tableFittingIsActive) {
3020 
3021  // Send to FittingWindow
3022  m_dockFittingWindow->doCopy ();
3023 
3024  } else if (tableGeometryIsActive) {
3025 
3026  // Send to GeometryWindow
3027  m_dockGeometryWindow->doCopy ();
3028 
3029  } else {
3030 
3031  // Process curve points in main window
3032  GraphicsItemsExtractor graphicsItemsExtractor;
3033  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
3034  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
3035 
3036  CmdCopy *cmd = new CmdCopy (*this,
3037  m_cmdMediator->document(),
3038  pointIdentifiers);
3039  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
3040  cmd);
3041  }
3042 }
3043 
3044 void MainWindow::slotEditCut ()
3045 {
3046  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCut";
3047 
3048  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
3049  bool tableFittingIsActive, tableFittingIsCopyable;
3050  bool tableGeometryIsActive, tableGeometryIsCopyable;
3051  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
3052  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
3053 
3054  if (tableFittingIsActive || tableGeometryIsActive) {
3055 
3056  // Cannot delete from fitting or geometry windows
3057 
3058  } else {
3059 
3060  // Process curve points in main window
3061  GraphicsItemsExtractor graphicsItemsExtractor;
3062  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
3063  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
3064 
3065  CmdCut *cmd = new CmdCut (*this,
3066  m_cmdMediator->document(),
3067  pointIdentifiers);
3068  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
3069  cmd);
3070  }
3071 }
3072 
3073 void MainWindow::slotEditDelete ()
3074 {
3075  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditDelete";
3076 
3077  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
3078  bool tableFittingIsActive, tableFittingIsCopyable;
3079  bool tableGeometryIsActive, tableGeometryIsCopyable;
3080  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
3081  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
3082 
3083  if (tableFittingIsActive || tableGeometryIsActive) {
3084 
3085  // Cannot delete from fitting or geometry windows
3086 
3087  } else {
3088 
3089  // If this is a map, which has a scale bar with two axis points, then selection of just one axis point
3090  // for deletion should result in deletion of the other point also so this object will enforce that. Otherwise
3091  // this class has no effect below
3092  ScaleBarAxisPointsUnite scaleBarAxisPoints;
3093 
3094  // Process curve points in main window
3095  GraphicsItemsExtractor graphicsItemsExtractor;
3096  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
3097  QStringList pointIdentifiers = scaleBarAxisPoints.unite (m_cmdMediator,
3098  graphicsItemsExtractor.selectedPointIdentifiers (items));
3099 
3100  CmdDelete *cmd = new CmdDelete (*this,
3101  m_cmdMediator->document(),
3102  pointIdentifiers);
3103  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
3104  cmd);
3105  }
3106 }
3107 
3108 void MainWindow::slotEditMenu ()
3109 {
3110  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditMenu";
3111 
3112  m_actionEditPasteAsNew->setEnabled (!QApplication::clipboard()->image().isNull());
3113  m_actionEditPasteAsNewAdvanced->setEnabled (!QApplication::clipboard()->image().isNull());
3114 }
3115 
3116 void MainWindow::slotEditPaste ()
3117 {
3118  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPaste";
3119 }
3120 
3121 void MainWindow::slotEditPasteAsNew ()
3122 {
3123  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPasteAsNew";
3124 
3125  filePaste (IMPORT_TYPE_SIMPLE);
3126 }
3127 
3128 void MainWindow::slotEditPasteAsNewAdvanced ()
3129 {
3130  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPasteAsNewAdvanced";
3131 
3132  filePaste (IMPORT_TYPE_ADVANCED);
3133 }
3134 
3135 void MainWindow::slotFileClose()
3136 {
3137  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileClose";
3138 
3139  if (maybeSave ()) {
3140 
3141  // Transition from defined to undefined. This must be after the clearing of the screen
3142  // since the axes checker screen item (and maybe others) must still exist
3143  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
3144  *m_cmdMediator,
3145  m_transformation,
3146  selectedGraphCurve());
3147 
3148  // Transition to empty state so an inadvertent mouse press does not trigger, for example,
3149  // the creation of an axis point on a non-existent GraphicsScene (=crash)
3150  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3151  DIGITIZE_STATE_EMPTY);
3152 
3153  // Deallocate fitted curve
3154  if (m_fittingCurve != 0) {
3155  m_scene->removeItem (m_fittingCurve);
3156  m_fittingCurve = 0;
3157  }
3158 
3159  // Remove screen objects
3160  m_scene->resetOnLoad ();
3161 
3162  // Remove background
3163  m_backgroundStateContext->close ();
3164 
3165  // Remove scroll bars if they exist
3166  m_scene->setSceneRect (QRectF (0, 0, 1, 1));
3167 
3168  // Remove stale data from fitting window
3169  m_dockFittingWindow->clear ();
3170 
3171  // Remove stale data from geometry window
3172  m_dockGeometryWindow->clear ();
3173 
3174  // Deallocate Document
3175  delete m_cmdMediator;
3176 
3177  // Remove file information
3178  m_cmdMediator = 0;
3179  m_currentFile = "";
3180  m_engaugeFile = "";
3181  setWindowTitle (engaugeWindowTitle ());
3182 
3183  m_gridLines.clear();
3184  updateControls();
3185  }
3186 }
3187 
3188 void MainWindow::slotFileExport ()
3189 {
3190  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileExport";
3191 
3192  if (m_transformation.transformIsDefined()) {
3193 
3194  ExportToFile exportStrategy;
3195  QString filter = QString ("%1;;%2;;All files (*.*)")
3196  .arg (exportStrategy.filterCsv ())
3197  .arg (exportStrategy.filterTsv ());
3198 
3199  // OSX sandbox requires, for the default, a non-empty filename
3200  QString defaultFileName = QString ("%1/%2.%3")
3201  .arg (QDir::currentPath ())
3202  .arg (m_currentFile)
3203  .arg (exportStrategy.fileExtensionCsv ());
3204  QFileDialog dlg;
3205  QString filterCsv = exportStrategy.filterCsv ();
3206  QString fileName = dlg.getSaveFileName (this,
3207  tr("Export"),
3208  defaultFileName,
3209  filter,
3210  &filterCsv);
3211  if (!fileName.isEmpty ()) {
3212 
3213  fileExport(fileName,
3214  exportStrategy);
3215  }
3216  } else {
3217  DlgRequiresTransform dlg ("Export");
3218  dlg.exec ();
3219  }
3220 }
3221 
3222 void MainWindow::slotFileImport ()
3223 {
3224  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImport";
3225 
3226  fileImportWithPrompts (IMPORT_TYPE_SIMPLE);
3227 }
3228 
3229 void MainWindow::slotFileImportAdvanced ()
3230 {
3231  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportAdvanced";
3232 
3233  fileImportWithPrompts (IMPORT_TYPE_ADVANCED);
3234 }
3235 
3236 void MainWindow::slotFileImportDraggedImage(QImage image)
3237 {
3238  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportDraggedImage";
3239 
3240  // No need to check return value from loadImage since there are no prompts that give the user a chance to cancel
3241  loadImage ("",
3242  image,
3243  IMPORT_TYPE_SIMPLE);
3244 }
3245 
3246 void MainWindow::slotFileImportDraggedImageUrl(QUrl url)
3247 {
3248  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportDraggedImageUrl url=" << url.toString ().toLatin1 ().data ();
3249 
3250 #ifdef NETWORKING
3251  m_loadImageFromUrl->startLoadImage (url);
3252 #endif
3253 }
3254 
3255 void MainWindow::slotFileImportImage(QString fileName, QImage image)
3256 {
3257  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportImage fileName=" << fileName.toLatin1 ().data ();
3258 
3259  // No need to check return value from loadImage since there are no prompts that give the user a chance to cancel
3260  loadImage (fileName,
3261  image,
3262  IMPORT_TYPE_SIMPLE);
3263 }
3264 
3265 void MainWindow::slotFileImportImageReplace ()
3266 {
3267  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportImageReplace";
3268 
3269  fileImportWithPrompts (IMPORT_TYPE_IMAGE_REPLACE);
3270 }
3271 
3272 void MainWindow::slotFileOpen()
3273 {
3274  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileOpen";
3275 
3276  if (maybeSave ()) {
3277 
3278  // Allow selection of files with strange suffixes in case the file extension was changed. Since
3279  // the default is the first filter, the wildcard filter is added afterwards (it is the off-nominal case)
3280  QString filter = QString ("%1 (*.%2);; All Files (*.*)")
3281  .arg (ENGAUGE_FILENAME_DESCRIPTION)
3282  .arg (ENGAUGE_FILENAME_EXTENSION);
3283 
3284  QString fileName = QFileDialog::getOpenFileName (this,
3285  tr("Open Document"),
3286  QDir::currentPath (),
3287  filter);
3288  if (!fileName.isEmpty ()) {
3289 
3290  loadDocumentFile (fileName);
3291 
3292  }
3293  }
3294 }
3295 
3296 void MainWindow::slotFileOpenDraggedDigFile (QString fileName)
3297 {
3298  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileOpenDraggedDigFile";
3299 
3300  loadDocumentFile (fileName);
3301 }
3302 
3303 void MainWindow::slotFilePrint()
3304 {
3305  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFilePrint";
3306 
3307  QPrinter printer (QPrinter::HighResolution);
3308  QPrintDialog dlg (&printer, this);
3309  if (dlg.exec() == QDialog::Accepted) {
3310  QPainter painter (&printer);
3311  m_view->render (&painter);
3312  painter.end();
3313  }
3314 }
3315 
3316 bool MainWindow::slotFileSave()
3317 {
3318  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileSave";
3319 
3320  if (m_engaugeFile.isEmpty()) {
3321  return slotFileSaveAs();
3322  } else {
3323  return saveDocumentFile (m_engaugeFile);
3324  }
3325 }
3326 
3327 bool MainWindow::slotFileSaveAs()
3328 {
3329  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileSaveAs";
3330 
3331  // Append engauge file extension if it is not already there
3332  QString filenameDefault = m_currentFile;
3333  if (!m_currentFile.endsWith (ENGAUGE_FILENAME_EXTENSION)) {
3334  filenameDefault = QString ("%1.%2")
3335  .arg (m_currentFile)
3336  .arg (ENGAUGE_FILENAME_EXTENSION);
3337  }
3338 
3339  if (!m_engaugeFile.isEmpty()) {
3340  filenameDefault = m_engaugeFile;
3341  }
3342 
3343  QString filterDigitizer = QString ("%1 (*.%2)")
3344  .arg (ENGAUGE_FILENAME_DESCRIPTION)
3345  .arg (ENGAUGE_FILENAME_EXTENSION);
3346  QString filterAll ("All files (*. *)");
3347 
3348  QStringList filters;
3349  filters << filterDigitizer;
3350  filters << filterAll;
3351 
3352  QFileDialog dlg(this);
3353  dlg.setFileMode (QFileDialog::AnyFile);
3354  dlg.selectNameFilter (filterDigitizer);
3355  dlg.setNameFilters (filters);
3356 #if defined(OSX_DEBUG) || defined(OSX_RELEASE)
3357 #else
3358  // Prevent hang in OSX
3359  dlg.setWindowModality(Qt::WindowModal);
3360 #endif
3361  dlg.setAcceptMode(QFileDialog::AcceptSave);
3362  dlg.selectFile(filenameDefault);
3363  if (dlg.exec()) {
3364 
3365  QStringList files = dlg.selectedFiles();
3366  return saveDocumentFile(files.at(0));
3367  }
3368 
3369  return false;
3370 }
3371 
3372 void MainWindow::slotFittingWindowClosed()
3373 {
3374  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFittingWindowClosed";
3375 
3376  m_actionViewFittingWindow->setChecked (false);
3377 }
3378 
3379 void MainWindow::slotFittingWindowCurveFit(FittingCurveCoefficients fittingCurveCoef,
3380  double xMin,
3381  double xMax,
3382  bool isLogXTheta,
3383  bool isLogYRadius)
3384 {
3385  // Do not output elements in fittingCurveCoef here since that list may be empty
3386  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFittingWindowCurveFit"
3387  << " order=" << fittingCurveCoef.size() - 1;
3388 
3389  if (m_fittingCurve != 0) {
3390  m_scene->removeItem (m_fittingCurve);
3391  delete m_fittingCurve;
3392  m_fittingCurve = 0;
3393  }
3394 
3395  m_fittingCurve = new FittingCurve (fittingCurveCoef,
3396  xMin,
3397  xMax,
3398  isLogXTheta,
3399  isLogYRadius,
3400  m_transformation);
3401  m_fittingCurve->setVisible (m_actionViewFittingWindow->isChecked ());
3402  m_scene->addItem (m_fittingCurve);
3403 }
3404 
3405 void MainWindow::slotGeometryWindowClosed()
3406 {
3407  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotGeometryWindowClosed";
3408 
3409  m_actionViewGeometryWindow->setChecked (false);
3410 }
3411 
3412 void MainWindow::slotHelpAbout()
3413 {
3414  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpAbout";
3415 
3416  DlgAbout dlg (*this);
3417  dlg.exec ();
3418 }
3419 
3420 void MainWindow::slotHelpTutorial()
3421 {
3422  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpTutorial";
3423 
3424  m_tutorialDlg->show ();
3425  m_tutorialDlg->exec ();
3426 }
3427 
3428 void MainWindow::slotKeyPress (Qt::Key key,
3429  bool atLeastOneSelectedItem)
3430 {
3431  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotKeyPress"
3432  << " key=" << QKeySequence (key).toString().toLatin1 ().data ()
3433  << " atLeastOneSelectedItem=" << (atLeastOneSelectedItem ? "true" : "false");
3434 
3435  m_digitizeStateContext->handleKeyPress (m_cmdMediator,
3436  key,
3437  atLeastOneSelectedItem);
3438 }
3439 
3440 void MainWindow::slotLoadStartupFiles ()
3441 {
3442  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotLoadStartupFiles";
3443 
3444  ENGAUGE_ASSERT (m_loadStartupFiles.count() > 0);
3445 
3446  QString fileName = m_loadStartupFiles.front(); // Get next file name
3447  m_loadStartupFiles.pop_front(); // Remove next file name
3448 
3449  // Load next file into this instance of Engauge
3450  LoadFileInfo loadFileInfo;
3451  if (loadFileInfo.loadsAsDigFile(fileName)) {
3452 
3453  loadDocumentFile (fileName);
3454 
3455  } else {
3456 
3457  fileImport (fileName,
3458  IMPORT_TYPE_SIMPLE);
3459 
3460  }
3461 
3462  if (m_loadStartupFiles.count() > 0) {
3463 
3464  // Fork off another instance of this application to handle the remaining files recursively. New process
3465  // is detached so killing/terminating this process does not automatically kill the child process(es) also
3466  QProcess::startDetached (QCoreApplication::applicationFilePath(),
3467  m_loadStartupFiles);
3468  }
3469 }
3470 
3471 void MainWindow::slotMouseMove (QPointF pos)
3472 {
3473 // LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotMouseMove pos=" << QPointFToString (pos).toLatin1 ().data ();
3474 
3475  // Ignore mouse moves before Document is loaded
3476  if (m_cmdMediator != 0) {
3477 
3478  QString needMoreText = (modeMap () ?
3479  QObject::tr ("Need scale bar") :
3480  QObject::tr ("Need more axis points"));
3481 
3482  // Get status bar coordinates
3483  QString coordsScreen, coordsGraph, resolutionGraph;
3484  m_transformation.coordTextForStatusBar (pos,
3485  coordsScreen,
3486  coordsGraph,
3487  resolutionGraph,
3488  needMoreText);
3489 
3490  // Update status bar coordinates
3491  m_statusBar->setCoordinates (coordsScreen,
3492  coordsGraph,
3493  resolutionGraph);
3494 
3495  // There used to be a call to updateGraphicsLinesToMatchGraphicsPoints here, but that resulted
3496  // in hundreds of gratuitous log messages as the cursor was moved around, and nothing important happened
3497 
3498  m_digitizeStateContext->handleMouseMove (m_cmdMediator,
3499  pos);
3500  }
3501 }
3502 
3503 void MainWindow::slotMousePress (QPointF pos)
3504 {
3505  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMousePress";
3506 
3507  m_scene->resetPositionHasChangedFlags();
3508 
3509  m_digitizeStateContext->handleMousePress (m_cmdMediator,
3510  pos);
3511 }
3512 
3513 void MainWindow::slotMouseRelease (QPointF pos)
3514 {
3515  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMouseRelease";
3516 
3517  if (pos.x() < 0 || pos.y() < 0) {
3518 
3519  // Cursor is outside the image so drop this event. However, call updateControls since this may be
3520  // a click-and-drag to select in which case the controls (especially Copy and Cut) reflect the new selection
3521  updateControls ();
3522 
3523  } else {
3524 
3525  // Cursor is within the image so process this as a normal mouse release
3526  m_digitizeStateContext->handleMouseRelease (m_cmdMediator,
3527  pos);
3528  }
3529 }
3530 
3531 void MainWindow::slotRecentFileAction ()
3532 {
3533  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileAction";
3534 
3535  QAction *action = qobject_cast<QAction*>(sender ());
3536 
3537  if (action) {
3538  QString fileName = action->data().toString();
3539  loadDocumentFile (fileName);
3540  }
3541 }
3542 
3543 void MainWindow::slotRecentFileClear ()
3544 {
3545  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileClear";
3546 
3547  QStringList emptyList;
3548 
3549  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
3550  settings.setValue (SETTINGS_RECENT_FILE_LIST,
3551  emptyList);
3552 
3553  updateRecentFileList();
3554 }
3555 
3556 void MainWindow::slotRedoTextChanged (const QString &text)
3557 {
3558  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotRedoTextChanged";
3559 
3560  QString completeText ("Redo");
3561  if (!text.isEmpty ()) {
3562  completeText += QString (" \"%1\"").arg (text);
3563  }
3564  m_actionEditRedo->setText (completeText);
3565 }
3566 
3567 void MainWindow::slotSettingsAxesChecker ()
3568 {
3569  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsAxesChecker";
3570 
3571  m_dlgSettingsAxesChecker->load (*m_cmdMediator);
3572  m_dlgSettingsAxesChecker->show ();
3573 }
3574 
3575 void MainWindow::slotSettingsColorFilter ()
3576 {
3577  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsColorFilter";
3578 
3579  m_dlgSettingsColorFilter->load (*m_cmdMediator);
3580  m_dlgSettingsColorFilter->show ();
3581 }
3582 
3583 void MainWindow::slotSettingsCoords ()
3584 {
3585  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCoords";
3586 
3587  m_dlgSettingsCoords->load (*m_cmdMediator);
3588  m_dlgSettingsCoords->show ();
3589 }
3590 
3591 void MainWindow::slotSettingsCurveAddRemove ()
3592 {
3593  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveAddRemove";
3594 
3595  m_dlgSettingsCurveAddRemove->load (*m_cmdMediator);
3596  m_dlgSettingsCurveAddRemove->show ();
3597 }
3598 
3599 void MainWindow::slotSettingsCurveProperties ()
3600 {
3601  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveProperties";
3602 
3603  m_dlgSettingsCurveProperties->load (*m_cmdMediator);
3604  m_dlgSettingsCurveProperties->setCurveName (selectedGraphCurve ());
3605  m_dlgSettingsCurveProperties->show ();
3606 }
3607 
3608 void MainWindow::slotSettingsDigitizeCurve ()
3609 {
3610  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsDigitizeCurve";
3611 
3612  m_dlgSettingsDigitizeCurve->load (*m_cmdMediator);
3613  m_dlgSettingsDigitizeCurve->show ();
3614 }
3615 
3616 void MainWindow::slotSettingsExportFormat ()
3617 {
3618  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsExportFormat";
3619 
3620  if (transformIsDefined()) {
3621  m_dlgSettingsExportFormat->load (*m_cmdMediator);
3622  m_dlgSettingsExportFormat->show ();
3623  } else {
3624  DlgRequiresTransform dlg ("Export settings");
3625  dlg.exec();
3626  }
3627 }
3628 
3629 void MainWindow::slotSettingsGeneral ()
3630 {
3631  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGeneral";
3632 
3633  m_dlgSettingsGeneral->load (*m_cmdMediator);
3634  m_dlgSettingsGeneral->show ();
3635 }
3636 
3637 void MainWindow::slotSettingsGridDisplay()
3638 {
3639  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridDisplay";
3640 
3641  m_dlgSettingsGridDisplay->load (*m_cmdMediator);
3642  m_dlgSettingsGridDisplay->show ();
3643 }
3644 
3645 void MainWindow::slotSettingsGridRemoval ()
3646 {
3647  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridRemoval";
3648 
3649  m_dlgSettingsGridRemoval->load (*m_cmdMediator);
3650  m_dlgSettingsGridRemoval->show ();
3651 }
3652 
3653 void MainWindow::slotSettingsPointMatch ()
3654 {
3655  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsPointMatch";
3656 
3657  m_dlgSettingsPointMatch->load (*m_cmdMediator);
3658  m_dlgSettingsPointMatch->show ();
3659 }
3660 
3661 void MainWindow::slotSettingsSegments ()
3662 {
3663  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsSegments";
3664 
3665  m_dlgSettingsSegments->load (*m_cmdMediator);
3666  m_dlgSettingsSegments->show ();
3667 }
3668 
3669 void MainWindow::slotTableStatusChange ()
3670 {
3671  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTableStatusChange";
3672 
3673  // This slot is called when either window in FittingWindow or GeometryWindow loses/gains focus. This is
3674  // so the Copy menu item can be updated
3675  updateControls ();
3676 }
3677 
3678 void MainWindow::slotSettingsMainWindow ()
3679 {
3680  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsMainWindow";
3681 
3682  m_dlgSettingsMainWindow->loadMainWindowModel (*m_cmdMediator,
3683  m_modelMainWindow);
3684  m_dlgSettingsMainWindow->show ();
3685 }
3686 
3687 void MainWindow::slotTimeoutRegressionErrorReport ()
3688 {
3689  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionErrorReport"
3690  << " cmdStackIndex=" << m_cmdMediator->index()
3691  << " cmdStackCount=" << m_cmdMediator->count();
3692 
3693  if (m_cmdStackShadow->canRedo()) {
3694 
3695  // Always reset current directory before the command. This guarantees the upcoming redo step will work
3696  QDir::setCurrent (m_startupDirectory);
3697 
3698  m_cmdStackShadow->slotRedo();
3699 
3700  // Always reset current directory after the command. This guarantees the final export to file will work
3701  QDir::setCurrent (m_startupDirectory);
3702 
3703  } else {
3704 
3705 #ifndef OSX_RELEASE
3706  exportAllCoordinateSystemsAfterRegressionTests ();
3707 #endif
3708 
3709  // Regression test has finished so exit. We unset the dirty flag so there is no prompt
3710  m_cmdMediator->setClean();
3711  close();
3712 
3713  }
3714 }
3715 
3716 void MainWindow::slotTimeoutRegressionFileCmdScript ()
3717 {
3718  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionFileCmdScript";
3719 
3720  if (m_fileCmdScript->canRedo()) {
3721 
3722  // Always reset current directory before the command. This guarantees the upcoming redo step will work
3723  QDir::setCurrent (m_startupDirectory);
3724 
3725  m_fileCmdScript->redo(*this);
3726 
3727  // Always reset current directory after the command. This guarantees the final export to file will work
3728  QDir::setCurrent (m_startupDirectory);
3729 
3730  } else {
3731 
3732  // Script file might already have closed the Document so export only if last was not closed
3733  if (m_cmdMediator != 0) {
3734 
3735 #ifndef OSX_RELEASE
3736  exportAllCoordinateSystemsAfterRegressionTests ();
3737 #endif
3738 
3739  // We unset the dirty flag so there is no "Save changes?" prompt
3740  m_cmdMediator->setClean();
3741 
3742  }
3743 
3744  // Regression test has finished so exit
3745  close();
3746 
3747  }
3748 }
3749 
3750 void MainWindow::slotUndoTextChanged (const QString &text)
3751 {
3752  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotUndoTextChanged";
3753 
3754  QString completeText ("Undo");
3755  if (!text.isEmpty ()) {
3756  completeText += QString (" \"%1\"").arg (text);
3757  }
3758  m_actionEditUndo->setText (completeText);
3759 }
3760 
3761 void MainWindow::slotViewGridLines ()
3762 {
3763  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotViewGridLines";
3764 
3765  updateGridLines ();
3766 }
3767 
3768 void MainWindow::slotViewGroupBackground(QAction *action)
3769 {
3770  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupBackground";
3771 
3772  // Set the combobox
3773  BackgroundImage backgroundImage;
3774  int indexBackground;
3775  if (action == m_actionViewBackgroundNone) {
3776  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_NONE));
3777  backgroundImage = BACKGROUND_IMAGE_NONE;
3778  } else if (action == m_actionViewBackgroundOriginal) {
3779  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
3780  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
3781  } else if (action == m_actionViewBackgroundFiltered) {
3782  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_FILTERED));
3783  backgroundImage = BACKGROUND_IMAGE_FILTERED;
3784  } else {
3785  ENGAUGE_ASSERT (false);
3786 
3787  // Defaults if assert is disabled so execution continues
3788  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
3789  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
3790  }
3791 
3792  m_cmbBackground->setCurrentIndex (indexBackground);
3793  m_backgroundStateContext->setBackgroundImage (backgroundImage);
3794 }
3795 
3796 void MainWindow::slotViewGroupCurves(QAction * /* action */)
3797 {
3798  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupCurves";
3799 
3800  updateViewedCurves ();
3801 }
3802 
3803 void MainWindow::slotViewGroupStatus(QAction *action)
3804 {
3805  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupStatus";
3806 
3807  ENGAUGE_CHECK_PTR (m_statusBar); // At startup, make sure status bar is already set up when View menu gets initialized
3808 
3809  if (action == m_actionStatusNever) {
3810  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_NEVER);
3811  } else if (action == m_actionStatusTemporary) {
3812  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_TEMPORARY);
3813  } else {
3814  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_ALWAYS);
3815  }
3816 }
3817 
3818 void MainWindow::slotViewToolBarBackground ()
3819 {
3820  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarBackground";
3821 
3822  if (m_actionViewBackground->isChecked ()) {
3823  m_toolBackground->show();
3824  } else {
3825  m_toolBackground->hide();
3826  }
3827 }
3828 
3829 void MainWindow::slotViewToolBarChecklistGuide ()
3830 {
3831  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarChecklistGuide";
3832 
3833  if (m_actionViewChecklistGuide->isChecked ()) {
3834  m_dockChecklistGuide->show();
3835  } else {
3836  m_dockChecklistGuide->hide();
3837  }
3838 }
3839 
3840 void MainWindow::slotViewToolBarCoordSystem ()
3841 {
3842  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarCoordSystem";
3843 
3844  if (m_actionViewCoordSystem->isChecked ()) {
3845  m_toolCoordSystem->show();
3846  } else {
3847  m_toolCoordSystem->hide();
3848  }
3849 }
3850 
3851 void MainWindow::slotViewToolBarDigitize ()
3852 {
3853  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarDigitize";
3854 
3855  if (m_actionViewDigitize->isChecked ()) {
3856  m_toolDigitize->show();
3857  } else {
3858  m_toolDigitize->hide();
3859  }
3860 }
3861 
3862 void MainWindow::slotViewToolBarFittingWindow()
3863 {
3864  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarFittingWindow";
3865 
3866  if (m_actionViewFittingWindow->isChecked()) {
3867  m_dockFittingWindow->show ();
3868  if (m_fittingCurve != 0) {
3869  m_fittingCurve->setVisible (true);
3870  }
3871  } else {
3872  m_dockFittingWindow->hide ();
3873  if (m_fittingCurve != 0) {
3874  m_fittingCurve->setVisible (false);
3875  }
3876  }
3877 }
3878 
3879 void MainWindow::slotViewToolBarGeometryWindow ()
3880 {
3881  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarGeometryWindow";
3882 
3883  if (m_actionViewGeometryWindow->isChecked ()) {
3884  m_dockGeometryWindow->show();
3885  } else {
3886  m_dockGeometryWindow->hide();
3887  }
3888 }
3889 
3890 void MainWindow::slotViewToolBarSettingsViews ()
3891 {
3892  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarSettingsViews";
3893 
3894  if (m_actionViewSettingsViews->isChecked ()) {
3895  m_toolSettingsViews->show();
3896  } else {
3897  m_toolSettingsViews->hide();
3898  }
3899 }
3900 
3901 void MainWindow::slotViewToolTips ()
3902 {
3903  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolTips";
3904 
3905  loadToolTips();
3906 }
3907 
3908 void MainWindow::slotViewZoom(int zoom)
3909 {
3910  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom";
3911 
3912  // Update zoom controls and apply the zoom factor
3913  switch ((ZoomFactor) zoom) {
3914  case ZOOM_16_TO_1:
3915  m_actionZoom16To1->setChecked(true);
3916  slotViewZoom16To1 ();
3917  break;
3918  case ZOOM_8_TO_1:
3919  m_actionZoom8To1->setChecked(true);
3920  slotViewZoom8To1 ();
3921  break;
3922  case ZOOM_4_TO_1:
3923  m_actionZoom4To1->setChecked(true);
3924  slotViewZoom4To1 ();
3925  break;
3926  case ZOOM_2_TO_1:
3927  m_actionZoom2To1->setChecked(true);
3928  slotViewZoom2To1 ();
3929  break;
3930  case ZOOM_1_TO_1:
3931  m_actionZoom1To1->setChecked(true);
3932  slotViewZoom1To1 ();
3933  break;
3934  case ZOOM_1_TO_2:
3935  m_actionZoom1To2->setChecked(true);
3936  slotViewZoom1To2 ();
3937  break;
3938  case ZOOM_1_TO_4:
3939  m_actionZoom1To4->setChecked(true);
3940  slotViewZoom1To4 ();
3941  break;
3942  case ZOOM_1_TO_8:
3943  m_actionZoom1To8->setChecked(true);
3944  slotViewZoom1To8 ();
3945  break;
3946  case ZOOM_1_TO_16:
3947  m_actionZoom1To16->setChecked(true);
3948  slotViewZoom1To16 ();
3949  break;
3950  case ZOOM_FILL:
3951  m_actionZoomFill->setChecked(true);
3952  slotViewZoomFill ();
3953  break;
3954  }
3955 }
3956 
3957 void MainWindow::slotViewZoom16To1 ()
3958 {
3959  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom16To1";
3960 
3961  QTransform transform;
3962  transform.scale (16.0, 16.0);
3963  m_view->setTransform (transform);
3964  emit signalZoom(ZOOM_16_TO_1);
3965 }
3966 
3967 void MainWindow::slotViewZoom8To1 ()
3968 {
3969  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom8To1";
3970 
3971  QTransform transform;
3972  transform.scale (8.0, 8.0);
3973  m_view->setTransform (transform);
3974  emit signalZoom(ZOOM_8_TO_1);
3975 }
3976 
3977 void MainWindow::slotViewZoom4To1 ()
3978 {
3979  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom4To1";
3980 
3981  QTransform transform;
3982  transform.scale (4.0, 4.0);
3983  m_view->setTransform (transform);
3984  emit signalZoom(ZOOM_4_TO_1);
3985 }
3986 
3987 void MainWindow::slotViewZoom2To1 ()
3988 {
3989  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom2To1";
3990 
3991  QTransform transform;
3992  transform.scale (2.0, 2.0);
3993  m_view->setTransform (transform);
3994  emit signalZoom(ZOOM_2_TO_1);
3995 }
3996 
3997 void MainWindow::slotViewZoom1To1 ()
3998 {
3999  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom1To1";
4000 
4001  QTransform transform;
4002  transform.scale (1.0, 1.0);
4003  m_view->setTransform (transform);
4004  emit signalZoom(ZOOM_1_TO_1);
4005 }
4006 
4007 void MainWindow::slotViewZoom1To2 ()
4008 {
4009  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom1To2";
4010 
4011  QTransform transform;
4012  transform.scale (0.5, 0.5);
4013  m_view->setTransform (transform);
4014  emit signalZoom(ZOOM_1_TO_2);
4015 }
4016 
4017 void MainWindow::slotViewZoom1To4 ()
4018 {
4019  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom1To4";
4020 
4021  QTransform transform;
4022  transform.scale (0.25, 0.25);
4023  m_view->setTransform (transform);
4024  emit signalZoom(ZOOM_1_TO_4);
4025 }
4026 
4027 void MainWindow::slotViewZoom1To8 ()
4028 {
4029  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom1To8";
4030 
4031  QTransform transform;
4032  transform.scale (0.125, 0.125);
4033  m_view->setTransform (transform);
4034  emit signalZoom(ZOOM_1_TO_8);
4035 }
4036 
4037 void MainWindow::slotViewZoom1To16 ()
4038 {
4039  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom1To16";
4040 
4041  QTransform transform;
4042  transform.scale (0.0625, 0.0625);
4043  m_view->setTransform (transform);
4044  emit signalZoom(ZOOM_1_TO_16);
4045 }
4046 
4047 void MainWindow::slotViewZoomFill ()
4048 {
4049  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomFill";
4050 
4051  m_backgroundStateContext->fitInView (*m_view);
4052 
4053  emit signalZoom(ZOOM_FILL);
4054 }
4055 
4056 void MainWindow::slotViewZoomIn ()
4057 {
4058  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomIn";
4059 
4060  // Try to zoom in. First determine what the next zoom factor should be
4061 
4062  bool goto16To1 = false, goto8To1 = false, goto4To1 = false, goto2To1 = false;
4063  bool goto1To1 = false;
4064  bool goto1To2 = false, goto1To4 = false, goto1To8 = false, goto1To16 = false;
4065  if (m_actionZoomFill->isChecked ()) {
4066 
4067  // Zooming in means user probably wants the more squished direction to be zoomed in by one step
4068  double xScale = m_view->transform().m11();
4069  double yScale = m_view->transform().m22();
4070  double scale = qMin(xScale, yScale);
4071  if (scale < 0.125) {
4072  goto1To8 = true;
4073  } else if (scale < 0.25) {
4074  goto1To4 = true;
4075  } else if (scale < 0.5) {
4076  goto1To2 = true;
4077  } else if (scale < 1) {
4078  goto1To1 = true;
4079  } else if (scale < 2) {
4080  goto2To1 = true;
4081  } else if (scale < 4) {
4082  goto4To1 = true;
4083  } else if (scale < 8) {
4084  goto8To1 = true;
4085  } else {
4086  goto1To16 = true;
4087  }
4088  } else {
4089  goto16To1 = m_actionZoom8To1->isChecked ();
4090  goto8To1 = m_actionZoom4To1->isChecked ();
4091  goto4To1 = m_actionZoom2To1->isChecked ();
4092  goto2To1 = m_actionZoom1To1->isChecked ();
4093  goto1To1 = m_actionZoom1To2->isChecked ();
4094  goto1To2 = m_actionZoom1To4->isChecked ();
4095  goto1To4 = m_actionZoom1To8->isChecked ();
4096  goto1To8 = m_actionZoom1To16->isChecked ();
4097  }
4098 
4099  // Update controls and apply zoom factor
4100  if (goto16To1) {
4101  m_actionZoom16To1->setChecked (true);
4102  slotViewZoom16To1 ();
4103  } else if (goto8To1) {
4104  m_actionZoom8To1->setChecked (true);
4105  slotViewZoom8To1 ();
4106  } else if (goto4To1) {
4107  m_actionZoom4To1->setChecked (true);
4108  slotViewZoom4To1 ();
4109  } else if (goto2To1) {
4110  m_actionZoom2To1->setChecked (true);
4111  slotViewZoom2To1 ();
4112  } else if (goto1To1) {
4113  m_actionZoom1To1->setChecked (true);
4114  slotViewZoom1To1 ();
4115  } else if (goto1To2) {
4116  m_actionZoom1To2->setChecked (true);
4117  slotViewZoom1To2 ();
4118  } else if (goto1To4) {
4119  m_actionZoom1To4->setChecked (true);
4120  slotViewZoom1To4 ();
4121  } else if (goto1To8) {
4122  m_actionZoom1To8->setChecked (true);
4123  slotViewZoom1To8 ();
4124  } else if (goto1To16) {
4125  m_actionZoom1To16->setChecked (true);
4126  slotViewZoom1To16 ();
4127  }
4128 }
4129 
4130 void MainWindow::slotViewZoomInFromWheelEvent ()
4131 {
4132  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomInFromWheelEvent";
4133 
4134  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
4135  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
4136 
4137  // Anchor the zoom to the cursor position
4138  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
4139 
4140  // Forward this event
4141  slotViewZoomIn ();
4142 
4143  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
4144  }
4145 }
4146 
4147 void MainWindow::slotViewZoomOut ()
4148 {
4149  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOut";
4150 
4151  // Try to zoom out. First determine what the next zoom factor should be
4152 
4153  bool goto16To1 = false, goto8To1 = false, goto4To1 = false, goto2To1 = false;
4154  bool goto1To1 = false;
4155  bool goto1To2 = false, goto1To4 = false, goto1To8 = false, goto1To16 = false;
4156  if (m_actionZoomFill->isChecked ()) {
4157 
4158  // Zooming out means user probably wants the less squished direction to be zoomed out by one step
4159  double xScale = m_view->transform().m11();
4160  double yScale = m_view->transform().m22();
4161  double scale = qMax(xScale, yScale);
4162  if (scale > 8) {
4163  goto8To1 = true;
4164  } else if (scale > 4) {
4165  goto4To1 = true;
4166  } else if (scale > 2) {
4167  goto2To1 = true;
4168  } else if (scale > 1) {
4169  goto1To1 = true;
4170  } else if (scale > 0.5) {
4171  goto1To2 = true;
4172  } else if (scale > 0.25) {
4173  goto1To4 = true;
4174  } else if (scale > 0.125) {
4175  goto1To8 = true;
4176  } else {
4177  goto1To16 = true;
4178  }
4179  } else {
4180  goto8To1 = m_actionZoom16To1->isChecked ();
4181  goto4To1 = m_actionZoom8To1->isChecked ();
4182  goto2To1 = m_actionZoom4To1->isChecked ();
4183  goto1To1 = m_actionZoom2To1->isChecked ();
4184  goto1To2 = m_actionZoom1To1->isChecked ();
4185  goto1To4 = m_actionZoom1To2->isChecked ();
4186  goto1To8 = m_actionZoom1To4->isChecked ();
4187  goto1To16 = m_actionZoom1To8->isChecked ();
4188  }
4189 
4190  // Update controls and apply zoom factor
4191  if (goto1To16) {
4192  m_actionZoom1To16->setChecked (true);
4193  slotViewZoom1To16 ();
4194  } else if (goto1To8) {
4195  m_actionZoom1To8->setChecked (true);
4196  slotViewZoom1To8 ();
4197  } else if (goto1To4) {
4198  m_actionZoom1To4->setChecked (true);
4199  slotViewZoom1To4 ();
4200  } else if (goto1To2) {
4201  m_actionZoom1To2->setChecked (true);
4202  slotViewZoom1To2 ();
4203  } else if (goto1To1) {
4204  m_actionZoom1To1->setChecked (true);
4205  slotViewZoom1To1 ();
4206  } else if (goto2To1) {
4207  m_actionZoom2To1->setChecked (true);
4208  slotViewZoom2To1 ();
4209  } else if (goto4To1) {
4210  m_actionZoom4To1->setChecked (true);
4211  slotViewZoom4To1 ();
4212  } else if (goto8To1) {
4213  m_actionZoom8To1->setChecked (true);
4214  slotViewZoom8To1 ();
4215  } else if (goto16To1) {
4216  m_actionZoom16To1->setChecked (true);
4217  slotViewZoom16To1 ();
4218  }
4219 }
4220 
4221 void MainWindow::slotViewZoomOutFromWheelEvent ()
4222 {
4223  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOutFromWheelEvent";
4224 
4225  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
4226  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
4227 
4228  // Anchor the zoom to the cursor position
4229  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
4230 
4231  // Forward this event
4232  slotViewZoomOut ();
4233 
4234  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
4235  }
4236 }
4237 
4238 void MainWindow::startRegressionTestErrorReport(const QString &regressionInputFile)
4239 {
4240  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestErrorReport";
4241 
4242  // In order for point-deleting commands to work (CmdCut, CmdDelete) in the regression tests, we need to
4243  // reset the Point identifier index here:
4244  // 1) after loading of the file which has increased the index value to greater than 0
4245  // 2) before running any commands since those commands implicitly assume the index is zero
4247 
4248  // Save output/export file name
4249  m_regressionFile = exportFilenameFromInputFilename (regressionInputFile);
4250 
4251  m_timerRegressionErrorReport = new QTimer();
4252  m_timerRegressionErrorReport->setSingleShot(false);
4253  connect (m_timerRegressionErrorReport, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionErrorReport()));
4254 
4255  m_timerRegressionErrorReport->start(REGRESSION_INTERVAL);
4256 }
4257 
4258 void MainWindow::startRegressionTestFileCmdScript()
4259 {
4260  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestFileCmdScript";
4261 
4262  m_timerRegressionFileCmdScript = new QTimer();
4263  m_timerRegressionFileCmdScript->setSingleShot(false);
4264  connect (m_timerRegressionFileCmdScript, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionFileCmdScript()));
4265 
4266  m_timerRegressionFileCmdScript->start(REGRESSION_INTERVAL);
4267 }
4268 
4270 {
4271  return m_transformation;
4272 }
4273 
4275 {
4276  return m_transformation.transformIsDefined();
4277 }
4278 
4280 {
4281  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommand";
4282 
4283  ENGAUGE_CHECK_PTR (m_cmdMediator);
4284 
4285  // Update transformation stuff, including the graph coordinates of every point in the Document, so coordinates in
4286  // status bar are up to date. Point coordinates in Document are also updated
4287  updateAfterCommandStatusBarCoords ();
4288 
4289  updateHighlightOpacity ();
4290 
4291  // Update graphics. Effectively, these steps do very little (just needed for highlight opacity)
4292  m_digitizeStateContext->updateAfterPointAddition (); // May or may not be needed due to point addition
4293 
4294  updateControls ();
4295  updateChecklistGuide ();
4296  updateFittingWindow ();
4297  updateGeometryWindow();
4298 
4299  // Final action at the end of a redo/undo is to checkpoint the Document and GraphicsScene to log files
4300  // so proper state can be verified
4301  writeCheckpointToLogFile ();
4302 
4303  // Since focus may have drifted over to Geometry Window or some other control we se focus on the GraphicsView
4304  // so the cursor is appropriate for the current state (otherwise it often ends up as default arrow)
4305  m_view->setFocus ();
4306 }
4307 
4308 void MainWindow::updateAfterCommandStatusBarCoords ()
4309 {
4310  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommandStatusBarCoords";
4311 
4312  // For some reason, mapFromGlobal(QCursor::pos) differs from event->pos by a little bit. We must compensate for
4313  // this so cursor coordinates in status bar match the DlgEditPointAxis inputs initially. After the mouse moves
4314  // the problem disappears since event->pos is available and QCursor::pos is no longer needed
4315  const QPoint HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT (1, 1);
4316 
4317  Transformation m_transformationBefore (m_transformation);
4318 
4319  updateTransformationAndItsDependencies();
4320 
4321  // Trigger state transitions for transformation if appropriate
4322  if (!m_transformationBefore.transformIsDefined() && m_transformation.transformIsDefined()) {
4323 
4324  // Transition from undefined to defined
4325  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_DEFINED,
4326  *m_cmdMediator,
4327  m_transformation,
4328  selectedGraphCurve());
4329 
4330  } else if (m_transformationBefore.transformIsDefined() && !m_transformation.transformIsDefined()) {
4331 
4332  // Transition from defined to undefined
4333  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
4334  *m_cmdMediator,
4335  m_transformation,
4336  selectedGraphCurve());
4337 
4338  } else if (m_transformation.transformIsDefined() && (m_transformationBefore != m_transformation)) {
4339 
4340  // There was not a define/undefined or undefined/defined transition, but the transformation changed so we
4341  // need to update the Checker
4342  m_transformationStateContext->updateAxesChecker(*m_cmdMediator,
4343  m_transformation);
4344 
4345  }
4346 
4347  QPoint posLocal = m_view->mapFromGlobal (QCursor::pos ()) - HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT;
4348  QPointF posScreen = m_view->mapToScene (posLocal);
4349 
4350  slotMouseMove (posScreen); // Update the status bar coordinates to reflect the newly updated transformation
4351 }
4352 
4354 {
4355  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterMouseRelease";
4356 
4357  updateControls ();
4358 }
4359 
4360 void MainWindow::updateChecklistGuide ()
4361 {
4362  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateChecklistGuide";
4363 
4364  m_isDocumentExported = true; // Set for next line and for all checklist guide updates after this
4365  m_dockChecklistGuide->update (*m_cmdMediator,
4366  m_isDocumentExported);
4367 }
4368 
4369 void MainWindow::updateControls ()
4370 {
4371  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateControls"
4372  << " selectedItems=" << m_scene->selectedItems().count();
4373 
4374  m_cmbBackground->setEnabled (!m_currentFile.isEmpty ());
4375 
4376  m_actionImportImageReplace->setEnabled (m_cmdMediator != 0);
4377 #ifndef OSX_RELEASE
4378  m_menuFileOpenRecent->setEnabled ((m_actionRecentFiles.count () > 0) &&
4379  (m_actionRecentFiles.at(0)->isVisible ())); // Need at least one visible recent file entry
4380 #endif
4381  m_actionClose->setEnabled (!m_currentFile.isEmpty ());
4382  m_actionSave->setEnabled (!m_currentFile.isEmpty ());
4383  m_actionSaveAs->setEnabled (!m_currentFile.isEmpty ());
4384  m_actionExport->setEnabled (!m_currentFile.isEmpty ());
4385  m_actionPrint->setEnabled (!m_currentFile.isEmpty ());
4386 
4387  if (m_cmdMediator == 0) {
4388  m_actionEditUndo->setEnabled (false);
4389  m_actionEditRedo->setEnabled (false);
4390  } else {
4391  m_actionEditUndo->setEnabled (m_cmdMediator->canUndo ());
4392  m_actionEditRedo->setEnabled (m_cmdMediator->canRedo () || m_cmdStackShadow->canRedo ());
4393  }
4394  bool tableFittingIsActive, tableFittingIsCopyable;
4395  bool tableGeometryIsActive, tableGeometryIsCopyable;
4396  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
4397  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
4398  m_actionEditCut->setEnabled (!tableFittingIsActive &&
4399  !tableGeometryIsActive &&
4400  m_scene->selectedItems().count () > 0);
4401  m_actionEditCopy->setEnabled ((!tableFittingIsActive && !tableGeometryIsActive && m_scene->selectedItems().count () > 0) ||
4402  (tableFittingIsActive && tableFittingIsCopyable) ||
4403  (tableGeometryIsActive && tableGeometryIsCopyable));
4404  m_actionEditPaste->setEnabled (false);
4405  m_actionEditDelete->setEnabled (!tableFittingIsActive &&
4406  !tableGeometryIsActive &&
4407  m_scene->selectedItems().count () > 0);
4408  // m_actionEditPasteAsNew and m_actionEditPasteAsNewAdvanced are updated when m_menuEdit is about to be shown
4409 
4410  m_actionDigitizeAxis->setEnabled (modeGraph ());
4411  m_actionDigitizeScale->setEnabled (modeMap ());
4412  m_actionDigitizeCurve ->setEnabled (!m_currentFile.isEmpty ());
4413  m_actionDigitizePointMatch->setEnabled (!m_currentFile.isEmpty ());
4414  m_actionDigitizeColorPicker->setEnabled (!m_currentFile.isEmpty ());
4415  m_actionDigitizeSegment->setEnabled (!m_currentFile.isEmpty ());
4416  m_actionDigitizeSelect->setEnabled (!m_currentFile.isEmpty ());
4417  if (m_transformation.transformIsDefined()) {
4418  m_actionViewGridLines->setEnabled (true);
4419  } else {
4420  m_actionViewGridLines->setEnabled (false);
4421  m_actionViewGridLines->setChecked (false);
4422  }
4423  m_actionViewBackground->setEnabled (!m_currentFile.isEmpty());
4424  m_actionViewChecklistGuide->setEnabled (!m_dockChecklistGuide->browserIsEmpty());
4425  m_actionViewDigitize->setEnabled (!m_currentFile.isEmpty ());
4426  m_actionViewSettingsViews->setEnabled (!m_currentFile.isEmpty ());
4427 
4428  m_actionSettingsCoords->setEnabled (!m_currentFile.isEmpty ());
4429  m_actionSettingsCurveAddRemove->setEnabled (!m_currentFile.isEmpty ());
4430  m_actionSettingsCurveProperties->setEnabled (!m_currentFile.isEmpty ());
4431  m_actionSettingsDigitizeCurve->setEnabled (!m_currentFile.isEmpty ());
4432  m_actionSettingsExport->setEnabled (!m_currentFile.isEmpty ());
4433  m_actionSettingsColorFilter->setEnabled (!m_currentFile.isEmpty ());
4434  m_actionSettingsAxesChecker->setEnabled (!m_currentFile.isEmpty ());
4435  m_actionSettingsGridDisplay->setEnabled (!m_currentFile.isEmpty () && m_transformation.transformIsDefined());
4436  m_actionSettingsGridRemoval->setEnabled (!m_currentFile.isEmpty ());
4437  m_actionSettingsPointMatch->setEnabled (!m_currentFile.isEmpty ());
4438  m_actionSettingsSegments->setEnabled (!m_currentFile.isEmpty ());
4439  m_actionSettingsGeneral->setEnabled (!m_currentFile.isEmpty ());
4440 
4441  m_groupBackground->setEnabled (!m_currentFile.isEmpty ());
4442  m_groupCurves->setEnabled (!m_currentFile.isEmpty ());
4443  m_groupZoom->setEnabled (!m_currentFile.isEmpty ());
4444 
4445  m_actionZoomIn->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
4446  m_actionZoomOut->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
4447 }
4448 
4449 void MainWindow::updateCoordSystem(CoordSystemIndex coordSystemIndex)
4450 {
4451  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateCoordSystem";
4452 
4453  // Set current curve in the Document and in the MainWindow combobox together so they are in sync. Setting
4454  // the selected curve prevents a crash in updateTransformationAndItsDependencies
4455  m_cmdMediator->document().setCoordSystemIndex (coordSystemIndex);
4456  loadCurveListFromCmdMediator ();
4457 
4458  updateTransformationAndItsDependencies(); // Transformation state may have changed
4459  updateSettingsAxesChecker(m_cmdMediator->document().modelAxesChecker()); // Axes checker dependes on transformation state
4460 
4461  // Nice trick for showing that a new coordinate system is in effect is to show the axes checker
4462  m_transformationStateContext->updateAxesChecker (*m_cmdMediator,
4463  m_transformation);
4464 
4466 }
4467 
4468 void MainWindow::updateDigitizeStateIfSoftwareTriggered (DigitizeState digitizeState)
4469 {
4470  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
4471 
4472  switch (digitizeState) {
4473  case DIGITIZE_STATE_AXIS:
4474  m_actionDigitizeAxis->setChecked(true);
4475  slotDigitizeAxis(); // Call the slot that the setChecked call fails to trigger
4476  break;
4477 
4478  case DIGITIZE_STATE_COLOR_PICKER:
4479  m_actionDigitizeColorPicker->setChecked(true);
4480  slotDigitizeColorPicker(); // Call the slot that the setChecked call fails to trigger
4481  break;
4482 
4483  case DIGITIZE_STATE_CURVE:
4484  m_actionDigitizeCurve->setChecked(true);
4485  slotDigitizeCurve(); // Call the slot that the setChecked call fails to trigger
4486  break;
4487 
4488  case DIGITIZE_STATE_EMPTY:
4489  break;
4490 
4491  case DIGITIZE_STATE_POINT_MATCH:
4492  m_actionDigitizePointMatch->setChecked(true);
4493  slotDigitizePointMatch(); // Call the slot that the setChecked call fails to trigger
4494  break;
4495 
4496  case DIGITIZE_STATE_SCALE:
4497  m_actionDigitizeScale->setChecked(true);
4498  slotDigitizeScale(); // Call the slot that the setChecked call fails to trigger
4499  break;
4500 
4501  case DIGITIZE_STATE_SEGMENT:
4502  m_actionDigitizeSegment->setChecked(true);
4503  slotDigitizeSegment(); // Call the slot that the setChecked call fails to trigger
4504  break;
4505 
4506  case DIGITIZE_STATE_SELECT:
4507  m_actionDigitizeSelect->setChecked(true);
4508  slotDigitizeSelect(); // Call the slot that the setChecked call fails to trigger
4509  break;
4510 
4511  default:
4512  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
4513  break;
4514  }
4515 }
4516 
4517 void MainWindow::updateFittingWindow ()
4518 {
4519  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateFittingWindow";
4520 
4521  if (m_cmdMediator != 0 &&
4522  m_cmbCurve != 0) {
4523 
4524  // Update fitting window
4525  m_dockFittingWindow->update (*m_cmdMediator,
4526  m_modelMainWindow,
4527  m_cmbCurve->currentText (),
4528  m_transformation);
4529  }
4530 }
4531 
4532 void MainWindow::updateGeometryWindow ()
4533 {
4534  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGeometryWindow";
4535 
4536  if (m_cmdMediator != 0 &&
4537  m_cmbCurve != 0) {
4538 
4539  // Update geometry window
4540  m_dockGeometryWindow->update (*m_cmdMediator,
4541  m_modelMainWindow,
4542  m_cmbCurve->currentText (),
4543  m_transformation);
4544  }
4545 }
4546 
4548 {
4549  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGraphicsLinesToMatchGraphicsPoints";
4550 
4552  m_transformation);
4553 }
4554 
4555 void MainWindow::updateGridLines ()
4556 {
4557  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGridLines";
4558 
4559  // Remove old grid lines
4560  m_gridLines.clear ();
4561 
4562  // Create new grid lines
4563  GridLineFactory factory (*m_scene,
4564  m_cmdMediator->document().modelCoords());
4565  factory.createGridLinesForEvenlySpacedGrid (m_cmdMediator->document().modelGridDisplay(),
4566  m_cmdMediator->document(),
4567  m_modelMainWindow,
4568  m_transformation,
4569  m_gridLines);
4570 
4571  m_gridLines.setVisible (m_actionViewGridLines->isChecked());
4572 }
4573 
4574 void MainWindow::updateHighlightOpacity ()
4575 {
4576  if (m_cmdMediator != 0) {
4577 
4578  // Update the QGraphicsScene with the populated Curves. This requires the points in the Document to be already updated
4579  // by updateAfterCommandStatusBarCoords
4580  m_scene->updateAfterCommand (*m_cmdMediator,
4581  m_modelMainWindow.highlightOpacity(),
4582  m_dockGeometryWindow);
4583  }
4584 }
4585 
4586 void MainWindow::updateRecentFileList()
4587 {
4588  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateRecentFileList";
4589 
4590 #ifndef OSX_RELEASE
4591  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
4592  QStringList recentFilePaths = settings.value(SETTINGS_RECENT_FILE_LIST).toStringList();
4593 
4594  // Determine the desired size of the path list
4595  unsigned int count = recentFilePaths.size();
4596  if (count > MAX_RECENT_FILE_LIST_SIZE) {
4597  count = MAX_RECENT_FILE_LIST_SIZE;
4598  }
4599 
4600  // Add visible entries
4601  unsigned int i;
4602  for (i = 0; i < count; i++) {
4603  QString strippedName = QFileInfo (recentFilePaths.at(i)).fileName();
4604  m_actionRecentFiles.at (i)->setText (strippedName);
4605  m_actionRecentFiles.at (i)->setData (recentFilePaths.at (i));
4606  m_actionRecentFiles.at (i)->setVisible (true);
4607  }
4608 
4609  // Hide any extra entries
4610  for (i = count; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
4611  m_actionRecentFiles.at (i)->setVisible (false);
4612  }
4613 #endif
4614 }
4615 
4617 {
4618  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsAxesChecker";
4619 
4620  m_cmdMediator->document().setModelAxesChecker(modelAxesChecker);
4621  if (m_transformation.transformIsDefined()) {
4622  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_DEFINED,
4623  *m_cmdMediator,
4624  m_transformation,
4625  m_cmbCurve->currentText());
4626  } else {
4627  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
4628  *m_cmdMediator,
4629  m_transformation,
4630  m_cmbCurve->currentText());
4631  }
4632 }
4633 
4635 {
4636  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsColorFilter";
4637 
4638  m_cmdMediator->document().setModelColorFilter(modelColorFilter);
4639  m_backgroundStateContext->updateColorFilter (m_transformation,
4640  m_cmdMediator->document().modelGridRemoval(),
4641  modelColorFilter,
4642  m_cmbCurve->currentText());
4643  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
4645 }
4646 
4648 {
4649  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCoords";
4650 
4651  m_cmdMediator->document().setModelCoords(modelCoords);
4652 }
4653 
4655 {
4656  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveAddRemove";
4657 
4658  m_cmdMediator->document().setCurvesGraphs (curvesGraphs);
4659  loadCurveListFromCmdMediator();
4661 }
4662 
4664 {
4665  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveStyles";
4666 
4667  m_scene->updateCurveStyles(modelCurveStyles);
4668  m_cmdMediator->document().setModelCurveStyles(modelCurveStyles);
4670 }
4671 
4673 {
4674  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsDigitizeCurve";
4675 
4676  m_cmdMediator->document().setModelDigitizeCurve(modelDigitizeCurve);
4677  m_digitizeStateContext->updateModelDigitizeCurve (m_cmdMediator,
4678  modelDigitizeCurve);
4679 }
4680 
4682 {
4683  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsExportFormat";
4684 
4685  m_cmdMediator->document().setModelExport (modelExport);
4686 }
4687 
4689 {
4690  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGeneral";
4691 
4692  m_cmdMediator->document().setModelGeneral(modelGeneral);
4693 }
4694 
4696 {
4697  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridDisplay";
4698 
4699  m_cmdMediator->document().setModelGridDisplay(modelGridDisplay);
4700 }
4701 
4703 {
4704  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridRemoval";
4705 
4706  m_cmdMediator->document().setModelGridRemoval(modelGridRemoval);
4707 }
4708 
4710 {
4711  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
4712 
4713  if (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_ONLY ||
4714  m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) {
4715 
4716  m_actionZoomIn->setShortcut (tr (""));
4717  m_actionZoomOut->setShortcut (tr (""));
4718 
4719  } else {
4720 
4721  m_actionZoomIn->setShortcut (tr ("+"));
4722  m_actionZoomOut->setShortcut (tr ("-"));
4723 
4724  }
4725 
4726  if ((m_scene != 0) &&
4727  (m_cmdMediator != 0)) {
4728  m_scene->updateCurveStyles(m_cmdMediator->document().modelCurveStyles());
4729  }
4730 
4731  updateHighlightOpacity();
4732  updateWindowTitle();
4733  updateFittingWindow(); // Forward the drag and drop choice
4734  updateGeometryWindow(); // Forward the drag and drop choice
4735 }
4736 
4738 {
4739  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
4740 
4741  m_modelMainWindow = modelMainWindow;
4743 }
4744 
4746 {
4747  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsPointMatch";
4748 
4749  m_cmdMediator->document().setModelPointMatch(modelPointMatch);
4750 }
4751 
4753 {
4754  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsSegments";
4755 
4756  m_cmdMediator->document().setModelSegments(modelSegments);
4757  m_digitizeStateContext->updateModelSegments(modelSegments);
4758 }
4759 
4760 void MainWindow::updateSmallDialogs ()
4761 {
4762  m_dlgSettingsAxesChecker->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4763  m_dlgSettingsColorFilter->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4764  m_dlgSettingsCoords->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4765  m_dlgSettingsCurveAddRemove->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4766  m_dlgSettingsCurveProperties->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4767  m_dlgSettingsDigitizeCurve->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4768  m_dlgSettingsExportFormat->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4769  m_dlgSettingsGeneral->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4770  m_dlgSettingsGridDisplay->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4771  m_dlgSettingsGridRemoval->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4772  m_dlgSettingsMainWindow->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4773  m_dlgSettingsPointMatch->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4774  m_dlgSettingsSegments->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4775 }
4776 
4777 void MainWindow::updateTransformationAndItsDependencies()
4778 {
4779  m_transformation.update (!m_currentFile.isEmpty (),
4780  *m_cmdMediator,
4781  m_modelMainWindow);
4782 
4783  // Grid removal is affected by new transformation above
4784  m_backgroundStateContext->setCurveSelected (m_transformation,
4785  m_cmdMediator->document().modelGridRemoval(),
4786  m_cmdMediator->document().modelColorFilter(),
4787  m_cmbCurve->currentText ());
4788 
4789  // Grid display is also affected by new transformation above, if there was a transition into defined state
4790  // in which case that transition triggered the initialization of the grid display parameters
4791  updateGridLines();
4792 }
4793 
4794 void MainWindow::updateViewedCurves ()
4795 {
4796  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewedCurves";
4797 
4798  if (m_actionViewCurvesAll->isChecked ()) {
4799 
4800  m_scene->showCurves (true, true);
4801 
4802  } else if (m_actionViewCurvesSelected->isChecked ()) {
4803 
4804  m_scene->showCurves (true, false, selectedGraphCurve ());
4805 
4806  } else if (m_actionViewCurvesNone->isChecked ()) {
4807 
4808  m_scene->showCurves (false);
4809 
4810  } else {
4811  ENGAUGE_ASSERT (false);
4812  }
4813 }
4814 
4816 {
4817  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewsOfSettings";
4818 
4819  QString activeCurve = m_digitizeStateContext->activeCurve ();
4820 
4821  updateViewsOfSettings (activeCurve);
4822 }
4823 
4824 void MainWindow::updateViewsOfSettings (const QString &activeCurve)
4825 {
4826  if (activeCurve.isEmpty ()) {
4827 
4828  m_viewPointStyle->unsetPointStyle ();
4829  m_viewSegmentFilter->unsetColorFilterSettings ();
4830 
4831 
4832  } else {
4833 
4834  PointStyle pointStyle = m_cmdMediator->document().modelCurveStyles().curveStyle(activeCurve).pointStyle();
4835  m_viewPointStyle->setPointStyle (pointStyle);
4836 
4837  ColorFilterSettings colorFilterSettings = m_cmdMediator->document().modelColorFilter().colorFilterSettings(activeCurve);
4838  m_viewSegmentFilter->setColorFilterSettings (colorFilterSettings,
4839  m_cmdMediator->pixmap ());
4840 
4841  }
4842 }
4843 
4844 void MainWindow::updateWindowTitle ()
4845 {
4846  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateWindowTitle";
4847 
4848  const QString PLACEHOLDER ("[*]");
4849 
4850  QString title = QString (tr ("Engauge Digitizer %1")
4851  .arg (VERSION_NUMBER));
4852 
4853  QString fileNameMaybeStripped;
4854  if (!m_currentFileWithPathAndFileExtension.isEmpty()) {
4855 
4856  QFileInfo fileInfo (m_currentFileWithPathAndFileExtension);
4857 
4858  switch (m_modelMainWindow.mainTitleBarFormat())
4859  {
4860  case MAIN_TITLE_BAR_FORMAT_NO_PATH:
4861  fileNameMaybeStripped = fileInfo.baseName(); // Remove file extension and path for "clean look"
4862  break;
4863 
4864  case MAIN_TITLE_BAR_FORMAT_PATH:
4865  fileNameMaybeStripped = m_currentFileWithPathAndFileExtension;
4866  break;
4867  }
4868 
4869  title += QString (": %1")
4870  .arg (fileNameMaybeStripped);
4871  }
4872 
4873  // To prevent "QWidget::setWindowModified: The window title does not contain a [*] placeholder" warnings,
4874  // we always append a placeholder
4875  title += PLACEHOLDER;
4876 
4877  setWindowTitle (title);
4878 }
4879 
4881 {
4882  ENGAUGE_CHECK_PTR (m_view);
4883  return *m_view;
4884 }
4885 
4887 {
4888  ENGAUGE_CHECK_PTR (m_view);
4889  return *m_view;
4890 }
4891 
4892 void MainWindow::writeCheckpointToLogFile ()
4893 {
4894  // Document
4895  QString checkpointDoc;
4896  QTextStream strDoc (&checkpointDoc);
4897  m_cmdMediator->document().printStream(INDENTATION_PAST_TIMESTAMP,
4898  strDoc);
4899 
4900  // Scene
4901  QString checkpointScene;
4902  QTextStream strScene (&checkpointScene);
4903  m_scene->printStream (INDENTATION_PAST_TIMESTAMP,
4904  strScene);
4905 
4906  // Skip slow string manipulation if BEFORE call to LOG4CPP_DEBUG_S
4907  if (mainCat->getPriority() == log4cpp::Priority::DEBUG) {
4908 
4909  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::writeCheckpointToLogFile\n"
4910  << "--------------DOCUMENT CHECKPOINT START----------" << "\n"
4911  << checkpointDoc.toLatin1().data()
4912  << "---------------DOCUMENT CHECKPOINT END-----------" << "\n"
4913  << "----------------SCENE CHECKPOINT START-----------" << "\n"
4914  << checkpointScene.toLatin1().data()
4915  << "-----------------SCENE CHECKPOINT END------------" ;
4916  }
4917 }
void addCoordSystems(unsigned int numberCoordSystemToAdd)
Add some number (0 or more) of additional coordinate systems.
Definition: Document.cpp:149
bool canRedo() const
Return true if there is a command available.
Factory class for generating the points, composed of QGraphicsItem objects, along a GridLine...
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void updateGraphicsLinesToMatchGraphicsPoints(const CurveStyles &modelCurveStyles, const Transformation &transformation)
A mouse move has just occurred so move the selected points, since they were dragged.
bool overrideCsvTsv() const
Get method for csv/tsv format override.
QImage imageFiltered() const
Background image that has been filtered for the current curve. This asserts if a curve-specific image...
void updateCoordSystem(CoordSystemIndex coordSystemIndex)
Select a different CoordSystem.
Model for DlgSettingsGeneral and CmdSettingsGeneral.
CurveStyle curveStyle(const QString &curveName) const
CurveStyle in specified curve.
Definition: CurveStyles.cpp:79
void unsetPointStyle()
Apply no PointStyle.
Given a set of point identifiers, if a map is in effect (with its two axis endpoints) then both axis ...
void setPixmap(const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const DocumentModelColorFilter &modelColorFilter, const QPixmap &pixmapOriginal, const QString &curveSelected)
Update the images of all states, rather than just the current state.
Dialog for sending error report with networking.
void setColorFilterSettings(const ColorFilterSettings &colorFilterSettings, const QPixmap &pixmap)
Apply the color filter of the currently selected curve. The pixmap is included so the background colo...
void setCurveName(const QString &curveName)
Load information for the specified curve name. When called externally, the load method must have been...
bool canRedo() const
Returns true if there is at least one command on the stack.
void createGhosts(QGraphicsScene &scene)
Create ghosts from the path/rect/polygon lists.
Definition: Ghosts.cpp:78
void updateColorFilter(const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const DocumentModelColorFilter &colorFilter, const QString &curveSelected)
Apply color filter settings.
Model for DlgSettingsPointMatch and CmdSettingsPointMatch.
Returns information about files.
Definition: LoadFileInfo.h:13
void updateAfterPointAddition()
Update the graphics attributes.
Color filter parameters for one curve. For a class, this is handled the same as LineStyle and PointSt...
void resetOnLoad(CmdMediator *cmdMediator)
Resetting makes re-initializes for documents after the first.
void updateSettingsMainWindow(const MainWindowModel &modelMainWindow)
Update with new main window properties.
void setSelectedCurveName(const QString &selectedCurveName)
Save curve name that is selected for the current coordinate system, for the next time the coordinate ...
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void setStatusBarMode(StatusBarMode statusBarMode)
Set the status bar visibility mode.
Definition: StatusBar.cpp:143
Model for DlgSettingsGridDisplay and CmdSettingsGridDisplay.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded...
Command for cutting all selected Points.
Definition: CmdCut.h:18
void setModelAxesChecker(const DocumentModelAxesChecker &modelAxesChecker)
Set method for DocumentModelAxesChecker.
Definition: Document.cpp:949
void setModelGridRemoval(const DocumentModelGridRemoval &modelGridRemoval)
Set method for DocumentModelGridRemoval.
Definition: Document.cpp:1026
Dialog for saving error report to local hard drive.
void clear()
Deallocate and remove all grid lines.
Definition: GridLines.cpp:19
void updateDigitizeStateIfSoftwareTriggered(DigitizeState digitizeState)
After software-triggered state transition, this method manually triggers the action as if user had cl...
void setDragDropExport(bool dragDropExport)
Set method for drag and drop export.
static void setIdentifierIndex(unsigned int identifierIndex)
Reset the current index while performing a Redo.
Definition: Point.cpp:466
void printStream(QString indentation, QTextStream &str)
Debugging method that supports print method of this class and printStream method of some other class(...
Wrapper around the Poppler library.
Definition: Pdf.h:28
Class that displays the current Segment Filter in a MainWindow toolbar.
Wrapper around OpenJPEG library, in C, for opening jpeg2000 files.
Definition: Jpeg2000.h:26
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
Dialog for editing Segments settings, for DigitizeStateSegment.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void fitInView(GraphicsView &view)
Zoom so background fills the window.
void setModelPointMatch(const DocumentModelPointMatch &modelPointMatch)
Set method for DocumentModelPointMatch.
Definition: Document.cpp:1033
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
Dialog for editing point match settings, for DigitizeStatePointMatch.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void updateModelDigitizeCurve(CmdMediator *cmdMediator, const DocumentModelDigitizeCurve &modelDigitizeCurve)
Update the digitize curve settings.
void setModelGeneral(const DocumentModelGeneral &modelGeneral)
Set method for DocumentModelGeneral.
Definition: Document.cpp:1012
void setEnabled(bool enabled)
Show the style with semi-transparency or full-transparency to indicate if associated Curve is active ...
Context class for transformation state machine.
Model for DlgSettingsCurveProperties and CmdSettingsCurveProperties.
Definition: CurveStyles.h:22
void createGridLinesForEvenlySpacedGrid(const DocumentModelGridDisplay &modelGridDisplay, const Document &document, const MainWindowModel &modelMainWindow, const Transformation &transformation, GridLines &gridLines)
Create a rectangular (cartesian) or annular (polar) grid of evenly spaced grid lines.
DocumentModelGridRemoval modelGridRemoval() const
Get method for DocumentModelGridRemoval.
Definition: Document.cpp:735
Wrapper around the QImage class for read and importing non-PDF files.
Definition: NonPdf.h:26
Dockable help window.
Definition: HelpWindow.h:16
void updateSettingsCurveAddRemove(const CurvesGraphs &curvesGraphs)
Update with new curves.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
bool loadsAsDigFile(const QString &urlString) const
Returns true if specified file name can be loaded as a DIG file.
void setModelSegments(const DocumentModelSegments &modelSegments)
Set method for DocumentModelSegments.
Definition: Document.cpp:1040
unsigned int coordSystemIndexToBeRestored() const
Coordinate system index that was active before the ghosts.
Definition: Ghosts.cpp:73
void handleContextMenuEventAxis(CmdMediator *cmdMediator, const QString &pointIdentifier)
See DigitizeStateAbstractBase::handleContextMenuEventAxis.
void updateAfterMouseRelease()
Call MainWindow::updateControls (which is private) after the very specific case - a mouse press/relea...
MainWindow(const QString &errorReportFile, const QString &fileCmdScriptFile, bool isRegressionTest, bool isGnuplot, bool isReset, QStringList loadStartupFiles, QWidget *parent=0)
Single constructor.
Definition: MainWindow.cpp:136
void exportToFile(const DocumentModelExportFormat &modelExport, const Document &document, const MainWindowModel &modelMainWindow, const Transformation &transformation, QTextStream &str) const
Export Document points according to the settings.
void handleCurveChange(CmdMediator *cmdMediator)
See DigitizeStateAbstractBase::handleCurveChange.
void setCoordinates(const QString &coordsScreen, const QString &coordsGraph, const QString &resolutionGraph)
Populate the coordinates fields. Unavailable values are empty. Html-encoding to highlight with colors...
Definition: StatusBar.cpp:124
QString reasonForUnsuccessfulRead() const
See Document::reasonForUnsuccessfulRead.
void handleContextMenuEventGraph(CmdMediator *cmdMediator, const QStringList &pointIdentifiers)
See DigitizeStateAbstractBase::handleContextMenuEventGraph.
PointStyle pointStyle() const
Get method for PointStyle.
Definition: CurveStyle.cpp:75
void cmdFileClose()
Close file. This is called from a file script command.
Definition: MainWindow.cpp:288
void setModelGridDisplay(const DocumentModelGridDisplay &modelGridDisplay)
Set method for DocumentModelGridDisplay.
Definition: Document.cpp:1019
void updateAfterCommand(CmdMediator &cmdMediator, double highlightOpacity, GeometryWindow *geometryWindow)
Update the Points and their Curves after executing a command.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void updateViewsOfSettings(const QString &activeCurve)
Update curve-specific view of settings. Private version gets active curve name from DigitizeStateCont...
void setHighlightOpacity(double highlightOpacity)
Set method for highlight opacity.
Class for showing points and lines for all coordinate systems simultaneously, even though the code no...
Definition: Ghosts.h:26
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
QString activeCurve() const
Curve name for active Curve. This can include AXIS_CURVE_NAME, and empty string.
QString selectedCurveName() const
Currently selected curve name. This is used to set the selected curve combobox in MainWindow...
void slotRedo()
Move next command from list to CmdMediator. Noop if there are no more commands.
DocumentAxesPointsRequired documentAxesPointsRequired() const
Get method for DocumentAxesPointsRequired.
Definition: Document.cpp:361
bool successfulRead() const
Wrapper for Document::successfulRead.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
DocumentModelColorFilter modelColorFilter() const
Get method for DocumentModelColorFilter.
Definition: Document.cpp:686
virtual void update(const CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow, const QString &curveSelected, const Transformation &transformation)
Populate the table with the specified Curve.
void getTableStatus(bool &tableIsActive, bool &tableIsCopyable) const
Give table status so MainWindow can determine if table can be copied.
void setModelDigitizeCurve(const DocumentModelDigitizeCurve &modelDigitizeCurve)
Set method for DocumentModelDigitizeCurve.
Definition: Document.cpp:998
void triggerStateTransition(TransformationState transformationState, CmdMediator &cmdMediator, const Transformation &transformation, const QString &selectedGraphCurve)
Trigger a state transition to be performed immediately.
QPixmap pixmap() const
See Document::pixmap.
Window that displays the geometry information, as a table, for the current curve. ...
void cmdFileOpen(const QString &fileName)
Open file. This is called from a file script command.
Definition: MainWindow.cpp:314
void setDocumentAxesPointsRequired(DocumentAxesPointsRequired documentAxesPointsRequired)
Set the number of axes points required.
virtual void update(const CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow, const QString &curveSelected, const Transformation &transformation)
Populate the table with the specified Curve.
double highlightOpacity() const
Get method for highlight opacity.
CmdMediator * cmdMediator()
Accessor for commands to process the Document.
Definition: MainWindow.cpp:322
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
void setModelCoords(const DocumentModelCoords &modelCoords)
Set method for DocumentModelCoords.
Definition: Document.cpp:974
const ColorFilterSettings colorFilterSettings(const QString &curveName) const
Get method for copying one color filter. Cannot return just a reference or else there is a warning ab...
void wakeUp()
Enable all widgets in the status bar. This is called just after a Document becomes active...
Definition: StatusBar.cpp:274
BackgroundImage selectOriginal(BackgroundImage backgroundImage)
Make original background visible, for DigitizeStateColorPicker.
QStringList supportedImageWildcards() const
List the supported jpeg2000 file extensions, for filtering import files.
Definition: Jpeg2000.cpp:305
static void bindToMainWindow(const MainWindow *mainWindow)
Bind to MainWindow so this class can access the command stack.
ZoomFactorInitial zoomFactorInitial() const
Get method for initial zoom factor.
Dialog for editing grid removal settings.
Dialog for editing exporting settings.
QString filterCsv() const
QFileDialog filter for CSV files.
void setDelimiter(ExportDelimiter exportDelimiter)
Set method for delimiter.
unsigned int numberCoordSystem() const
Number of coordinate systems selected by user.
void setLocale(QLocale::Language language, QLocale::Country country)
Set method for locale given attributes.
void handleKeyPress(CmdMediator *cmdMediator, Qt::Key key, bool atLeastOneSelectedItem)
See DigitizeStateAbstractBase::handleKeyPress.
void uploadErrorReport(const QString &report)
Upload the error report asynchronously.
void setPixmap(const QImage &image)
Set method for the background pixmap.
Definition: Document.cpp:1047
bool smallDialogs() const
Get method for small dialogs flag.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
Transformation transformation() const
Return read-only copy of transformation.
void showTemporaryMessage(const QString &temporaryMessage)
Show temporary message in status bar.
Dialog for editing curve names settings.
StatusBarMode statusBarMode() const
Current mode for status bar visibility. This is tracked locally so this class knows when to hide/show...
Definition: StatusBar.h:42
void setImageIsLoaded(CmdMediator *cmdMediator, bool imageIsLoaded)
Set the image so QGraphicsView cursor and drag mode are accessible.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void setCoordSystemIndex(CoordSystemIndex coordSystemIndex)
Set the index of current active CoordSystem.
Definition: Document.cpp:916
void updateSettingsDigitizeCurve(const DocumentModelDigitizeCurve &modelDigitizeCurve)
Update with new curve digitization styles.
bool load(const QString &filename, QImage &image) const
Load image from jpeg2000 file.
Definition: Jpeg2000.cpp:192
void loadMainWindowModel(CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow)
Replaced load method since the main window settings are independent of document, unlike other DlgSett...
This class consolidates utility routines that deal with graphics items that are getting extracted fro...
Tutorial using a strategy like a comic strip with decision points deciding which panels appear...
Definition: TutorialDlg.h:19
void cmdFileExport(const QString &fileName)
Export file. This is called from a file script command.
Definition: MainWindow.cpp:296
Strategy class for exporting to a file. This strategy is external to the Document class so that class...
Definition: ExportToFile.h:25
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
Dockable text window containing checklist guide.
void setModelExport(const DocumentModelExportFormat &modelExport)
Set method for DocumentModelExportFormat.
Definition: Document.cpp:1005
Model for DlgSettingsDigitizeCurve and CmdSettingsDigitizeCurve.
GraphicsView & view()
View for the QImage and QGraphicsItems, without const.
void saveErrorReportFileAndExit(const char *comment, const char *file, int line, const char *context) const
Save error report and exit.
Affine transformation between screen and graph coordinates, based on digitized axis points...
Dialog for editing filtering settings.
DocumentAxesPointsRequired documentAxesPointsRequired() const
Number of axes points selected by user.
Details for a specific Point.
Definition: PointStyle.h:20
Class for exporting during regression, when the Transformation has not yet been defined.
Container for all graph curves. The axes point curve is external to this class.
Definition: CurvesGraphs.h:24
void setBackgroundImage(BackgroundImage backgroundImage)
Transition to the specified state. This method is used by classes outside of the state machine to tri...
ZoomControl zoomControl() const
Get method for zoom control.
Model for DlgSettingsColorFilter and CmdSettingsColorFilter.
void coordTextForStatusBar(QPointF cursorScreen, QString &coordsScreen, QString &coordsGraph, QString &resolutionGraph, const QString &needMoreText)
Return string descriptions of cursor coordinates for status bar.
Wrapper around QStatusBar to manage permanent widgets.
Definition: StatusBar.h:21
GraphicsScene & scene()
Scene container for the QImage and QGraphicsItems.
void updateSettingsGridDisplay(const DocumentModelGridDisplay &modelGridDisplay)
Update with new grid display properties.
void setEnabled(bool enabled)
Show the style with semi-transparency or full-transparency to indicate if associated Curve is active ...
void updateSettingsCurveStyles(const CurveStyles &modelCurveStyles)
Update with new curve styles.
Client for interacting with Engauge server.
Definition: NetworkClient.h:16
ImportCropping importCropping() const
Get method for import cropping.
void setModelCurveStyles(const CurveStyles &modelCurveStyles)
Set method for CurveStyles.
Definition: Document.cpp:981
bool transformIsDefined() const
Return true if all three axis points have been defined.
Context class that manages the background image state machine.
QGraphicsView class with event handling added. Typically the events are sent to the active digitizing...
Definition: GraphicsView.h:20
virtual void doCopy()
Copy the current selection to the clipboard.
bool isGnuplot() const
Get method for gnuplot flag.
Container for all DigitizeStateAbstractBase subclasses. This functions as the context class in a stan...
Model for DlgSettingsMainWindow.
void appendNewCmd(CmdMediator *cmdMediator, QUndoCommand *cmd)
Append just-created QUndoCommand to command stack. This is called from DigitizeStateAbstractBase subc...
CoordSystemIndex coordSystemIndex() const
Index of current active CoordSystem.
Definition: Document.cpp:312
void updateModelSegments(const DocumentModelSegments &modelSegments)
Update the segments given the new settings.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
int maximumGridLines() const
Maximum number of grid lines.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded...
Dialog for editing general settings.
void resetPositionHasChangedFlags()
Reset positionHasChanged flag for all items. Typically this is done as part of mousePressEvent.
DocumentModelGridDisplay modelGridDisplay() const
Get method for DocumentModelGridDisplay.
Definition: Document.cpp:728
QStringList unite(CmdMediator *cmdMediator, const QStringList &pointIdentifiersIn) const
Add.
void setModelColorFilter(const DocumentModelColorFilter &modelColorFilter)
Set method for DocumentModelColorFilter.
Definition: Document.cpp:956
void close()
Open Document is being closed so remove the background.
QString xmlToUpload() const
Xml to be uploaded. Includes document if user has approved.
Model for DlgSettingsCoords and CmdSettingsCoords.
void setVisible(bool visible)
Make all grid lines visible or hidden.
Definition: GridLines.cpp:38
void updateAfterCommand()
See GraphicsScene::updateAfterCommand.
Curve that overlays the current scene so the regression-fitted curve is visible.
Definition: FittingCurve.h:16
void updateSettingsColorFilter(const DocumentModelColorFilter &modelColorFilter)
Update with new color filter properties.
Dialog for editing grid display settings.
NonPdfReturn load(const QString &fileName, QImage &image, ImportCropping importCropping, bool isErrorReportRegressionTest) const
Try to load the specified file. Success is indicated in the function return value.
Definition: NonPdf.cpp:18
void setCurveSelected(const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const DocumentModelColorFilter &modelColorFilter, const QString &curveSelected)
Update the selected curve.
int pdfResolution() const
Get method for resolution of imported PDF files, in dots per inch.
Command for deleting all selected Points.
Definition: CmdDelete.h:18
void setMaximumGridLines(int maximumGridLines)
Set method for maximum number of grid lines.
Dialog for editing DigitizeStateCurve settings.
void updateSettingsAxesChecker(const DocumentModelAxesChecker &modelAxesChecker)
Update with new axes indicator properties.
void updateSettingsPointMatch(const DocumentModelPointMatch &modelPointMatch)
Update with new point match properties.
void updateSettingsGeneral(const DocumentModelGeneral &modelGeneral)
Update with new general properties.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void redo(MainWindow &mainWindow)
Apply the next command. Requires non-empty stack.
void setPointStyle(const PointStyle &pointStyle)
Apply the PointStyle of the currently selected curve.
void printStream(QString indentation, QTextStream &str) const
Debugging method that supports print method of this class and printStream method of some other class(...
Definition: Document.cpp:840
void updateSettingsGridRemoval(const DocumentModelGridRemoval &modelGridRemoval)
Update with new grid removal properties.
Class that displays a view of the current Curve&#39;s point style.
void showTemporaryMessage(const QString &message)
Show temporary message in status bar. After a short interval the message will disappear.
Definition: StatusBar.cpp:153
void updateCurveStyles(const CurveStyles &modelCurveStyles)
Update curve styles after settings changed.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void unsetColorFilterSettings()
Apply no color filter.
Dialog for setting the advanced parameters in a newly imported Document.
QStringList selectedPointIdentifiers(const QList< QGraphicsItem *> &items) const
Return list of selected point identifiers.
Wizard for setting up the checklist guide.
bool transformIsDefined() const
Transform is defined when at least three axis points have been digitized.
Dialog for editing main window settings, which are entirely independent of all documents.
void handleMouseMove(CmdMediator *cmdMediator, QPointF pos)
See DigitizeStateAbstractBase::handleMouseMove.
MainWindowModel modelMainWindow() const
Get method for main window model.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
MainTitleBarFormat mainTitleBarFormat() const
Get method for MainWindow titlebar filename format.
QLocale locale() const
Get method for locale.
Model for DlgSettingsAxesChecker and CmdSettingsAxesChecker.
Command stack that shadows the CmdMediator command stack at startup when reading commands from an err...
unsigned int coordSystemCount() const
Number of CoordSystem.
Definition: Document.cpp:305
void updateSettingsExportFormat(const DocumentModelExportFormat &modelExport)
Update with new export properties.
Dialog for editing coordinates settings.
Load QImage from url. This is trivial for a file, but requires an asynchronous download step for http...
virtual bool eventFilter(QObject *, QEvent *)
Catch secret keypresses.
void startLoadImage(const QUrl &url)
Start the asynchronous loading of an image from the specified url.
void load(CmdMediator &cmdMediator)
Load settings from Document.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded...
void saveXml(QXmlStreamWriter &writer) const
Serialize to xml.
Dialog for editing curve properties settings.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void setZoomControl(ZoomControl zoomControl)
Set method for zoom control.
QString fileExtensionTsv() const
File extension for tsv export files.
QStringList curveNames(CoordSystemIndex coordSystemIndex) const
Curve names to be placed into Document.
void setMainTitleBarFormat(MainTitleBarFormat mainTitleBarFormat)
Set method for MainWindow titlebar filename format.
void handleMouseRelease(CmdMediator *cmdMediator, QPointF pos)
See DigitizeStateAbstractBase::handleMouseRelease.
void captureGraphicsItems(QGraphicsScene &scene)
Take a snapshot of the graphics items.
Definition: Ghosts.cpp:26
Command queue stack.
Definition: CmdMediator.h:23
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void setZoomFactorInitial(ZoomFactorInitial zoomFactorInitial)
Set method for initial zoom factor.
void update(bool fileIsLoaded, const CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow)
Update transform by iterating through the axis points.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
bool dragDropExport() const
Get method for drag and drop export.
void signalZoom(int)
Send zoom selection, picked from menu or keystroke, to StatusBar.
Model for DlgSettingsSegments and CmdSettingsSegments.
void destroyGhosts(QGraphicsScene &scene)
Destory ghosts. Called at end of algorithm.
Definition: Ghosts.cpp:119
QImage imageForCurveState() const
Image for the Curve state, even if the current state is different.
void cmdFileImport(const QString &fileName)
Import file. This is called from a file script command.
Definition: MainWindow.cpp:305
void setCurvesGraphs(const CurvesGraphs &curvesGraphs)
Let CmdAbstract classes overwrite CurvesGraphs.
Definition: Document.cpp:930
void updateAxesChecker(CmdMediator &cmdMediator, const Transformation &transformation)
Apply the new DocumentModelAxesChecker.
void resizeEvent(QResizeEvent *event)
Intercept resize event so graphics scene can be appropriately resized when in Fill mode...
void updateSettingsCoords(const DocumentModelCoords &modelCoords)
Update with new coordinate properties.
void loadCommands(MainWindow &mainWindow, Document &document, QXmlStreamReader &reader)
Load commands from serialized xml.
DocumentModelExportFormat modelExport() const
Get method for DocumentModelExportFormat.
Definition: Document.cpp:714
void update(const CmdMediator &cmdMediator, bool documentIsExported)
Update using current CmdMediator/Document state.
void saveXml(QXmlStreamWriter &writer) const
Save document to xml.
Definition: Document.cpp:882
File that manages a command stack for regression testing of file import/open/export/close.
Definition: FileCmdScript.h:20
QString fileExtensionCsv() const
File extension for csv export files.
void setSmallDialogs(bool smallDialogs)
Set method for small dialogs flag.
void handleMousePress(CmdMediator *cmdMediator, QPointF pos)
See DigitizeStateAbstractBase::handleMousePress.
Add point and line handling to generic QGraphicsScene.
Definition: GraphicsScene.h:33
CurveStyles modelCurveStyles() const
Get method for CurveStyles.
Definition: Document.cpp:700
bool isModified() const
Dirty flag.
Definition: CmdMediator.cpp:82
QString selectedGraphCurve() const
Curve name that is currently selected in m_cmbCurve.
Command for moving all selected Points by a specified translation.
Definition: CmdCopy.h:18
Window that displays curve fitting as applied to the currently selected curve.
Definition: FittingWindow.h:34
bool browserIsEmpty() const
When browser is empty, it is pointless to show it.
Model for DlgSettingsGridRemoval and CmdSettingsGridRemoval. The settings are unstable until the user...
QString filterTsv() const
QFileDialog filter for TSV files.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void fileExport(const QString &filename) const
Export to the specified file. This is called when the Transformation has not been defined...
void updateSettingsSegments(const DocumentModelSegments &modelSegments)
Update with new segments properties.
Command for changing the currently selected CoordSystem.
void showCurves(bool show, bool showAll=false, const QString &curveName="")
Show or hide all Curves (if showAll is true) or just the selected Curve (if showAll is false);...
Dialog for editing axes checker settings.
void setPdfResolution(int resolution)
Set method for resolution of imported PDF files, in dots per inch.
Dialog to be displayed whenever some operation or processing cannot be performed since the axis point...
void updateGraphicsLinesToMatchGraphicsPoints()
Update the graphics lines so they follow the graphics points, after a drag, addition, removal, and such.
QString templateHtml(CoordSystemIndex coordSystemIndex) const
Template html comprising the checklist for display.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:693
void populateCurvesGraphs(CoordSystemIndex coordSystemIndex, CurvesGraphs &curvesGraphs)
Create entries in CurvesGraphs for each curve name that user provided.
void setImportCropping(ImportCropping importCropping)
Set method for import cropping.
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: Document.cpp:347
void setTemplateHtml(const QString &html, const QStringList &curveNames)
Populate the browser with template html.
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: CmdMediator.cpp:62
virtual void clear()
Clear stale information.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
About Engauge dialog. This provides a hidden shortcut for triggering ENGAUGE_ASSERT.
Definition: DlgAbout.h:15
DocumentModelAxesChecker modelAxesChecker() const
Get method for DocumentModelAxesChecker.
Definition: Document.cpp:679
virtual void clear()
Clear stale information.
virtual void showEvent(QShowEvent *)
Processing performed after gui becomes available.
PdfReturn load(const QString &fileName, QImage &image, int resolution, ImportCropping importCropping, bool isErrorReportRegressionTest) const
Try to load the specified file. Success is indicated in the function return value.
Definition: Pdf.cpp:25
void requestImmediateStateTransition(CmdMediator *cmdMediator, DigitizeState digitizeState)
Perform immediate state transition. Called from outside state machine.
virtual void doCopy()
Copy the current selection to the clipboard.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.