Engauge Digitizer  2
 All Classes Files Functions Variables Enumerations Enumerator Friends Pages
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."));
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 1: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  m_modelMainWindow.setSmallDialogs (settings.value (SETTINGS_SMALL_DIALOGS,
2492  QVariant (DEFAULT_SMALL_DIALOGS)).toBool ());
2493 
2495  updateSmallDialogs();
2496 
2497  settings.endGroup();
2498 }
2499 
2500 void MainWindow::settingsWrite ()
2501 {
2502  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
2503 
2504  settings.beginGroup (SETTINGS_GROUP_ENVIRONMENT);
2505  settings.setValue (SETTINGS_CURRENT_DIRECTORY, QDir::currentPath ());
2506  settings.endGroup ();
2507 
2508  settings.beginGroup (SETTINGS_GROUP_MAIN_WINDOW);
2509  settings.setValue (SETTINGS_SIZE, size ());
2510  settings.setValue (SETTINGS_POS, pos ());
2511 #ifndef OSX_RELEASE
2512  settings.setValue (SETTINGS_HELP_SIZE, m_helpWindow->size());
2513  settings.setValue (SETTINGS_HELP_POS, m_helpWindow->pos ());
2514 #endif
2515  if (m_dockChecklistGuide->isFloating()) {
2516 
2517  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, Qt::NoDockWidgetArea);
2518  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY, m_dockChecklistGuide->saveGeometry ());
2519 
2520  } else {
2521 
2522  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, dockWidgetArea (m_dockChecklistGuide));
2523 
2524  }
2525  if (m_dockGeometryWindow->isFloating()) {
2526 
2527  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, Qt::NoDockWidgetArea);
2528  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY, m_dockGeometryWindow->saveGeometry ());
2529 
2530  } else {
2531 
2532  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, dockWidgetArea (m_dockGeometryWindow));
2533 
2534  }
2535  settings.setValue (SETTINGS_BACKGROUND_IMAGE, m_cmbBackground->currentData().toInt());
2536  settings.setValue (SETTINGS_CHECKLIST_GUIDE_WIZARD, m_actionHelpChecklistGuideWizard->isChecked ());
2537  settings.setValue (SETTINGS_HIGHLIGHT_OPACITY, m_modelMainWindow.highlightOpacity());
2538  settings.setValue (SETTINGS_IMPORT_CROPPING, m_modelMainWindow.importCropping());
2539  settings.setValue (SETTINGS_IMPORT_PDF_RESOLUTION, m_modelMainWindow.pdfResolution ());
2540  settings.setValue (SETTINGS_LOCALE_LANGUAGE, m_modelMainWindow.locale().language());
2541  settings.setValue (SETTINGS_LOCALE_COUNTRY, m_modelMainWindow.locale().country());
2542  settings.setValue (SETTINGS_MAIN_TITLE_BAR_FORMAT, m_modelMainWindow.mainTitleBarFormat());
2543  settings.setValue (SETTINGS_MAXIMUM_GRID_LINES, m_modelMainWindow.maximumGridLines());
2544  settings.setValue (SETTINGS_SMALL_DIALOGS, m_modelMainWindow.smallDialogs());
2545  settings.setValue (SETTINGS_VIEW_BACKGROUND_TOOLBAR, m_actionViewBackground->isChecked());
2546  settings.setValue (SETTINGS_VIEW_DIGITIZE_TOOLBAR, m_actionViewDigitize->isChecked ());
2547  settings.setValue (SETTINGS_VIEW_STATUS_BAR, m_statusBar->statusBarMode ());
2548  settings.setValue (SETTINGS_VIEW_SETTINGS_VIEWS_TOOLBAR, m_actionViewSettingsViews->isChecked ());
2549  settings.setValue (SETTINGS_VIEW_COORD_SYSTEM_TOOLBAR, m_actionViewCoordSystem->isChecked ());
2550  settings.setValue (SETTINGS_VIEW_TOOL_TIPS, m_actionViewToolTips->isChecked ());
2551  settings.setValue (SETTINGS_ZOOM_CONTROL, m_modelMainWindow.zoomControl());
2552  settings.setValue (SETTINGS_ZOOM_FACTOR, currentZoomFactor ());
2553  settings.setValue (SETTINGS_ZOOM_FACTOR_INITIAL, m_modelMainWindow.zoomFactorInitial());
2554  settings.endGroup ();
2555 }
2556 
2557 bool MainWindow::setupAfterLoadNewDocument (const QString &fileName,
2558  const QString &temporaryMessage ,
2559  ImportType importType)
2560 {
2561  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setupAfterLoadNewDocument"
2562  << " file=" << fileName.toLatin1().data()
2563  << " message=" << temporaryMessage.toLatin1().data()
2564  << " importType=" << importType;
2565 
2566  // The steps in this method should theoretically be a superset of the steps in setupAfterLoadNewDocument. Therefore, any
2567  // changes to this method should be considered for application to the other method also
2568 
2569  const QString EMPTY_CURVE_NAME_TO_SKIP_BACKGROUND_PROCESSING; // For bootstrapping the preview
2570 
2571  // At this point the code assumes CmdMediator for the NEW Document is already stored in m_cmdMediator
2572 
2573  m_digitizeStateContext->resetOnLoad (m_cmdMediator); // Before setPixmap
2574  m_backgroundStateContext->setCurveSelected (m_transformation,
2575  m_cmdMediator->document().modelGridRemoval(),
2576  m_cmdMediator->document().modelColorFilter(),
2577  EMPTY_CURVE_NAME_TO_SKIP_BACKGROUND_PROCESSING); // Before setPixmap
2578  setPixmap (m_cmdMediator->document().curvesGraphsNames().first(),
2579  m_cmdMediator->pixmap ()); // Set background immediately so it is visible as a preview when any dialogs are displayed
2580 
2581  // Image is visible now so the user can refer to it when we ask for the number of coordinate systems. Note that the Document
2582  // may already have multiple CoordSystem if user loaded a file that had multiple CoordSystem entries
2583  if (importType == IMPORT_TYPE_ADVANCED) {
2584 
2585  applyZoomFactorAfterLoad(); // Apply the currently selected zoom factor
2586 
2587  DlgImportAdvanced dlgImportAdvanced (*this);
2588  dlgImportAdvanced.exec();
2589 
2590  if (dlgImportAdvanced.result() == QDialog::Rejected) {
2591  return false;
2592  }
2593 
2594  int numberCoordSystem = dlgImportAdvanced.numberCoordSystem();
2595  m_cmdMediator->document().addCoordSystems (numberCoordSystem - 1);
2596  m_cmdMediator->setDocumentAxesPointsRequired (dlgImportAdvanced.documentAxesPointsRequired());
2597  }
2598 
2599  m_transformation.resetOnLoad();
2600  m_transformationStateContext->resetOnLoad();
2601  m_scene->resetOnLoad();
2602 
2603  connect (m_actionEditUndo, SIGNAL (triggered ()), m_cmdMediator, SLOT (undo ()));
2604  connect (m_actionEditUndo, SIGNAL (triggered ()), m_cmdStackShadow, SLOT (slotUndo ()));
2605  connect (m_actionEditRedo, SIGNAL (triggered ()), m_cmdMediator, SLOT (redo ())); // No effect until CmdMediator::undo and CmdStackShadow::slotUndo get called
2606  connect (m_actionEditRedo, SIGNAL (triggered ()), m_cmdStackShadow, SLOT (slotRedo ())); // No effect after CmdMediator::undo and CmdStackShadow::slotUndo get called
2607  connect (m_cmdMediator, SIGNAL (canRedoChanged(bool)), this, SLOT (slotCanRedoChanged (bool)));
2608  connect (m_cmdMediator, SIGNAL (canUndoChanged(bool)), this, SLOT (slotCanUndoChanged (bool)));
2609  connect (m_cmdMediator, SIGNAL (redoTextChanged (const QString &)), this, SLOT (slotRedoTextChanged (const QString &)));
2610  connect (m_cmdMediator, SIGNAL (undoTextChanged (const QString &)), this, SLOT (slotUndoTextChanged (const QString &)));
2611  loadCurveListFromCmdMediator ();
2612  loadCoordSystemListFromCmdMediator ();
2614 
2615  m_isDocumentExported = false;
2616 
2617  // Background must be set (by setPixmap) before slotViewZoomFill which relies on the background. At this point
2618  // the transformation is undefined (unless the code is changed) so grid removal will not work
2619  // but updateTransformationAndItsDependencies will call this again to fix that issue. Note that the selected
2620  // curve name was set (by setCurveSelected) earlier before the call to setPixmap
2621  m_backgroundStateContext->setCurveSelected (m_transformation,
2622  m_cmdMediator->document().modelGridRemoval(),
2623  m_cmdMediator->document().modelColorFilter(),
2624  m_cmbCurve->currentText ());
2625  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) m_cmbBackground->currentIndex ());
2626 
2627  applyZoomFactorAfterLoad(); // Zoom factor must be reapplied after background image is set, to have any effect
2628 
2629  setCurrentFile(fileName);
2630  m_statusBar->showTemporaryMessage (temporaryMessage);
2631  m_statusBar->wakeUp ();
2632 
2633  saveStartingDocumentSnapshot();
2634 
2635  updateAfterCommand(); // Replace stale points by points in new Document
2636 
2637  return true;
2638 }
2639 
2640 bool MainWindow::setupAfterLoadReplacingImage (const QString &fileName,
2641  const QString &temporaryMessage ,
2642  ImportType importType)
2643 {
2644  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setupAfterLoadReplacingImage"
2645  << " file=" << fileName.toLatin1().data()
2646  << " message=" << temporaryMessage.toLatin1().data()
2647  << " importType=" << importType;
2648 
2649  // The steps in this method should theoretically be just a subset of the steps in setupAfterLoadNewDocument
2650 
2651  // After this point there should be no commands in CmdMediator, since we effectively have a new document
2652  m_cmdMediator->clear();
2653 
2654  setPixmap (m_cmdMediator->document().curvesGraphsNames().first(),
2655  m_cmdMediator->pixmap ()); // Set background immediately so it is visible as a preview when any dialogs are displayed
2656 
2657  m_isDocumentExported = false;
2658 
2659  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) m_cmbBackground->currentIndex ());
2660 
2661  applyZoomFactorAfterLoad(); // Zoom factor must be reapplied after background image is set, to have any effect
2662 
2663  setCurrentFile(fileName);
2664  m_statusBar->showTemporaryMessage (temporaryMessage);
2665  m_statusBar->wakeUp ();
2666 
2667  saveStartingDocumentSnapshot();
2668 
2669  updateAfterCommand(); // Replace stale points by points in new Document
2670 
2671  return true;
2672 }
2673 
2674 void MainWindow::showEvent (QShowEvent *event)
2675 {
2676  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::showEvent"
2677  << " files=" << m_loadStartupFiles.join (",").toLatin1().data();
2678 
2679  QMainWindow::showEvent (event);
2680 
2681  if (m_loadStartupFiles.count() > 0) {
2682 
2683  m_timerLoadStartupFiles = new QTimer;
2684  m_timerLoadStartupFiles->setSingleShot (true);
2685  connect (m_timerLoadStartupFiles, SIGNAL (timeout ()), this, SLOT (slotLoadStartupFiles ()));
2686  m_timerLoadStartupFiles->start (0); // Zero delay still waits until execution finishes and gui is available
2687 
2688  }
2689 }
2690 
2691 void MainWindow::showTemporaryMessage (const QString &temporaryMessage)
2692 {
2693  m_statusBar->showTemporaryMessage (temporaryMessage);
2694 }
2695 
2696 void MainWindow::slotBtnPrintAll ()
2697 {
2698  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnPrintAll";
2699 
2700  ghostsCreate ();
2701 
2702  QPrinter printer (QPrinter::HighResolution);
2703  QPrintDialog dlg (&printer, this);
2704  if (dlg.exec() == QDialog::Accepted) {
2705  QPainter painter (&printer);
2706  m_view->render (&painter);
2707  painter.end();
2708  }
2709 
2710  ghostsDestroy ();
2711 }
2712 
2713 void MainWindow::slotBtnShowAllPressed ()
2714 {
2715  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnShowAllPressed";
2716 
2717  // Start of press-release sequence
2718  ghostsCreate ();
2719 }
2720 
2721 void MainWindow::slotBtnShowAllReleased ()
2722 {
2723  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnShowAllReleased";
2724 
2725  // End of press-release sequence
2726  ghostsDestroy ();
2727 }
2728 
2729 void MainWindow::slotCanRedoChanged (bool canRedo)
2730 {
2731  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotCanRedoChanged";
2732 
2733  m_actionEditRedo->setEnabled (canRedo || m_cmdStackShadow->canRedo());
2734 }
2735 
2736 void MainWindow::slotCanUndoChanged (bool canUndo)
2737 {
2738  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotCanUndoChanged";
2739 
2740  m_actionEditUndo->setEnabled (canUndo);
2741 }
2742 
2743 void MainWindow::slotChecklistClosed()
2744 {
2745  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotChecklistClosed";
2746 
2747  m_actionViewChecklistGuide->setChecked (false);
2748 }
2749 
2750 void MainWindow::slotCleanChanged(bool clean)
2751 {
2752  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCleanChanged";
2753 
2754  setWindowModified (!clean);
2755 }
2756 
2757 void MainWindow::slotCmbBackground(int currentIndex)
2758 {
2759  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbBackground";
2760 
2761  switch (currentIndex) {
2762  case BACKGROUND_IMAGE_NONE:
2763  if (!m_actionViewBackgroundNone->isChecked()) {
2764  m_actionViewBackgroundNone->toggle();
2765  }
2766  break;
2767 
2768  case BACKGROUND_IMAGE_ORIGINAL:
2769  if (!m_actionViewBackgroundOriginal->isChecked ()) {
2770  m_actionViewBackgroundOriginal->toggle();
2771  }
2772  break;
2773 
2774  case BACKGROUND_IMAGE_FILTERED:
2775  if (!m_actionViewBackgroundFiltered->isChecked ()) {
2776  m_actionViewBackgroundFiltered->toggle();
2777  }
2778  break;
2779  }
2780 
2781  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) currentIndex);
2782 }
2783 
2784 void MainWindow::slotCmbCoordSystem(int index)
2785 {
2786  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbCoordSystem";
2787 
2788  CmdSelectCoordSystem *cmd = new CmdSelectCoordSystem (*this,
2789  m_cmdMediator->document(),
2790  index);
2791 
2792  m_cmdMediator->push (cmd);
2793 }
2794 
2795 void MainWindow::slotCmbCurve(int /* index */)
2796 {
2797  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbCurve";
2798 
2799  m_backgroundStateContext->setCurveSelected (m_transformation,
2800  m_cmdMediator->document().modelGridRemoval(),
2801  m_cmdMediator->document().modelColorFilter(),
2802  m_cmbCurve->currentText ());
2803  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
2804  m_cmdMediator->setSelectedCurveName (m_cmbCurve->currentText ()); // Save for next time current coordinate system returns
2805 
2806  updateViewedCurves();
2808  updateGeometryWindow();
2809 }
2810 
2811 void MainWindow::slotContextMenuEventAxis (QString pointIdentifier)
2812 {
2813  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventAxis point=" << pointIdentifier.toLatin1 ().data ();
2814 
2815  m_digitizeStateContext->handleContextMenuEventAxis (m_cmdMediator,
2816  pointIdentifier);
2817 }
2818 
2819 void MainWindow::slotContextMenuEventGraph (QStringList pointIdentifiers)
2820 {
2821  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventGraph point=" << pointIdentifiers.join(",").toLatin1 ().data ();
2822 
2823  m_digitizeStateContext->handleContextMenuEventGraph (m_cmdMediator,
2824  pointIdentifiers);
2825 }
2826 
2827 void MainWindow::slotDigitizeAxis ()
2828 {
2829  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeAxis";
2830 
2831  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2832  DIGITIZE_STATE_AXIS);
2833  m_cmbCurve->setEnabled (false); // Graph curve is irrelevant in this mode
2834  m_viewPointStyle->setEnabled (true); // Point style is important in this mode
2835  m_viewSegmentFilter->setEnabled (true); // Filtering is important in this mode
2836 }
2837 
2838 void MainWindow::slotDigitizeColorPicker ()
2839 {
2840  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeColorPicker";
2841 
2842  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2843  DIGITIZE_STATE_COLOR_PICKER);
2844  m_cmbCurve->setEnabled (true);
2845  m_viewPointStyle->setEnabled (true);
2846  m_viewSegmentFilter->setEnabled (true);
2847 }
2848 
2849 void MainWindow::slotDigitizeCurve ()
2850 {
2851  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeCurve";
2852 
2853  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2854  DIGITIZE_STATE_CURVE);
2855  m_cmbCurve->setEnabled (true);
2856  m_viewPointStyle->setEnabled (true);
2857  m_viewSegmentFilter->setEnabled (true);
2858 }
2859 
2860 void MainWindow::slotDigitizePointMatch ()
2861 {
2862  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizePointMatch";
2863 
2864  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2865  DIGITIZE_STATE_POINT_MATCH);
2866  m_cmbCurve->setEnabled (true);
2867  m_viewPointStyle->setEnabled (true);
2868  m_viewSegmentFilter->setEnabled (true);
2869 }
2870 
2871 void MainWindow::slotDigitizeSegment ()
2872 {
2873  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeSegment";
2874 
2875  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2876  DIGITIZE_STATE_SEGMENT);
2877  m_cmbCurve->setEnabled (true);
2878  m_viewPointStyle->setEnabled (true);
2879  m_viewSegmentFilter->setEnabled (true);
2880 }
2881 
2882 void MainWindow::slotDigitizeSelect ()
2883 {
2884  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeSelect";
2885 
2886  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2887  DIGITIZE_STATE_SELECT);
2888  m_cmbCurve->setEnabled (false);
2889  m_viewPointStyle->setEnabled (false);
2890  m_viewSegmentFilter->setEnabled (false);
2891 }
2892 
2893 void MainWindow::slotEditCopy ()
2894 {
2895  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCopy";
2896 
2897  GraphicsItemsExtractor graphicsItemsExtractor;
2898  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
2899  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
2900 
2901  CmdCopy *cmd = new CmdCopy (*this,
2902  m_cmdMediator->document(),
2903  pointIdentifiers);
2904  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
2905  cmd);
2906 }
2907 
2908 void MainWindow::slotEditCut ()
2909 {
2910  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCut";
2911 
2912  GraphicsItemsExtractor graphicsItemsExtractor;
2913  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
2914  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
2915 
2916  CmdCut *cmd = new CmdCut (*this,
2917  m_cmdMediator->document(),
2918  pointIdentifiers);
2919  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
2920  cmd);
2921 }
2922 
2923 void MainWindow::slotEditDelete ()
2924 {
2925  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditDelete";
2926 
2927  GraphicsItemsExtractor graphicsItemsExtractor;
2928  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
2929  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
2930 
2931  CmdDelete *cmd = new CmdDelete (*this,
2932  m_cmdMediator->document(),
2933  pointIdentifiers);
2934  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
2935  cmd);
2936 }
2937 
2938 void MainWindow::slotEditMenu ()
2939 {
2940  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditMenu";
2941 
2942  m_actionEditPasteAsNew->setEnabled (!QApplication::clipboard()->image().isNull());
2943  m_actionEditPasteAsNewAdvanced->setEnabled (!QApplication::clipboard()->image().isNull());
2944 }
2945 
2946 void MainWindow::slotEditPaste ()
2947 {
2948  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPaste";
2949 }
2950 
2951 void MainWindow::slotEditPasteAsNew ()
2952 {
2953  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPasteAsNew";
2954 
2955  filePaste (IMPORT_TYPE_SIMPLE);
2956 }
2957 
2958 void MainWindow::slotEditPasteAsNewAdvanced ()
2959 {
2960  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPasteAsNewAdvanced";
2961 
2962  filePaste (IMPORT_TYPE_ADVANCED);
2963 }
2964 
2965 void MainWindow::slotFileClose()
2966 {
2967  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileClose";
2968 
2969  if (maybeSave ()) {
2970 
2971  // Transition from defined to undefined. This must be after the clearing of the screen
2972  // since the axes checker screen item (and maybe others) must still exist
2973  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
2974  *m_cmdMediator,
2975  m_transformation,
2976  selectedGraphCurve());
2977 
2978  // Transition to empty state so an inadvertent mouse press does not trigger, for example,
2979  // the creation of an axis point on a non-existent GraphicsScene (=crash)
2980  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2981  DIGITIZE_STATE_EMPTY);
2982 
2983  // Remove screen objects
2984  m_scene->resetOnLoad ();
2985 
2986  // Remove background
2987  m_backgroundStateContext->close ();
2988 
2989  // Remove scroll bars if they exist
2990  m_scene->setSceneRect (QRectF (0, 0, 1, 1));
2991 
2992  // Remove stale data from geometry window
2993  m_dockGeometryWindow->clear ();
2994 
2995  // Deallocate Document
2996  delete m_cmdMediator;
2997 
2998  // Remove file information
2999  m_cmdMediator = 0;
3000  m_currentFile = "";
3001  m_engaugeFile = "";
3002  setWindowTitle (engaugeWindowTitle ());
3003 
3004  m_gridLines.clear();
3005  updateControls();
3006  }
3007 }
3008 
3009 void MainWindow::slotFileExport ()
3010 {
3011  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileExport";
3012 
3013  if (m_transformation.transformIsDefined()) {
3014 
3015  ExportToFile exportStrategy;
3016  QString filter = QString ("%1;;%2;;All files (*.*)")
3017  .arg (exportStrategy.filterCsv ())
3018  .arg (exportStrategy.filterTsv ());
3019 
3020  // OSX sandbox requires, for the default, a non-empty filename
3021  QString defaultFileName = QString ("%1/%2.%3")
3022  .arg (QDir::currentPath ())
3023  .arg (m_currentFile)
3024  .arg (exportStrategy.fileExtensionCsv ());
3025  QFileDialog dlg;
3026  QString filterCsv = exportStrategy.filterCsv ();
3027  QString fileName = dlg.getSaveFileName (this,
3028  tr("Export"),
3029  defaultFileName,
3030  filter,
3031  &filterCsv);
3032  if (!fileName.isEmpty ()) {
3033 
3034  fileExport(fileName,
3035  exportStrategy);
3036  }
3037  } else {
3038  DlgRequiresTransform dlg ("Export");
3039  dlg.exec ();
3040  }
3041 }
3042 
3043 void MainWindow::slotFileImport ()
3044 {
3045  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImport";
3046 
3047  fileImportWithPrompts (IMPORT_TYPE_SIMPLE);
3048 }
3049 
3050 void MainWindow::slotFileImportAdvanced ()
3051 {
3052  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportAdvanced";
3053 
3054  fileImportWithPrompts (IMPORT_TYPE_ADVANCED);
3055 }
3056 
3057 void MainWindow::slotFileImportDraggedImage(QImage image)
3058 {
3059  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportDraggedImage";
3060 
3061  // No need to check return value from loadImage since there are no prompts that give the user a chance to cancel
3062  loadImage ("",
3063  image,
3064  IMPORT_TYPE_SIMPLE);
3065 }
3066 
3067 void MainWindow::slotFileImportDraggedImageUrl(QUrl url)
3068 {
3069  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportDraggedImageUrl url=" << url.toString ().toLatin1 ().data ();
3070 
3071  m_loadImageFromUrl->startLoadImage (url);
3072 }
3073 
3074 void MainWindow::slotFileImportImage(QString fileName, QImage image)
3075 {
3076  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportImage fileName=" << fileName.toLatin1 ().data ();
3077 
3078  // No need to check return value from loadImage since there are no prompts that give the user a chance to cancel
3079  loadImage (fileName,
3080  image,
3081  IMPORT_TYPE_SIMPLE);
3082 }
3083 
3084 void MainWindow::slotFileImportImageReplace ()
3085 {
3086  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportImageReplace";
3087 
3088  fileImportWithPrompts (IMPORT_TYPE_IMAGE_REPLACE);
3089 }
3090 
3091 void MainWindow::slotFileOpen()
3092 {
3093  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileOpen";
3094 
3095  if (maybeSave ()) {
3096 
3097  // Allow selection of files with strange suffixes in case the file extension was changed. Since
3098  // the default is the first filter, the wildcard filter is added afterwards (it is the off-nominal case)
3099  QString filter = QString ("%1 (*.%2);; All Files (*.*)")
3100  .arg (ENGAUGE_FILENAME_DESCRIPTION)
3101  .arg (ENGAUGE_FILENAME_EXTENSION);
3102 
3103  QString fileName = QFileDialog::getOpenFileName (this,
3104  tr("Open Document"),
3105  QDir::currentPath (),
3106  filter);
3107  if (!fileName.isEmpty ()) {
3108 
3109  loadDocumentFile (fileName);
3110 
3111  }
3112  }
3113 }
3114 
3115 void MainWindow::slotFileOpenDraggedDigFile (QString fileName)
3116 {
3117  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileOpenDraggedDigFile";
3118 
3119  loadDocumentFile (fileName);
3120 }
3121 
3122 void MainWindow::slotFilePrint()
3123 {
3124  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFilePrint";
3125 
3126  QPrinter printer (QPrinter::HighResolution);
3127  QPrintDialog dlg (&printer, this);
3128  if (dlg.exec() == QDialog::Accepted) {
3129  QPainter painter (&printer);
3130  m_view->render (&painter);
3131  painter.end();
3132  }
3133 }
3134 
3135 bool MainWindow::slotFileSave()
3136 {
3137  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileSave";
3138 
3139  if (m_engaugeFile.isEmpty()) {
3140  return slotFileSaveAs();
3141  } else {
3142  return saveDocumentFile (m_engaugeFile);
3143  }
3144 }
3145 
3146 bool MainWindow::slotFileSaveAs()
3147 {
3148  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileSaveAs";
3149 
3150  // Append engauge file extension if it is not already there
3151  QString filenameDefault = m_currentFile;
3152  if (!m_currentFile.endsWith (ENGAUGE_FILENAME_EXTENSION)) {
3153  filenameDefault = QString ("%1.%2")
3154  .arg (m_currentFile)
3155  .arg (ENGAUGE_FILENAME_EXTENSION);
3156  }
3157 
3158  if (!m_engaugeFile.isEmpty()) {
3159  filenameDefault = m_engaugeFile;
3160  }
3161 
3162  QString filterDigitizer = QString ("%1 (*.%2)")
3163  .arg (ENGAUGE_FILENAME_DESCRIPTION)
3164  .arg (ENGAUGE_FILENAME_EXTENSION);
3165  QString filterAll ("All files (*. *)");
3166 
3167  QStringList filters;
3168  filters << filterDigitizer;
3169  filters << filterAll;
3170 
3171  QFileDialog dlg(this);
3172  dlg.setFileMode (QFileDialog::AnyFile);
3173  dlg.selectNameFilter (filterDigitizer);
3174  dlg.setNameFilters (filters);
3175 #if defined(OSX_DEBUG) || defined(OSX_RELEASE)
3176 #else
3177  // Prevent hang in OSX
3178  dlg.setWindowModality(Qt::WindowModal);
3179 #endif
3180  dlg.setAcceptMode(QFileDialog::AcceptSave);
3181  dlg.selectFile(filenameDefault);
3182  if (dlg.exec()) {
3183 
3184  QStringList files = dlg.selectedFiles();
3185  return saveDocumentFile(files.at(0));
3186  }
3187 
3188  return false;
3189 }
3190 
3191 void MainWindow::slotGeometryWindowClosed()
3192 {
3193  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotGeometryWindowClosed";
3194 
3195  m_actionViewGeometryWindow->setChecked (false);
3196 }
3197 
3198 void MainWindow::slotHelpAbout()
3199 {
3200  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpAbout";
3201 
3202  DlgAbout dlg (*this);
3203  dlg.exec ();
3204 }
3205 
3206 void MainWindow::slotHelpTutorial()
3207 {
3208  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpTutorial";
3209 
3210  m_tutorialDlg->show ();
3211  m_tutorialDlg->exec ();
3212 }
3213 
3214 void MainWindow::slotKeyPress (Qt::Key key,
3215  bool atLeastOneSelectedItem)
3216 {
3217  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotKeyPress"
3218  << " key=" << QKeySequence (key).toString().toLatin1 ().data ()
3219  << " atLeastOneSelectedItem=" << (atLeastOneSelectedItem ? "true" : "false");
3220 
3221  m_digitizeStateContext->handleKeyPress (m_cmdMediator,
3222  key,
3223  atLeastOneSelectedItem);
3224 }
3225 
3226 void MainWindow::slotLoadStartupFiles ()
3227 {
3228  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotLoadStartupFiles";
3229 
3230  ENGAUGE_ASSERT (m_loadStartupFiles.count() > 0);
3231 
3232  QString fileName = m_loadStartupFiles.front(); // Get next file name
3233  m_loadStartupFiles.pop_front(); // Remove next file name
3234 
3235  // Load next file into this instance of Engauge
3236  LoadFileInfo loadFileInfo;
3237  if (loadFileInfo.loadsAsDigFile(fileName)) {
3238 
3239  loadDocumentFile (fileName);
3240 
3241  } else {
3242 
3243  fileImport (fileName,
3244  IMPORT_TYPE_SIMPLE);
3245 
3246  }
3247 
3248  if (m_loadStartupFiles.count() > 0) {
3249 
3250  // Fork off another instance of this application to handle the remaining files recursively. New process
3251  // is detached so killing/terminating this process does not automatically kill the child process(es) also
3252  QProcess::startDetached (QCoreApplication::applicationFilePath(),
3253  m_loadStartupFiles);
3254  }
3255 }
3256 
3257 void MainWindow::slotMouseMove (QPointF pos)
3258 {
3259 // LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotMouseMove pos=" << QPointFToString (pos).toLatin1 ().data ();
3260 
3261  // Ignore mouse moves before Document is loaded
3262  if (m_cmdMediator != 0) {
3263 
3264  // Get status bar coordinates
3265  QString coordsScreen, coordsGraph, resolutionGraph;
3266  m_transformation.coordTextForStatusBar (pos,
3267  coordsScreen,
3268  coordsGraph,
3269  resolutionGraph);
3270 
3271  // Update status bar coordinates
3272  m_statusBar->setCoordinates (coordsScreen,
3273  coordsGraph,
3274  resolutionGraph);
3275 
3276  // There used to be a call to updateGraphicsLinesToMatchGraphicsPoints here, but that resulted
3277  // in hundreds of gratuitous log messages as the cursor was moved around, and nothing important happened
3278 
3279  m_digitizeStateContext->handleMouseMove (m_cmdMediator,
3280  pos);
3281  }
3282 }
3283 
3284 void MainWindow::slotMousePress (QPointF pos)
3285 {
3286  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMousePress";
3287 
3288  m_scene->resetPositionHasChangedFlags();
3289 
3290  m_digitizeStateContext->handleMousePress (m_cmdMediator,
3291  pos);
3292 }
3293 
3294 void MainWindow::slotMouseRelease (QPointF pos)
3295 {
3296  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMouseRelease";
3297 
3298  if (pos.x() < 0 || pos.y() < 0) {
3299 
3300  // Cursor is outside the image so drop this event. However, call updateControls since this may be
3301  // a click-and-drag to select in which case the controls (especially Copy and Cut) reflect the new selection
3302  updateControls ();
3303 
3304  } else {
3305 
3306  // Cursor is within the image so process this as a normal mouse release
3307  m_digitizeStateContext->handleMouseRelease (m_cmdMediator,
3308  pos);
3309  }
3310 }
3311 
3312 void MainWindow::slotRecentFileAction ()
3313 {
3314  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileAction";
3315 
3316  QAction *action = qobject_cast<QAction*>(sender ());
3317 
3318  if (action) {
3319  QString fileName = action->data().toString();
3320  loadDocumentFile (fileName);
3321  }
3322 }
3323 
3324 void MainWindow::slotRecentFileClear ()
3325 {
3326  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileClear";
3327 
3328  QStringList emptyList;
3329 
3330  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
3331  settings.setValue (SETTINGS_RECENT_FILE_LIST,
3332  emptyList);
3333 
3334  updateRecentFileList();
3335 }
3336 
3337 void MainWindow::slotRedoTextChanged (const QString &text)
3338 {
3339  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotRedoTextChanged";
3340 
3341  QString completeText ("Redo");
3342  if (!text.isEmpty ()) {
3343  completeText += QString (" \"%1\"").arg (text);
3344  }
3345  m_actionEditRedo->setText (completeText);
3346 }
3347 
3348 void MainWindow::slotSettingsAxesChecker ()
3349 {
3350  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsAxesChecker";
3351 
3352  m_dlgSettingsAxesChecker->load (*m_cmdMediator);
3353  m_dlgSettingsAxesChecker->show ();
3354 }
3355 
3356 void MainWindow::slotSettingsColorFilter ()
3357 {
3358  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsColorFilter";
3359 
3360  m_dlgSettingsColorFilter->load (*m_cmdMediator);
3361  m_dlgSettingsColorFilter->show ();
3362 }
3363 
3364 void MainWindow::slotSettingsCoords ()
3365 {
3366  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCoords";
3367 
3368  m_dlgSettingsCoords->load (*m_cmdMediator);
3369  m_dlgSettingsCoords->show ();
3370 }
3371 
3372 void MainWindow::slotSettingsCurveAddRemove ()
3373 {
3374  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveAddRemove";
3375 
3376  m_dlgSettingsCurveAddRemove->load (*m_cmdMediator);
3377  m_dlgSettingsCurveAddRemove->show ();
3378 }
3379 
3380 void MainWindow::slotSettingsCurveProperties ()
3381 {
3382  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveProperties";
3383 
3384  m_dlgSettingsCurveProperties->load (*m_cmdMediator);
3385  m_dlgSettingsCurveProperties->setCurveName (selectedGraphCurve ());
3386  m_dlgSettingsCurveProperties->show ();
3387 }
3388 
3389 void MainWindow::slotSettingsDigitizeCurve ()
3390 {
3391  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsDigitizeCurve";
3392 
3393  m_dlgSettingsDigitizeCurve->load (*m_cmdMediator);
3394  m_dlgSettingsDigitizeCurve->show ();
3395 }
3396 
3397 void MainWindow::slotSettingsExportFormat ()
3398 {
3399  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsExportFormat";
3400 
3401  if (transformIsDefined()) {
3402  m_dlgSettingsExportFormat->load (*m_cmdMediator);
3403  m_dlgSettingsExportFormat->show ();
3404  } else {
3405  DlgRequiresTransform dlg ("Export settings");
3406  dlg.exec();
3407  }
3408 }
3409 
3410 void MainWindow::slotSettingsGeneral ()
3411 {
3412  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGeneral";
3413 
3414  m_dlgSettingsGeneral->load (*m_cmdMediator);
3415  m_dlgSettingsGeneral->show ();
3416 }
3417 
3418 void MainWindow::slotSettingsGridDisplay()
3419 {
3420  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridDisplay";
3421 
3422  m_dlgSettingsGridDisplay->load (*m_cmdMediator);
3423  m_dlgSettingsGridDisplay->show ();
3424 }
3425 
3426 void MainWindow::slotSettingsGridRemoval ()
3427 {
3428  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridRemoval";
3429 
3430  m_dlgSettingsGridRemoval->load (*m_cmdMediator);
3431  m_dlgSettingsGridRemoval->show ();
3432 }
3433 
3434 void MainWindow::slotSettingsPointMatch ()
3435 {
3436  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsPointMatch";
3437 
3438  m_dlgSettingsPointMatch->load (*m_cmdMediator);
3439  m_dlgSettingsPointMatch->show ();
3440 }
3441 
3442 void MainWindow::slotSettingsSegments ()
3443 {
3444  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsSegments";
3445 
3446  m_dlgSettingsSegments->load (*m_cmdMediator);
3447  m_dlgSettingsSegments->show ();
3448 }
3449 
3450 void MainWindow::slotSettingsMainWindow ()
3451 {
3452  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsMainWindow";
3453 
3454  m_dlgSettingsMainWindow->loadMainWindowModel (*m_cmdMediator,
3455  m_modelMainWindow);
3456  m_dlgSettingsMainWindow->show ();
3457 }
3458 
3459 void MainWindow::slotTimeoutRegressionErrorReport ()
3460 {
3461  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionErrorReport"
3462  << " cmdStackIndex=" << m_cmdMediator->index()
3463  << " cmdStackCount=" << m_cmdMediator->count();
3464 
3465  if (m_cmdStackShadow->canRedo()) {
3466 
3467  // Always reset current directory before the command. This guarantees the upcoming redo step will work
3468  QDir::setCurrent (m_startupDirectory);
3469 
3470  m_cmdStackShadow->slotRedo();
3471 
3472  // Always reset current directory after the command. This guarantees the final export to file will work
3473  QDir::setCurrent (m_startupDirectory);
3474 
3475  } else {
3476 
3477 #ifndef OSX_RELEASE
3478  exportAllCoordinateSystemsAfterRegressionTests ();
3479 #endif
3480 
3481  // Regression test has finished so exit. We unset the dirty flag so there is no prompt
3482  m_cmdMediator->setClean();
3483  close();
3484 
3485  }
3486 }
3487 
3488 void MainWindow::slotTimeoutRegressionFileCmdScript ()
3489 {
3490  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionFileCmdScript";
3491 
3492  if (m_fileCmdScript->canRedo()) {
3493 
3494  // Always reset current directory before the command. This guarantees the upcoming redo step will work
3495  QDir::setCurrent (m_startupDirectory);
3496 
3497  m_fileCmdScript->redo(*this);
3498 
3499  // Always reset current directory after the command. This guarantees the final export to file will work
3500  QDir::setCurrent (m_startupDirectory);
3501 
3502  } else {
3503 
3504  // Script file might already have closed the Document so export only if last was not closed
3505  if (m_cmdMediator != 0) {
3506 
3507 #ifndef OSX_RELEASE
3508  exportAllCoordinateSystemsAfterRegressionTests ();
3509 #endif
3510 
3511  // We unset the dirty flag so there is no "Save changes?" prompt
3512  m_cmdMediator->setClean();
3513 
3514  }
3515 
3516  // Regression test has finished so exit
3517  close();
3518 
3519  }
3520 }
3521 
3522 void MainWindow::slotUndoTextChanged (const QString &text)
3523 {
3524  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotUndoTextChanged";
3525 
3526  QString completeText ("Undo");
3527  if (!text.isEmpty ()) {
3528  completeText += QString (" \"%1\"").arg (text);
3529  }
3530  m_actionEditUndo->setText (completeText);
3531 }
3532 
3533 void MainWindow::slotViewGridLines ()
3534 {
3535  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotViewGridLines";
3536 
3537  updateGridLines ();
3538 }
3539 
3540 void MainWindow::slotViewGroupBackground(QAction *action)
3541 {
3542  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupBackground";
3543 
3544  // Set the combobox
3545  BackgroundImage backgroundImage;
3546  int indexBackground;
3547  if (action == m_actionViewBackgroundNone) {
3548  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_NONE));
3549  backgroundImage = BACKGROUND_IMAGE_NONE;
3550  } else if (action == m_actionViewBackgroundOriginal) {
3551  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
3552  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
3553  } else if (action == m_actionViewBackgroundFiltered) {
3554  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_FILTERED));
3555  backgroundImage = BACKGROUND_IMAGE_FILTERED;
3556  } else {
3557  ENGAUGE_ASSERT (false);
3558 
3559  // Defaults if assert is disabled so execution continues
3560  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
3561  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
3562  }
3563 
3564  m_cmbBackground->setCurrentIndex (indexBackground);
3565  m_backgroundStateContext->setBackgroundImage (backgroundImage);
3566 }
3567 
3568 void MainWindow::slotViewGroupCurves(QAction * /* action */)
3569 {
3570  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupCurves";
3571 
3572  updateViewedCurves ();
3573 }
3574 
3575 void MainWindow::slotViewGroupStatus(QAction *action)
3576 {
3577  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupStatus";
3578 
3579  ENGAUGE_CHECK_PTR (m_statusBar); // At startup, make sure status bar is already set up when View menu gets initialized
3580 
3581  if (action == m_actionStatusNever) {
3582  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_NEVER);
3583  } else if (action == m_actionStatusTemporary) {
3584  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_TEMPORARY);
3585  } else {
3586  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_ALWAYS);
3587  }
3588 }
3589 
3590 void MainWindow::slotViewToolBarBackground ()
3591 {
3592  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarBackground";
3593 
3594  if (m_actionViewBackground->isChecked ()) {
3595  m_toolBackground->show();
3596  } else {
3597  m_toolBackground->hide();
3598  }
3599 }
3600 
3601 void MainWindow::slotViewToolBarChecklistGuide ()
3602 {
3603  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarChecklistGuide";
3604 
3605  if (m_actionViewChecklistGuide->isChecked ()) {
3606  m_dockChecklistGuide->show();
3607  } else {
3608  m_dockChecklistGuide->hide();
3609  }
3610 }
3611 
3612 void MainWindow::slotViewToolBarCoordSystem ()
3613 {
3614  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarCoordSystem";
3615 
3616  if (m_actionViewCoordSystem->isChecked ()) {
3617  m_toolCoordSystem->show();
3618  } else {
3619  m_toolCoordSystem->hide();
3620  }
3621 }
3622 
3623 void MainWindow::slotViewToolBarDigitize ()
3624 {
3625  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarDigitize";
3626 
3627  if (m_actionViewDigitize->isChecked ()) {
3628  m_toolDigitize->show();
3629  } else {
3630  m_toolDigitize->hide();
3631  }
3632 }
3633 
3634 void MainWindow::slotViewToolBarGeometryWindow ()
3635 {
3636  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarGeometryWindow";
3637 
3638  if (m_actionViewGeometryWindow->isChecked ()) {
3639  m_dockGeometryWindow->show();
3640  } else {
3641  m_dockGeometryWindow->hide();
3642  }
3643 }
3644 
3645 void MainWindow::slotViewToolBarSettingsViews ()
3646 {
3647  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarSettingsViews";
3648 
3649  if (m_actionViewSettingsViews->isChecked ()) {
3650  m_toolSettingsViews->show();
3651  } else {
3652  m_toolSettingsViews->hide();
3653  }
3654 }
3655 
3656 void MainWindow::slotViewToolTips ()
3657 {
3658  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolTips";
3659 
3660  loadToolTips();
3661 }
3662 
3663 void MainWindow::slotViewZoom(int zoom)
3664 {
3665  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom";
3666 
3667  // Update zoom controls and apply the zoom factor
3668  switch ((ZoomFactor) zoom) {
3669  case ZOOM_16_TO_1:
3670  m_actionZoom16To1->setChecked(true);
3671  slotViewZoom16To1 ();
3672  break;
3673  case ZOOM_8_TO_1:
3674  m_actionZoom8To1->setChecked(true);
3675  slotViewZoom8To1 ();
3676  break;
3677  case ZOOM_4_TO_1:
3678  m_actionZoom4To1->setChecked(true);
3679  slotViewZoom4To1 ();
3680  break;
3681  case ZOOM_2_TO_1:
3682  m_actionZoom2To1->setChecked(true);
3683  slotViewZoom2To1 ();
3684  break;
3685  case ZOOM_1_TO_1:
3686  m_actionZoom1To1->setChecked(true);
3687  slotViewZoom1To1 ();
3688  break;
3689  case ZOOM_1_TO_2:
3690  m_actionZoom1To2->setChecked(true);
3691  slotViewZoom1To2 ();
3692  break;
3693  case ZOOM_1_TO_4:
3694  m_actionZoom1To4->setChecked(true);
3695  slotViewZoom1To4 ();
3696  break;
3697  case ZOOM_1_TO_8:
3698  m_actionZoom1To8->setChecked(true);
3699  slotViewZoom1To8 ();
3700  break;
3701  case ZOOM_1_TO_16:
3702  m_actionZoom1To16->setChecked(true);
3703  slotViewZoom1To16 ();
3704  break;
3705  case ZOOM_FILL:
3706  m_actionZoomFill->setChecked(true);
3707  slotViewZoomFill ();
3708  break;
3709  }
3710 }
3711 
3712 void MainWindow::slotViewZoom16To1 ()
3713 {
3714  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom16To1";
3715 
3716  QTransform transform;
3717  transform.scale (16.0, 16.0);
3718  m_view->setTransform (transform);
3719  emit signalZoom(ZOOM_16_TO_1);
3720 }
3721 
3722 void MainWindow::slotViewZoom8To1 ()
3723 {
3724  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom8To1";
3725 
3726  QTransform transform;
3727  transform.scale (8.0, 8.0);
3728  m_view->setTransform (transform);
3729  emit signalZoom(ZOOM_8_TO_1);
3730 }
3731 
3732 void MainWindow::slotViewZoom4To1 ()
3733 {
3734  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom4To1";
3735 
3736  QTransform transform;
3737  transform.scale (4.0, 4.0);
3738  m_view->setTransform (transform);
3739  emit signalZoom(ZOOM_4_TO_1);
3740 }
3741 
3742 void MainWindow::slotViewZoom2To1 ()
3743 {
3744  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom2To1";
3745 
3746  QTransform transform;
3747  transform.scale (2.0, 2.0);
3748  m_view->setTransform (transform);
3749  emit signalZoom(ZOOM_2_TO_1);
3750 }
3751 
3752 void MainWindow::slotViewZoom1To1 ()
3753 {
3754  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom1To1";
3755 
3756  QTransform transform;
3757  transform.scale (1.0, 1.0);
3758  m_view->setTransform (transform);
3759  emit signalZoom(ZOOM_1_TO_1);
3760 }
3761 
3762 void MainWindow::slotViewZoom1To2 ()
3763 {
3764  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom1To2";
3765 
3766  QTransform transform;
3767  transform.scale (0.5, 0.5);
3768  m_view->setTransform (transform);
3769  emit signalZoom(ZOOM_1_TO_2);
3770 }
3771 
3772 void MainWindow::slotViewZoom1To4 ()
3773 {
3774  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom1To4";
3775 
3776  QTransform transform;
3777  transform.scale (0.25, 0.25);
3778  m_view->setTransform (transform);
3779  emit signalZoom(ZOOM_1_TO_4);
3780 }
3781 
3782 void MainWindow::slotViewZoom1To8 ()
3783 {
3784  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom1To8";
3785 
3786  QTransform transform;
3787  transform.scale (0.125, 0.125);
3788  m_view->setTransform (transform);
3789  emit signalZoom(ZOOM_1_TO_8);
3790 }
3791 
3792 void MainWindow::slotViewZoom1To16 ()
3793 {
3794  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotZoom1To16";
3795 
3796  QTransform transform;
3797  transform.scale (0.0625, 0.0625);
3798  m_view->setTransform (transform);
3799  emit signalZoom(ZOOM_1_TO_16);
3800 }
3801 
3802 void MainWindow::slotViewZoomFill ()
3803 {
3804  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomFill";
3805 
3806  m_backgroundStateContext->fitInView (*m_view);
3807 
3808  emit signalZoom(ZOOM_FILL);
3809 }
3810 
3811 void MainWindow::slotViewZoomIn ()
3812 {
3813  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomIn";
3814 
3815  // Try to zoom in. First determine what the next zoom factor should be
3816 
3817  bool goto16To1 = false, goto8To1 = false, goto4To1 = false, goto2To1 = false;
3818  bool goto1To1 = false;
3819  bool goto1To2 = false, goto1To4 = false, goto1To8 = false, goto1To16 = false;
3820  if (m_actionZoomFill->isChecked ()) {
3821 
3822  // Zooming in means user probably wants the more squished direction to be zoomed in by one step
3823  double xScale = m_view->transform().m11();
3824  double yScale = m_view->transform().m22();
3825  double scale = qMin(xScale, yScale);
3826  if (scale < 0.125) {
3827  goto1To8 = true;
3828  } else if (scale < 0.25) {
3829  goto1To4 = true;
3830  } else if (scale < 0.5) {
3831  goto1To2 = true;
3832  } else if (scale < 1) {
3833  goto1To1 = true;
3834  } else if (scale < 2) {
3835  goto2To1 = true;
3836  } else if (scale < 4) {
3837  goto4To1 = true;
3838  } else if (scale < 8) {
3839  goto8To1 = true;
3840  } else {
3841  goto1To16 = true;
3842  }
3843  } else {
3844  goto16To1 = m_actionZoom8To1->isChecked ();
3845  goto8To1 = m_actionZoom4To1->isChecked ();
3846  goto4To1 = m_actionZoom2To1->isChecked ();
3847  goto2To1 = m_actionZoom1To1->isChecked ();
3848  goto1To1 = m_actionZoom1To2->isChecked ();
3849  goto1To2 = m_actionZoom1To4->isChecked ();
3850  goto1To4 = m_actionZoom1To8->isChecked ();
3851  goto1To8 = m_actionZoom1To16->isChecked ();
3852  }
3853 
3854  // Update controls and apply zoom factor
3855  if (goto16To1) {
3856  m_actionZoom16To1->setChecked (true);
3857  slotViewZoom16To1 ();
3858  } else if (goto8To1) {
3859  m_actionZoom8To1->setChecked (true);
3860  slotViewZoom8To1 ();
3861  } else if (goto4To1) {
3862  m_actionZoom4To1->setChecked (true);
3863  slotViewZoom4To1 ();
3864  } else if (goto2To1) {
3865  m_actionZoom2To1->setChecked (true);
3866  slotViewZoom2To1 ();
3867  } else if (goto1To1) {
3868  m_actionZoom1To1->setChecked (true);
3869  slotViewZoom1To1 ();
3870  } else if (goto1To2) {
3871  m_actionZoom1To2->setChecked (true);
3872  slotViewZoom1To2 ();
3873  } else if (goto1To4) {
3874  m_actionZoom1To4->setChecked (true);
3875  slotViewZoom1To4 ();
3876  } else if (goto1To8) {
3877  m_actionZoom1To8->setChecked (true);
3878  slotViewZoom1To8 ();
3879  } else if (goto1To16) {
3880  m_actionZoom1To16->setChecked (true);
3881  slotViewZoom1To16 ();
3882  }
3883 }
3884 
3885 void MainWindow::slotViewZoomInFromWheelEvent ()
3886 {
3887  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomInFromWheelEvent";
3888 
3889  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
3890  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
3891 
3892  // Anchor the zoom to the cursor position
3893  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
3894 
3895  // Forward this event
3896  slotViewZoomIn ();
3897 
3898  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
3899  }
3900 }
3901 
3902 void MainWindow::slotViewZoomOut ()
3903 {
3904  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOut";
3905 
3906  // Try to zoom out. First determine what the next zoom factor should be
3907 
3908  bool goto16To1 = false, goto8To1 = false, goto4To1 = false, goto2To1 = false;
3909  bool goto1To1 = false;
3910  bool goto1To2 = false, goto1To4 = false, goto1To8 = false, goto1To16 = false;
3911  if (m_actionZoomFill->isChecked ()) {
3912 
3913  // Zooming out means user probably wants the less squished direction to be zoomed out by one step
3914  double xScale = m_view->transform().m11();
3915  double yScale = m_view->transform().m22();
3916  double scale = qMax(xScale, yScale);
3917  if (scale > 8) {
3918  goto8To1 = true;
3919  } else if (scale > 4) {
3920  goto4To1 = true;
3921  } else if (scale > 2) {
3922  goto2To1 = true;
3923  } else if (scale > 1) {
3924  goto1To1 = true;
3925  } else if (scale > 0.5) {
3926  goto1To2 = true;
3927  } else if (scale > 0.25) {
3928  goto1To4 = true;
3929  } else if (scale > 0.125) {
3930  goto1To8 = true;
3931  } else {
3932  goto1To16 = true;
3933  }
3934  } else {
3935  goto8To1 = m_actionZoom16To1->isChecked ();
3936  goto4To1 = m_actionZoom8To1->isChecked ();
3937  goto2To1 = m_actionZoom4To1->isChecked ();
3938  goto1To1 = m_actionZoom2To1->isChecked ();
3939  goto1To2 = m_actionZoom1To1->isChecked ();
3940  goto1To4 = m_actionZoom1To2->isChecked ();
3941  goto1To8 = m_actionZoom1To4->isChecked ();
3942  goto1To16 = m_actionZoom1To8->isChecked ();
3943  }
3944 
3945  // Update controls and apply zoom factor
3946  if (goto1To16) {
3947  m_actionZoom1To16->setChecked (true);
3948  slotViewZoom1To16 ();
3949  } else if (goto1To8) {
3950  m_actionZoom1To8->setChecked (true);
3951  slotViewZoom1To8 ();
3952  } else if (goto1To4) {
3953  m_actionZoom1To4->setChecked (true);
3954  slotViewZoom1To4 ();
3955  } else if (goto1To2) {
3956  m_actionZoom1To2->setChecked (true);
3957  slotViewZoom1To2 ();
3958  } else if (goto1To1) {
3959  m_actionZoom1To1->setChecked (true);
3960  slotViewZoom1To1 ();
3961  } else if (goto2To1) {
3962  m_actionZoom2To1->setChecked (true);
3963  slotViewZoom2To1 ();
3964  } else if (goto4To1) {
3965  m_actionZoom4To1->setChecked (true);
3966  slotViewZoom4To1 ();
3967  } else if (goto8To1) {
3968  m_actionZoom8To1->setChecked (true);
3969  slotViewZoom8To1 ();
3970  } else if (goto16To1) {
3971  m_actionZoom16To1->setChecked (true);
3972  slotViewZoom16To1 ();
3973  }
3974 }
3975 
3976 void MainWindow::slotViewZoomOutFromWheelEvent ()
3977 {
3978  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOutFromWheelEvent";
3979 
3980  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
3981  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
3982 
3983  // Anchor the zoom to the cursor position
3984  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
3985 
3986  // Forward this event
3987  slotViewZoomOut ();
3988 
3989  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
3990  }
3991 }
3992 
3993 void MainWindow::startRegressionTestErrorReport(const QString &regressionInputFile)
3994 {
3995  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestErrorReport";
3996 
3997  // In order for point-deleting commands to work (CmdCut, CmdDelete) in the regression tests, we need to
3998  // reset the Point identifier index here:
3999  // 1) after loading of the file which has increased the index value to greater than 0
4000  // 2) before running any commands since those commands implicitly assume the index is zero
4002 
4003  // Save output/export file name
4004  m_regressionFile = exportFilenameFromInputFilename (regressionInputFile);
4005 
4006  m_timerRegressionErrorReport = new QTimer();
4007  m_timerRegressionErrorReport->setSingleShot(false);
4008  connect (m_timerRegressionErrorReport, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionErrorReport()));
4009 
4010  m_timerRegressionErrorReport->start(REGRESSION_INTERVAL);
4011 }
4012 
4013 void MainWindow::startRegressionTestFileCmdScript()
4014 {
4015  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestFileCmdScript";
4016 
4017  m_timerRegressionFileCmdScript = new QTimer();
4018  m_timerRegressionFileCmdScript->setSingleShot(false);
4019  connect (m_timerRegressionFileCmdScript, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionFileCmdScript()));
4020 
4021  m_timerRegressionFileCmdScript->start(REGRESSION_INTERVAL);
4022 }
4023 
4025 {
4026  return m_transformation;
4027 }
4028 
4030 {
4031  return m_transformation.transformIsDefined();
4032 }
4033 
4035 {
4036  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommand";
4037 
4038  ENGAUGE_CHECK_PTR (m_cmdMediator);
4039 
4040  // Update transformation stuff, including the graph coordinates of every point in the Document, so coordinates in
4041  // status bar are up to date. Point coordinates in Document are also updated
4042  updateAfterCommandStatusBarCoords ();
4043 
4044  updateHighlightOpacity ();
4045 
4046  // Update graphics. Effectively, these steps do very little (just needed for highlight opacity)
4047  m_digitizeStateContext->updateAfterPointAddition (); // May or may not be needed due to point addition
4048 
4049  updateControls ();
4050  updateChecklistGuide ();
4051  updateGeometryWindow();
4052 
4053  // Final action at the end of a redo/undo is to checkpoint the Document and GraphicsScene to log files
4054  // so proper state can be verified
4055  writeCheckpointToLogFile ();
4056 
4057  // Since focus may have drifted over to Geometry Window or some other control we se focus on the GraphicsView
4058  // so the cursor is appropriate for the current state (otherwise it often ends up as default arrow)
4059  m_view->setFocus ();
4060 }
4061 
4062 void MainWindow::updateAfterCommandStatusBarCoords ()
4063 {
4064  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommandStatusBarCoords";
4065 
4066  // For some reason, mapFromGlobal(QCursor::pos) differs from event->pos by a little bit. We must compensate for
4067  // this so cursor coordinates in status bar match the DlgEditPointAxis inputs initially. After the mouse moves
4068  // the problem disappears since event->pos is available and QCursor::pos is no longer needed
4069  const QPoint HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT (1, 1);
4070 
4071  Transformation m_transformationBefore (m_transformation);
4072 
4073  updateTransformationAndItsDependencies();
4074 
4075  // Trigger state transitions for transformation if appropriate
4076  if (!m_transformationBefore.transformIsDefined() && m_transformation.transformIsDefined()) {
4077 
4078  // Transition from undefined to defined
4079  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_DEFINED,
4080  *m_cmdMediator,
4081  m_transformation,
4082  selectedGraphCurve());
4083 
4084  } else if (m_transformationBefore.transformIsDefined() && !m_transformation.transformIsDefined()) {
4085 
4086  // Transition from defined to undefined
4087  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
4088  *m_cmdMediator,
4089  m_transformation,
4090  selectedGraphCurve());
4091 
4092  } else if (m_transformation.transformIsDefined() && (m_transformationBefore != m_transformation)) {
4093 
4094  // There was not a define/undefined or undefined/defined transition, but the transformation changed so we
4095  // need to update the Checker
4096  m_transformationStateContext->updateAxesChecker(*m_cmdMediator,
4097  m_transformation);
4098 
4099  }
4100 
4101  QPoint posLocal = m_view->mapFromGlobal (QCursor::pos ()) - HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT;
4102  QPointF posScreen = m_view->mapToScene (posLocal);
4103 
4104  slotMouseMove (posScreen); // Update the status bar coordinates to reflect the newly updated transformation
4105 }
4106 
4108 {
4109  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterMouseRelease";
4110 
4111  updateControls ();
4112 }
4113 
4114 void MainWindow::updateChecklistGuide ()
4115 {
4116  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateChecklistGuide";
4117 
4118  m_isDocumentExported = true; // Set for next line and for all checklist guide updates after this
4119  m_dockChecklistGuide->update (*m_cmdMediator,
4120  m_isDocumentExported);
4121 }
4122 
4123 void MainWindow::updateControls ()
4124 {
4125  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateControls"
4126  << " selectedItems=" << m_scene->selectedItems().count();
4127 
4128  m_cmbBackground->setEnabled (!m_currentFile.isEmpty ());
4129 
4130  m_actionImportImageReplace->setEnabled (m_cmdMediator != 0);
4131 #ifndef OSX_RELEASE
4132  m_menuFileOpenRecent->setEnabled ((m_actionRecentFiles.count () > 0) &&
4133  (m_actionRecentFiles.at(0)->isVisible ())); // Need at least one visible recent file entry
4134 #endif
4135  m_actionClose->setEnabled (!m_currentFile.isEmpty ());
4136  m_actionSave->setEnabled (!m_currentFile.isEmpty ());
4137  m_actionSaveAs->setEnabled (!m_currentFile.isEmpty ());
4138  m_actionExport->setEnabled (!m_currentFile.isEmpty ());
4139  m_actionPrint->setEnabled (!m_currentFile.isEmpty ());
4140 
4141  if (m_cmdMediator == 0) {
4142  m_actionEditUndo->setEnabled (false);
4143  m_actionEditRedo->setEnabled (false);
4144  } else {
4145  m_actionEditUndo->setEnabled (m_cmdMediator->canUndo ());
4146  m_actionEditRedo->setEnabled (m_cmdMediator->canRedo () || m_cmdStackShadow->canRedo ());
4147  }
4148  m_actionEditCut->setEnabled (m_scene->selectedItems().count () > 0);
4149  m_actionEditCopy->setEnabled (m_scene->selectedItems().count () > 0);
4150  m_actionEditPaste->setEnabled (false);
4151  m_actionEditDelete->setEnabled (m_scene->selectedItems().count () > 0);
4152  // m_actionEditPasteAsNew and m_actionEditPasteAsNewAdvanced are updated when m_menuEdit is about to be shown
4153 
4154  m_actionDigitizeAxis->setEnabled (!m_currentFile.isEmpty ());
4155  m_actionDigitizeCurve ->setEnabled (!m_currentFile.isEmpty ());
4156  m_actionDigitizePointMatch->setEnabled (!m_currentFile.isEmpty ());
4157  m_actionDigitizeColorPicker->setEnabled (!m_currentFile.isEmpty ());
4158  m_actionDigitizeSegment->setEnabled (!m_currentFile.isEmpty ());
4159  m_actionDigitizeSelect->setEnabled (!m_currentFile.isEmpty ());
4160  if (m_transformation.transformIsDefined()) {
4161  m_actionViewGridLines->setEnabled (true);
4162  } else {
4163  m_actionViewGridLines->setEnabled (false);
4164  m_actionViewGridLines->setChecked (false);
4165  }
4166  m_actionViewBackground->setEnabled (!m_currentFile.isEmpty());
4167  m_actionViewChecklistGuide->setEnabled (!m_dockChecklistGuide->browserIsEmpty());
4168  m_actionViewDigitize->setEnabled (!m_currentFile.isEmpty ());
4169  m_actionViewSettingsViews->setEnabled (!m_currentFile.isEmpty ());
4170 
4171  m_actionSettingsCoords->setEnabled (!m_currentFile.isEmpty ());
4172  m_actionSettingsCurveAddRemove->setEnabled (!m_currentFile.isEmpty ());
4173  m_actionSettingsCurveProperties->setEnabled (!m_currentFile.isEmpty ());
4174  m_actionSettingsDigitizeCurve->setEnabled (!m_currentFile.isEmpty ());
4175  m_actionSettingsExport->setEnabled (!m_currentFile.isEmpty ());
4176  m_actionSettingsColorFilter->setEnabled (!m_currentFile.isEmpty ());
4177  m_actionSettingsAxesChecker->setEnabled (!m_currentFile.isEmpty ());
4178  m_actionSettingsGridDisplay->setEnabled (!m_currentFile.isEmpty () && m_transformation.transformIsDefined());
4179  m_actionSettingsGridRemoval->setEnabled (!m_currentFile.isEmpty ());
4180  m_actionSettingsPointMatch->setEnabled (!m_currentFile.isEmpty ());
4181  m_actionSettingsSegments->setEnabled (!m_currentFile.isEmpty ());
4182  m_actionSettingsGeneral->setEnabled (!m_currentFile.isEmpty ());
4183 
4184  m_groupBackground->setEnabled (!m_currentFile.isEmpty ());
4185  m_groupCurves->setEnabled (!m_currentFile.isEmpty ());
4186  m_groupZoom->setEnabled (!m_currentFile.isEmpty ());
4187 
4188  m_actionZoomIn->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
4189  m_actionZoomOut->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
4190 }
4191 
4192 void MainWindow::updateCoordSystem(CoordSystemIndex coordSystemIndex)
4193 {
4194  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateCoordSystem";
4195 
4196  // Set current curve in the Document and in the MainWindow combobox together so they are in sync. Setting
4197  // the selected curve prevents a crash in updateTransformationAndItsDependencies
4198  m_cmdMediator->document().setCoordSystemIndex (coordSystemIndex);
4199  loadCurveListFromCmdMediator ();
4200 
4201  updateTransformationAndItsDependencies(); // Transformation state may have changed
4202  updateSettingsAxesChecker(m_cmdMediator->document().modelAxesChecker()); // Axes checker dependes on transformation state
4203 
4204  // Nice trick for showing that a new coordinate system is in effect is to show the axes checker
4205  m_transformationStateContext->updateAxesChecker (*m_cmdMediator,
4206  m_transformation);
4207 
4209 }
4210 
4211 void MainWindow::updateDigitizeStateIfSoftwareTriggered (DigitizeState digitizeState)
4212 {
4213  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
4214 
4215  switch (digitizeState) {
4216  case DIGITIZE_STATE_AXIS:
4217  m_actionDigitizeAxis->setChecked(true);
4218  slotDigitizeAxis(); // Call the slot that the setChecked call fails to trigger
4219  break;
4220 
4221  case DIGITIZE_STATE_COLOR_PICKER:
4222  m_actionDigitizeColorPicker->setChecked(true);
4223  slotDigitizeColorPicker(); // Call the slot that the setChecked call fails to trigger
4224  break;
4225 
4226  case DIGITIZE_STATE_CURVE:
4227  m_actionDigitizeCurve->setChecked(true);
4228  slotDigitizeCurve(); // Call the slot that the setChecked call fails to trigger
4229  break;
4230 
4231  case DIGITIZE_STATE_EMPTY:
4232  break;
4233 
4234  case DIGITIZE_STATE_POINT_MATCH:
4235  m_actionDigitizePointMatch->setChecked(true);
4236  slotDigitizePointMatch(); // Call the slot that the setChecked call fails to trigger
4237  break;
4238 
4239  case DIGITIZE_STATE_SEGMENT:
4240  m_actionDigitizeSegment->setChecked(true);
4241  slotDigitizeSegment(); // Call the slot that the setChecked call fails to trigger
4242  break;
4243 
4244  case DIGITIZE_STATE_SELECT:
4245  m_actionDigitizeSelect->setChecked(true);
4246  slotDigitizeSelect(); // Call the slot that the setChecked call fails to trigger
4247  break;
4248 
4249  default:
4250  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
4251  break;
4252  }
4253 }
4254 
4255 void MainWindow::updateGeometryWindow ()
4256 {
4257  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGeometryWindow";
4258 
4259  // Update geometry window
4260  m_dockGeometryWindow->update (*m_cmdMediator,
4261  m_modelMainWindow,
4262  m_cmbCurve->currentText (),
4263  m_transformation);
4264 }
4265 
4267 {
4268  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGraphicsLinesToMatchGraphicsPoints";
4269 
4271  m_transformation);
4272 }
4273 
4274 void MainWindow::updateGridLines ()
4275 {
4276  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGridLines";
4277 
4278  // Remove old grid lines
4279  m_gridLines.clear ();
4280 
4281  // Create new grid lines
4282  GridLineFactory factory (*m_scene,
4283  m_cmdMediator->document().modelCoords());
4284  factory.createGridLinesForEvenlySpacedGrid (m_cmdMediator->document().modelGridDisplay(),
4285  m_cmdMediator->document(),
4286  m_modelMainWindow,
4287  m_transformation,
4288  m_gridLines);
4289 
4290  m_gridLines.setVisible (m_actionViewGridLines->isChecked());
4291 }
4292 
4293 void MainWindow::updateHighlightOpacity ()
4294 {
4295  if (m_cmdMediator != 0) {
4296 
4297  // Update the QGraphicsScene with the populated Curves. This requires the points in the Document to be already updated
4298  // by updateAfterCommandStatusBarCoords
4299  m_scene->updateAfterCommand (*m_cmdMediator,
4300  m_modelMainWindow.highlightOpacity(),
4301  m_dockGeometryWindow);
4302  }
4303 }
4304 
4305 void MainWindow::updateRecentFileList()
4306 {
4307  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateRecentFileList";
4308 
4309 #ifndef OSX_RELEASE
4310  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
4311  QStringList recentFilePaths = settings.value(SETTINGS_RECENT_FILE_LIST).toStringList();
4312 
4313  // Determine the desired size of the path list
4314  unsigned int count = recentFilePaths.size();
4315  if (count > MAX_RECENT_FILE_LIST_SIZE) {
4316  count = MAX_RECENT_FILE_LIST_SIZE;
4317  }
4318 
4319  // Add visible entries
4320  unsigned int i;
4321  for (i = 0; i < count; i++) {
4322  QString strippedName = QFileInfo (recentFilePaths.at(i)).fileName();
4323  m_actionRecentFiles.at (i)->setText (strippedName);
4324  m_actionRecentFiles.at (i)->setData (recentFilePaths.at (i));
4325  m_actionRecentFiles.at (i)->setVisible (true);
4326  }
4327 
4328  // Hide any extra entries
4329  for (i = count; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
4330  m_actionRecentFiles.at (i)->setVisible (false);
4331  }
4332 #endif
4333 }
4334 
4336 {
4337  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsAxesChecker";
4338 
4339  m_cmdMediator->document().setModelAxesChecker(modelAxesChecker);
4340  if (m_transformation.transformIsDefined()) {
4341  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_DEFINED,
4342  *m_cmdMediator,
4343  m_transformation,
4344  m_cmbCurve->currentText());
4345  } else {
4346  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
4347  *m_cmdMediator,
4348  m_transformation,
4349  m_cmbCurve->currentText());
4350  }
4351 }
4352 
4354 {
4355  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsColorFilter";
4356 
4357  m_cmdMediator->document().setModelColorFilter(modelColorFilter);
4358  m_backgroundStateContext->updateColorFilter (m_transformation,
4359  m_cmdMediator->document().modelGridRemoval(),
4360  modelColorFilter,
4361  m_cmbCurve->currentText());
4362  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
4364 }
4365 
4367 {
4368  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCoords";
4369 
4370  m_cmdMediator->document().setModelCoords(modelCoords);
4371 }
4372 
4374 {
4375  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveAddRemove";
4376 
4377  m_cmdMediator->document().setCurvesGraphs (curvesGraphs);
4378  loadCurveListFromCmdMediator();
4380 }
4381 
4383 {
4384  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveStyles";
4385 
4386  m_scene->updateCurveStyles(modelCurveStyles);
4387  m_cmdMediator->document().setModelCurveStyles(modelCurveStyles);
4389 }
4390 
4392 {
4393  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsDigitizeCurve";
4394 
4395  m_cmdMediator->document().setModelDigitizeCurve(modelDigitizeCurve);
4396  m_digitizeStateContext->updateModelDigitizeCurve (m_cmdMediator,
4397  modelDigitizeCurve);
4398 }
4399 
4401 {
4402  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsExportFormat";
4403 
4404  m_cmdMediator->document().setModelExport (modelExport);
4405 }
4406 
4408 {
4409  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGeneral";
4410 
4411  m_cmdMediator->document().setModelGeneral(modelGeneral);
4412 }
4413 
4415 {
4416  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridDisplay";
4417 
4418  m_cmdMediator->document().setModelGridDisplay(modelGridDisplay);
4419 }
4420 
4422 {
4423  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridRemoval";
4424 
4425  m_cmdMediator->document().setModelGridRemoval(modelGridRemoval);
4426 }
4427 
4428 void MainWindow::updateSettingsMainWindow()
4429 {
4430  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
4431 
4432  if (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_ONLY ||
4433  m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) {
4434 
4435  m_actionZoomIn->setShortcut (tr (""));
4436  m_actionZoomOut->setShortcut (tr (""));
4437 
4438  } else {
4439 
4440  m_actionZoomIn->setShortcut (tr ("+"));
4441  m_actionZoomOut->setShortcut (tr ("-"));
4442 
4443  }
4444 
4445  if ((m_scene != 0) &&
4446  (m_cmdMediator != 0)) {
4447  m_scene->updateCurveStyles(m_cmdMediator->document().modelCurveStyles());
4448  }
4449 
4450  updateHighlightOpacity();
4451  updateWindowTitle();
4452 }
4453 
4455 {
4456  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
4457 
4458  m_modelMainWindow = modelMainWindow;
4460 }
4461 
4463 {
4464  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsPointMatch";
4465 
4466  m_cmdMediator->document().setModelPointMatch(modelPointMatch);
4467 }
4468 
4470 {
4471  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsSegments";
4472 
4473  m_cmdMediator->document().setModelSegments(modelSegments);
4474  m_digitizeStateContext->updateModelSegments(modelSegments);
4475 }
4476 
4477 void MainWindow::updateSmallDialogs ()
4478 {
4479  m_dlgSettingsAxesChecker->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4480  m_dlgSettingsColorFilter->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4481  m_dlgSettingsCoords->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4482  m_dlgSettingsCurveAddRemove->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4483  m_dlgSettingsCurveProperties->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4484  m_dlgSettingsDigitizeCurve->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4485  m_dlgSettingsExportFormat->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4486  m_dlgSettingsGeneral->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4487  m_dlgSettingsGridDisplay->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4488  m_dlgSettingsGridRemoval->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4489  m_dlgSettingsMainWindow->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4490  m_dlgSettingsPointMatch->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4491  m_dlgSettingsSegments->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4492 }
4493 
4494 void MainWindow::updateTransformationAndItsDependencies()
4495 {
4496  m_transformation.update (!m_currentFile.isEmpty (),
4497  *m_cmdMediator,
4498  m_modelMainWindow);
4499 
4500  // Grid removal is affected by new transformation above
4501  m_backgroundStateContext->setCurveSelected (m_transformation,
4502  m_cmdMediator->document().modelGridRemoval(),
4503  m_cmdMediator->document().modelColorFilter(),
4504  m_cmbCurve->currentText ());
4505 
4506  // Grid display is also affected by new transformation above, if there was a transition into defined state
4507  // in which case that transition triggered the initialization of the grid display parameters
4508  updateGridLines();
4509 }
4510 
4511 void MainWindow::updateViewedCurves ()
4512 {
4513  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewedCurves";
4514 
4515  if (m_actionViewCurvesAll->isChecked ()) {
4516 
4517  m_scene->showCurves (true, true);
4518 
4519  } else if (m_actionViewCurvesSelected->isChecked ()) {
4520 
4521  m_scene->showCurves (true, false, selectedGraphCurve ());
4522 
4523  } else if (m_actionViewCurvesNone->isChecked ()) {
4524 
4525  m_scene->showCurves (false);
4526 
4527  } else {
4528  ENGAUGE_ASSERT (false);
4529  }
4530 }
4531 
4533 {
4534  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewsOfSettings";
4535 
4536  QString activeCurve = m_digitizeStateContext->activeCurve ();
4537 
4538  updateViewsOfSettings (activeCurve);
4539 }
4540 
4541 void MainWindow::updateViewsOfSettings (const QString &activeCurve)
4542 {
4543  if (activeCurve.isEmpty ()) {
4544 
4545  m_viewPointStyle->unsetPointStyle ();
4546  m_viewSegmentFilter->unsetColorFilterSettings ();
4547 
4548 
4549  } else {
4550 
4551  PointStyle pointStyle = m_cmdMediator->document().modelCurveStyles().curveStyle(activeCurve).pointStyle();
4552  m_viewPointStyle->setPointStyle (pointStyle);
4553 
4554  ColorFilterSettings colorFilterSettings = m_cmdMediator->document().modelColorFilter().colorFilterSettings(activeCurve);
4555  m_viewSegmentFilter->setColorFilterSettings (colorFilterSettings,
4556  m_cmdMediator->pixmap ());
4557 
4558  }
4559 }
4560 
4561 void MainWindow::updateWindowTitle ()
4562 {
4563  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateWindowTitle";
4564 
4565  const QString PLACEHOLDER ("[*]");
4566 
4567  QString title = QString (tr ("Engauge Digitizer %1")
4568  .arg (VERSION_NUMBER));
4569 
4570  QString fileNameMaybeStripped;
4571  if (!m_currentFileWithPathAndFileExtension.isEmpty()) {
4572 
4573  QFileInfo fileInfo (m_currentFileWithPathAndFileExtension);
4574 
4575  switch (m_modelMainWindow.mainTitleBarFormat())
4576  {
4577  case MAIN_TITLE_BAR_FORMAT_NO_PATH:
4578  fileNameMaybeStripped = fileInfo.baseName(); // Remove file extension and path for "clean look"
4579  break;
4580 
4581  case MAIN_TITLE_BAR_FORMAT_PATH:
4582  fileNameMaybeStripped = m_currentFileWithPathAndFileExtension;
4583  break;
4584  }
4585 
4586  title += QString (": %1")
4587  .arg (fileNameMaybeStripped);
4588  }
4589 
4590  // To prevent "QWidget::setWindowModified: The window title does not contain a [*] placeholder" warnings,
4591  // we always append a placeholder
4592  title += PLACEHOLDER;
4593 
4594  setWindowTitle (title);
4595 }
4596 
4598 {
4599  ENGAUGE_CHECK_PTR (m_view);
4600  return *m_view;
4601 }
4602 
4604 {
4605  ENGAUGE_CHECK_PTR (m_view);
4606  return *m_view;
4607 }
4608 
4609 void MainWindow::writeCheckpointToLogFile ()
4610 {
4611  // Document
4612  QString checkpointDoc;
4613  QTextStream strDoc (&checkpointDoc);
4614  m_cmdMediator->document().printStream(INDENTATION_PAST_TIMESTAMP,
4615  strDoc);
4616 
4617  // Scene
4618  QString checkpointScene;
4619  QTextStream strScene (&checkpointScene);
4620  m_scene->printStream (INDENTATION_PAST_TIMESTAMP,
4621  strScene);
4622 
4623  // Skip slow string manipulation if BEFORE call to LOG4CPP_DEBUG_S
4624  if (mainCat->getPriority() == log4cpp::Priority::DEBUG) {
4625 
4626  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::writeCheckpointToLogFile\n"
4627  << "--------------DOCUMENT CHECKPOINT START----------" << "\n"
4628  << checkpointDoc.toLatin1().data()
4629  << "---------------DOCUMENT CHECKPOINT END-----------" << "\n"
4630  << "----------------SCENE CHECKPOINT START-----------" << "\n"
4631  << checkpointScene.toLatin1().data()
4632  << "-----------------SCENE CHECKPOINT END------------" ;
4633  }
4634 }
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...
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void updateGraphicsLinesToMatchGraphicsPoints(const CurveStyles &modelCurveStyles, const Transformation &transformation)
A mouse move has just occurred so move the selected points, since they were dragged.
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 ...
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void setStatusBarMode(StatusBarMode statusBarMode)
Set the status bar visibility mode.
Definition: StatusBar.cpp:143
Model for DlgSettingsGridDisplay and CmdSettingsGridDisplay.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded...
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
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
Dialog for editing Segments settings, for DigitizeStateSegment.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void fitInView(GraphicsView &view)
Zoom so background fills the window.
void setModelPointMatch(const DocumentModelPointMatch &modelPointMatch)
Set method for DocumentModelPointMatch.
Definition: Document.cpp:955
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
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 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
void createGridLinesForEvenlySpacedGrid(const DocumentModelGridDisplay &modelGridDisplay, const Document &document, const MainWindowModel &modelMainWindow, const Transformation &transformation, GridLines &gridLines)
Create a rectangular (cartesian) or annular (polar) grid of evenly spaced grid lines.
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.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void updateViewsOfSettings(const QString &activeCurve)
Update curve-specific view of settings. Private version gets active curve name from DigitizeStateCont...
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.
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
bool smallDialogs() const
Get method for small dialogs flag.
Strategy class for exporting to a file. This strategy is external to the Document class so that class...
Definition: ExportToFile.h:25
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
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.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded...
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.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void redo(MainWindow &mainWindow)
Apply the next command. Requires non-empty stack.
void setPointStyle(const PointStyle &pointStyle)
Apply the PointStyle of the currently selected curve.
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.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
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.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
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.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void setZoomControl(ZoomControl zoomControl)
Set method for zoom control.
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 saveErrorReportFileAndExit(const char *comment, const char *file, int line, const char *context) const
Save error report and exit.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
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
void setSmallDialogs(bool smallDialogs)
Set method for small dialogs flag.
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
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
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.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.