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