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