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  // Get status bar coordinates
3683  QString coordsScreen, coordsGraph, resolutionGraph;
3684  m_transformation.coordTextForStatusBar (pos,
3685  coordsScreen,
3686  coordsGraph,
3687  resolutionGraph,
3688  modeMap ());
3689 
3690  // Update status bar coordinates
3691  m_statusBar->setCoordinates (coordsScreen,
3692  coordsGraph,
3693  resolutionGraph);
3694 
3695  // There used to be a call to updateGraphicsLinesToMatchGraphicsPoints here, but that resulted
3696  // in hundreds of gratuitous log messages as the cursor was moved around, and nothing important happened
3697 
3698  m_digitizeStateContext->handleMouseMove (m_cmdMediator,
3699  pos);
3700  }
3701 }
3702 
3703 void MainWindow::slotMousePress (QPointF pos)
3704 {
3705  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMousePress";
3706 
3707  m_scene->resetPositionHasChangedFlags();
3708 
3709  m_digitizeStateContext->handleMousePress (m_cmdMediator,
3710  pos);
3711 }
3712 
3713 void MainWindow::slotMouseRelease (QPointF pos)
3714 {
3715  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMouseRelease";
3716 
3717  if (pos.x() < 0 || pos.y() < 0) {
3718 
3719  // Cursor is outside the image so drop this event. However, call updateControls since this may be
3720  // a click-and-drag to select in which case the controls (especially Copy and Cut) reflect the new selection
3721  updateControls ();
3722 
3723  } else {
3724 
3725  // Cursor is within the image so process this as a normal mouse release
3726  m_digitizeStateContext->handleMouseRelease (m_cmdMediator,
3727  pos);
3728  }
3729 }
3730 
3731 void MainWindow::slotRecentFileAction ()
3732 {
3733  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileAction";
3734 
3735  QAction *action = qobject_cast<QAction*>(sender ());
3736 
3737  if (action) {
3738  QString fileName = action->data().toString();
3739  loadDocumentFile (fileName);
3740  }
3741 }
3742 
3743 void MainWindow::slotRecentFileClear ()
3744 {
3745  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileClear";
3746 
3747  QStringList emptyList;
3748 
3749  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
3750  settings.setValue (SETTINGS_RECENT_FILE_LIST,
3751  emptyList);
3752 
3753  updateRecentFileList();
3754 }
3755 
3756 void MainWindow::slotRedoTextChanged (const QString &text)
3757 {
3758  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotRedoTextChanged";
3759 
3760  QString completeText ("Redo");
3761  if (!text.isEmpty ()) {
3762  completeText += QString (" \"%1\"").arg (text);
3763  }
3764  m_actionEditRedo->setText (completeText);
3765 }
3766 
3767 void MainWindow::slotSettingsAxesChecker ()
3768 {
3769  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsAxesChecker";
3770 
3771  m_dlgSettingsAxesChecker->load (*m_cmdMediator);
3772  m_dlgSettingsAxesChecker->show ();
3773 }
3774 
3775 void MainWindow::slotSettingsColorFilter ()
3776 {
3777  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsColorFilter";
3778 
3779  m_dlgSettingsColorFilter->load (*m_cmdMediator);
3780  m_dlgSettingsColorFilter->show ();
3781 }
3782 
3783 void MainWindow::slotSettingsCoords ()
3784 {
3785  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCoords";
3786 
3787  m_dlgSettingsCoords->load (*m_cmdMediator);
3788  m_dlgSettingsCoords->show ();
3789 }
3790 
3791 void MainWindow::slotSettingsCurveAddRemove ()
3792 {
3793  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveAddRemove";
3794 
3795  m_dlgSettingsCurveAddRemove->load (*m_cmdMediator);
3796  m_dlgSettingsCurveAddRemove->show ();
3797 }
3798 
3799 void MainWindow::slotSettingsCurveProperties ()
3800 {
3801  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveProperties";
3802 
3803  m_dlgSettingsCurveProperties->load (*m_cmdMediator);
3804  m_dlgSettingsCurveProperties->setCurveName (selectedGraphCurve ());
3805  m_dlgSettingsCurveProperties->show ();
3806 }
3807 
3808 void MainWindow::slotSettingsDigitizeCurve ()
3809 {
3810  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsDigitizeCurve";
3811 
3812  m_dlgSettingsDigitizeCurve->load (*m_cmdMediator);
3813  m_dlgSettingsDigitizeCurve->show ();
3814 }
3815 
3816 void MainWindow::slotSettingsExportFormat ()
3817 {
3818  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsExportFormat";
3819 
3820  if (transformIsDefined()) {
3821  m_dlgSettingsExportFormat->load (*m_cmdMediator);
3822  m_dlgSettingsExportFormat->show ();
3823  } else {
3824  DlgRequiresTransform dlg ("Export settings");
3825  dlg.exec();
3826  }
3827 }
3828 
3829 void MainWindow::slotSettingsGeneral ()
3830 {
3831  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGeneral";
3832 
3833  m_dlgSettingsGeneral->load (*m_cmdMediator);
3834  m_dlgSettingsGeneral->show ();
3835 }
3836 
3837 void MainWindow::slotSettingsGridDisplay()
3838 {
3839  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridDisplay";
3840 
3841  m_dlgSettingsGridDisplay->load (*m_cmdMediator);
3842  m_dlgSettingsGridDisplay->show ();
3843 }
3844 
3845 void MainWindow::slotSettingsGridRemoval ()
3846 {
3847  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridRemoval";
3848 
3849  m_dlgSettingsGridRemoval->load (*m_cmdMediator);
3850  m_dlgSettingsGridRemoval->show ();
3851 }
3852 
3853 void MainWindow::slotSettingsPointMatch ()
3854 {
3855  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsPointMatch";
3856 
3857  m_dlgSettingsPointMatch->load (*m_cmdMediator);
3858  m_dlgSettingsPointMatch->show ();
3859 }
3860 
3861 void MainWindow::slotSettingsSegments ()
3862 {
3863  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsSegments";
3864 
3865  m_dlgSettingsSegments->load (*m_cmdMediator);
3866  m_dlgSettingsSegments->show ();
3867 }
3868 
3869 void MainWindow::slotTableStatusChange ()
3870 {
3871  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTableStatusChange";
3872 
3873  // This slot is called when either window in FittingWindow or GeometryWindow loses/gains focus. This is
3874  // so the Copy menu item can be updated
3875  updateControls ();
3876 }
3877 
3878 void MainWindow::slotSettingsMainWindow ()
3879 {
3880  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsMainWindow";
3881 
3882  m_dlgSettingsMainWindow->loadMainWindowModel (*m_cmdMediator,
3883  m_modelMainWindow);
3884  m_dlgSettingsMainWindow->show ();
3885 }
3886 
3887 void MainWindow::slotTimeoutRegressionErrorReport ()
3888 {
3889  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionErrorReport"
3890  << " cmdStackIndex=" << m_cmdMediator->index()
3891  << " cmdStackCount=" << m_cmdMediator->count();
3892 
3893  if (m_cmdStackShadow->canRedo()) {
3894 
3895  // Always reset current directory before the command. This guarantees the upcoming redo step will work
3896  QDir::setCurrent (m_startupDirectory);
3897 
3898  m_cmdStackShadow->slotRedo();
3899 
3900  // Always reset current directory after the command. This guarantees the final export to file will work
3901  QDir::setCurrent (m_startupDirectory);
3902 
3903  } else {
3904 
3905 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
3906  exportAllCoordinateSystemsAfterRegressionTests ();
3907 #endif
3908 
3909  // Regression test has finished so exit. We unset the dirty flag so there is no prompt
3910  m_cmdMediator->setClean();
3911  close();
3912 
3913  }
3914 }
3915 
3916 void MainWindow::slotTimeoutRegressionFileCmdScript ()
3917 {
3918  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionFileCmdScript";
3919 
3920  if (m_fileCmdScript->canRedo()) {
3921 
3922  // Always reset current directory before the command. This guarantees the upcoming redo step will work
3923  QDir::setCurrent (m_startupDirectory);
3924 
3925  m_fileCmdScript->redo(*this);
3926 
3927  // Always reset current directory after the command. This guarantees the final export to file will work
3928  QDir::setCurrent (m_startupDirectory);
3929 
3930  } else {
3931 
3932  // Script file might already have closed the Document so export only if last was not closed
3933  if (m_cmdMediator != 0) {
3934 
3935 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
3936  exportAllCoordinateSystemsAfterRegressionTests ();
3937 #endif
3938 
3939  // We unset the dirty flag so there is no "Save changes?" prompt
3940  m_cmdMediator->setClean();
3941 
3942  }
3943 
3944  // Regression test has finished so exit
3945  close();
3946 
3947  }
3948 }
3949 
3950 void MainWindow::slotUndoTextChanged (const QString &text)
3951 {
3952  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotUndoTextChanged";
3953 
3954  QString completeText ("Undo");
3955  if (!text.isEmpty ()) {
3956  completeText += QString (" \"%1\"").arg (text);
3957  }
3958  m_actionEditUndo->setText (completeText);
3959 }
3960 
3961 void MainWindow::slotViewGridLines ()
3962 {
3963  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotViewGridLines";
3964 
3965  updateGridLines ();
3966 }
3967 
3968 void MainWindow::slotViewGroupBackground(QAction *action)
3969 {
3970  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupBackground";
3971 
3972  // Set the combobox
3973  BackgroundImage backgroundImage;
3974  int indexBackground;
3975  if (action == m_actionViewBackgroundNone) {
3976  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_NONE));
3977  backgroundImage = BACKGROUND_IMAGE_NONE;
3978  } else if (action == m_actionViewBackgroundOriginal) {
3979  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
3980  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
3981  } else if (action == m_actionViewBackgroundFiltered) {
3982  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_FILTERED));
3983  backgroundImage = BACKGROUND_IMAGE_FILTERED;
3984  } else {
3985  ENGAUGE_ASSERT (false);
3986 
3987  // Defaults if assert is disabled so execution continues
3988  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
3989  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
3990  }
3991 
3992  m_cmbBackground->setCurrentIndex (indexBackground);
3993  m_backgroundStateContext->setBackgroundImage (backgroundImage);
3994 }
3995 
3996 void MainWindow::slotViewGroupCurves(QAction * /* action */)
3997 {
3998  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupCurves";
3999 
4000  updateViewedCurves ();
4001 }
4002 
4003 void MainWindow::slotViewGroupStatus(QAction *action)
4004 {
4005  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupStatus";
4006 
4007  ENGAUGE_CHECK_PTR (m_statusBar); // At startup, make sure status bar is already set up when View menu gets initialized
4008 
4009  if (action == m_actionStatusNever) {
4010  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_NEVER);
4011  } else if (action == m_actionStatusTemporary) {
4012  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_TEMPORARY);
4013  } else {
4014  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_ALWAYS);
4015  }
4016 }
4017 
4018 void MainWindow::slotViewToolBarBackground ()
4019 {
4020  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarBackground";
4021 
4022  if (m_actionViewBackground->isChecked ()) {
4023  m_toolBackground->show();
4024  } else {
4025  m_toolBackground->hide();
4026  }
4027 }
4028 
4029 void MainWindow::slotViewToolBarChecklistGuide ()
4030 {
4031  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarChecklistGuide";
4032 
4033  if (m_actionViewChecklistGuide->isChecked ()) {
4034  m_dockChecklistGuide->show();
4035  } else {
4036  m_dockChecklistGuide->hide();
4037  }
4038 }
4039 
4040 void MainWindow::slotViewToolBarCoordSystem ()
4041 {
4042  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarCoordSystem";
4043 
4044  if (m_actionViewCoordSystem->isChecked ()) {
4045  m_toolCoordSystem->show();
4046  } else {
4047  m_toolCoordSystem->hide();
4048  }
4049 }
4050 
4051 void MainWindow::slotViewToolBarDigitize ()
4052 {
4053  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarDigitize";
4054 
4055  if (m_actionViewDigitize->isChecked ()) {
4056  m_toolDigitize->show();
4057  } else {
4058  m_toolDigitize->hide();
4059  }
4060 }
4061 
4062 void MainWindow::slotViewToolBarFittingWindow()
4063 {
4064  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarFittingWindow";
4065 
4066  if (m_actionViewFittingWindow->isChecked()) {
4067  m_dockFittingWindow->show ();
4068  if (m_fittingCurve != 0) {
4069  m_fittingCurve->setVisible (true);
4070  }
4071  } else {
4072  m_dockFittingWindow->hide ();
4073  if (m_fittingCurve != 0) {
4074  m_fittingCurve->setVisible (false);
4075  }
4076  }
4077 }
4078 
4079 void MainWindow::slotViewToolBarGeometryWindow ()
4080 {
4081  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarGeometryWindow";
4082 
4083  if (m_actionViewGeometryWindow->isChecked ()) {
4084  m_dockGeometryWindow->show();
4085  } else {
4086  m_dockGeometryWindow->hide();
4087  }
4088 }
4089 
4090 void MainWindow::slotViewToolBarSettingsViews ()
4091 {
4092  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarSettingsViews";
4093 
4094  if (m_actionViewSettingsViews->isChecked ()) {
4095  m_toolSettingsViews->show();
4096  } else {
4097  m_toolSettingsViews->hide();
4098  }
4099 }
4100 
4101 void MainWindow::slotViewToolTips ()
4102 {
4103  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolTips";
4104 
4105  loadToolTips();
4106 }
4107 
4108 void MainWindow::slotViewZoom (int zoom)
4109 {
4110  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom";
4111 
4112  // Update zoom controls and apply the zoom factor
4113  ZoomFactor zoomFactor = (ZoomFactor) zoom;
4114  m_zoomMapToAction [zoomFactor]->setChecked (true);
4115  slotViewZoomFactor ((ZoomFactor) zoom);
4116 }
4117 
4118 void MainWindow::slotViewZoomFactor (ZoomFactor zoomFactor)
4119 {
4120  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomFactor";
4121 
4122  if (zoomFactor == ZOOM_FILL) {
4123  m_backgroundStateContext->fitInView (*m_view);
4124  } else {
4125 
4126  ZoomTransition zoomTransition;
4127  double factor = zoomTransition.mapToFactor (zoomFactor);
4128 
4129  QTransform transform;
4130  transform.scale (factor, factor);
4131  m_view->setTransform (transform);
4132  }
4133 
4134  emit signalZoom(zoomFactor);
4135 }
4136 
4137 void MainWindow::slotViewZoomFactorInt (int zoom)
4138 {
4139  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomFactorInt";
4140 
4141  slotViewZoomFactor ((ZoomFactor) zoom);
4142 }
4143 
4144 void MainWindow::slotViewZoomIn ()
4145 {
4146  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomIn";
4147 
4148  ZoomTransition zoomTransition;
4149  ZoomFactor zoomFactorNew = zoomTransition.zoomIn (currentZoomFactor (),
4150  m_view->transform ().m11 (),
4151  m_view->transform ().m22 (),
4152  m_actionZoomFill->isChecked ());
4153  setNonFillZoomFactor (zoomFactorNew);
4154 }
4155 
4156 
4157 void MainWindow::slotViewZoomInFromWheelEvent ()
4158 {
4159  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomInFromWheelEvent";
4160 
4161  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
4162  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
4163 
4164  // Anchor the zoom to the cursor position
4165  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
4166 
4167  // Forward this event
4168  slotViewZoomIn ();
4169 
4170  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
4171  }
4172 }
4173 
4174 void MainWindow::slotViewZoomOut ()
4175 {
4176  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOut";
4177 
4178  // Try to zoom out
4179  ZoomTransition zoomTransition;
4180  ZoomFactor zoomFactorNew = zoomTransition.zoomOut (currentZoomFactor (),
4181  m_view->transform ().m11 (),
4182  m_view->transform ().m22 (),
4183  m_actionZoomFill->isChecked ());
4184  setNonFillZoomFactor (zoomFactorNew);
4185 }
4186 
4187 void MainWindow::slotViewZoomOutFromWheelEvent ()
4188 {
4189  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOutFromWheelEvent";
4190 
4191  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
4192  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
4193 
4194  // Anchor the zoom to the cursor position
4195  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
4196 
4197  // Forward this event
4198  slotViewZoomOut ();
4199 
4200  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
4201  }
4202 }
4203 
4204 void MainWindow::startRegressionTestErrorReport(const QString &regressionInputFile)
4205 {
4206  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestErrorReport";
4207 
4208  // In order for point-deleting commands to work (CmdCut, CmdDelete) in the regression tests, we need to
4209  // reset the Point identifier index here:
4210  // 1) after loading of the file which has increased the index value to greater than 0
4211  // 2) before running any commands since those commands implicitly assume the index is zero
4213 
4214  // Save output/export file name
4215  m_regressionFile = exportFilenameFromInputFilename (regressionInputFile);
4216 
4217  m_timerRegressionErrorReport = new QTimer();
4218  m_timerRegressionErrorReport->setSingleShot(false);
4219  connect (m_timerRegressionErrorReport, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionErrorReport()));
4220 
4221  m_timerRegressionErrorReport->start(REGRESSION_INTERVAL);
4222 }
4223 
4224 void MainWindow::startRegressionTestFileCmdScript()
4225 {
4226  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestFileCmdScript";
4227 
4228  m_timerRegressionFileCmdScript = new QTimer();
4229  m_timerRegressionFileCmdScript->setSingleShot(false);
4230  connect (m_timerRegressionFileCmdScript, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionFileCmdScript()));
4231 
4232  m_timerRegressionFileCmdScript->start(REGRESSION_INTERVAL);
4233 }
4234 
4236 {
4237  return m_transformation;
4238 }
4239 
4241 {
4242  return m_transformation.transformIsDefined();
4243 }
4244 
4246 {
4247  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommand";
4248 
4249  ENGAUGE_CHECK_PTR (m_cmdMediator);
4250 
4251  // Update transformation stuff, including the graph coordinates of every point in the Document, so coordinates in
4252  // status bar are up to date. Point coordinates in Document are also updated
4253  updateAfterCommandStatusBarCoords ();
4254 
4255  updateHighlightOpacity ();
4256 
4257  // Update graphics. Effectively, these steps do very little (just needed for highlight opacity)
4258  m_digitizeStateContext->updateAfterPointAddition (); // May or may not be needed due to point addition
4259 
4260  updateControls ();
4261  updateChecklistGuide ();
4262  updateFittingWindow ();
4263  updateGeometryWindow();
4264 
4265  // Final action at the end of a redo/undo is to checkpoint the Document and GraphicsScene to log files
4266  // so proper state can be verified
4267  writeCheckpointToLogFile ();
4268 
4269  // Since focus may have drifted over to Geometry Window or some other control we se focus on the GraphicsView
4270  // so the cursor is appropriate for the current state (otherwise it often ends up as default arrow)
4271  m_view->setFocus ();
4272 }
4273 
4274 void MainWindow::updateAfterCommandStatusBarCoords ()
4275 {
4276  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommandStatusBarCoords";
4277 
4278  // For some reason, mapFromGlobal(QCursor::pos) differs from event->pos by a little bit. We must compensate for
4279  // this so cursor coordinates in status bar match the DlgEditPointAxis inputs initially. After the mouse moves
4280  // the problem disappears since event->pos is available and QCursor::pos is no longer needed
4281  const QPoint HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT (1, 1);
4282 
4283  Transformation m_transformationBefore (m_transformation);
4284 
4285  updateTransformationAndItsDependencies();
4286 
4287  // Trigger state transitions for transformation if appropriate
4288  if (!m_transformationBefore.transformIsDefined() && m_transformation.transformIsDefined()) {
4289 
4290  // Transition from undefined to defined
4291  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_DEFINED,
4292  *m_cmdMediator,
4293  m_transformation,
4294  selectedGraphCurve());
4295 
4296  } else if (m_transformationBefore.transformIsDefined() && !m_transformation.transformIsDefined()) {
4297 
4298  // Transition from defined to undefined
4299  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
4300  *m_cmdMediator,
4301  m_transformation,
4302  selectedGraphCurve());
4303 
4304  } else if (m_transformation.transformIsDefined() && (m_transformationBefore != m_transformation)) {
4305 
4306  // There was not a define/undefined or undefined/defined transition, but the transformation changed so we
4307  // need to update the Checker
4308  m_transformationStateContext->updateAxesChecker(*m_cmdMediator,
4309  m_transformation);
4310 
4311  }
4312 
4313  QPoint posLocal = m_view->mapFromGlobal (QCursor::pos ()) - HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT;
4314  QPointF posScreen = m_view->mapToScene (posLocal);
4315 
4316  slotMouseMove (posScreen); // Update the status bar coordinates to reflect the newly updated transformation
4317 }
4318 
4320 {
4321  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterMouseRelease";
4322 
4323  updateControls ();
4324 }
4325 
4326 void MainWindow::updateChecklistGuide ()
4327 {
4328  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateChecklistGuide";
4329 
4330  m_isDocumentExported = true; // Set for next line and for all checklist guide updates after this
4331  m_dockChecklistGuide->update (*m_cmdMediator,
4332  m_isDocumentExported);
4333 }
4334 
4335 void MainWindow::updateControls ()
4336 {
4337  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateControls"
4338  << " selectedItems=" << m_scene->selectedItems().count();
4339 
4340  m_cmbBackground->setEnabled (!m_currentFile.isEmpty ());
4341 
4342  m_actionImportImageReplace->setEnabled (m_cmdMediator != 0);
4343 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
4344  m_menuFileOpenRecent->setEnabled ((m_actionRecentFiles.count () > 0) &&
4345  (m_actionRecentFiles.at(0)->isVisible ())); // Need at least one visible recent file entry
4346 #endif
4347  m_actionClose->setEnabled (!m_currentFile.isEmpty ());
4348  m_actionSave->setEnabled (!m_currentFile.isEmpty ());
4349  m_actionSaveAs->setEnabled (!m_currentFile.isEmpty ());
4350  m_actionExport->setEnabled (!m_currentFile.isEmpty ());
4351  m_actionPrint->setEnabled (!m_currentFile.isEmpty ());
4352 
4353  if (m_cmdMediator == 0) {
4354  m_actionEditUndo->setEnabled (false);
4355  m_actionEditRedo->setEnabled (false);
4356  } else {
4357  m_actionEditUndo->setEnabled (m_cmdMediator->canUndo ());
4358  m_actionEditRedo->setEnabled (m_cmdMediator->canRedo () || m_cmdStackShadow->canRedo ());
4359  }
4360  bool tableFittingIsActive, tableFittingIsCopyable;
4361  bool tableGeometryIsActive, tableGeometryIsCopyable;
4362  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
4363  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
4364  m_actionEditCut->setEnabled (!tableFittingIsActive &&
4365  !tableGeometryIsActive &&
4366  m_scene->selectedItems().count () > 0);
4367  m_actionEditCopy->setEnabled ((!tableFittingIsActive && !tableGeometryIsActive && m_scene->selectedItems().count () > 0) ||
4368  (tableFittingIsActive && tableFittingIsCopyable) ||
4369  (tableGeometryIsActive && tableGeometryIsCopyable));
4370  m_actionEditPaste->setEnabled (m_digitizeStateContext->canPaste (m_transformation,
4371  m_view->size ()));
4372  m_actionEditDelete->setEnabled (!tableFittingIsActive &&
4373  !tableGeometryIsActive &&
4374  m_scene->selectedItems().count () > 0);
4375  // m_actionEditPasteAsNew and m_actionEditPasteAsNewAdvanced are updated when m_menuEdit is about to be shown
4376 
4377  m_actionDigitizeAxis->setEnabled (modeGraph ());
4378  m_actionDigitizeScale->setEnabled (modeMap ());
4379  m_actionDigitizeCurve ->setEnabled (!m_currentFile.isEmpty ());
4380  m_actionDigitizePointMatch->setEnabled (!m_currentFile.isEmpty ());
4381  m_actionDigitizeColorPicker->setEnabled (!m_currentFile.isEmpty ());
4382  m_actionDigitizeSegment->setEnabled (!m_currentFile.isEmpty ());
4383  m_actionDigitizeSelect->setEnabled (!m_currentFile.isEmpty ());
4384  if (m_transformation.transformIsDefined()) {
4385  m_actionViewGridLines->setEnabled (true);
4386  } else {
4387  m_actionViewGridLines->setEnabled (false);
4388  m_actionViewGridLines->setChecked (false);
4389  }
4390  m_actionViewBackground->setEnabled (!m_currentFile.isEmpty());
4391  m_actionViewChecklistGuide->setEnabled (!m_dockChecklistGuide->browserIsEmpty());
4392  m_actionViewDigitize->setEnabled (!m_currentFile.isEmpty ());
4393  m_actionViewSettingsViews->setEnabled (!m_currentFile.isEmpty ());
4394 
4395  m_actionSettingsCoords->setEnabled (!m_currentFile.isEmpty ());
4396  m_actionSettingsCurveAddRemove->setEnabled (!m_currentFile.isEmpty ());
4397  m_actionSettingsCurveProperties->setEnabled (!m_currentFile.isEmpty ());
4398  m_actionSettingsDigitizeCurve->setEnabled (!m_currentFile.isEmpty ());
4399  m_actionSettingsExport->setEnabled (!m_currentFile.isEmpty ());
4400  m_actionSettingsColorFilter->setEnabled (!m_currentFile.isEmpty ());
4401  m_actionSettingsAxesChecker->setEnabled (!m_currentFile.isEmpty ());
4402  m_actionSettingsGridDisplay->setEnabled (!m_currentFile.isEmpty () && m_transformation.transformIsDefined());
4403  m_actionSettingsGridRemoval->setEnabled (!m_currentFile.isEmpty ());
4404  m_actionSettingsPointMatch->setEnabled (!m_currentFile.isEmpty ());
4405  m_actionSettingsSegments->setEnabled (!m_currentFile.isEmpty ());
4406  m_actionSettingsGeneral->setEnabled (!m_currentFile.isEmpty ());
4407 
4408  m_groupBackground->setEnabled (!m_currentFile.isEmpty ());
4409  m_groupCurves->setEnabled (!m_currentFile.isEmpty ());
4410  m_groupZoom->setEnabled (!m_currentFile.isEmpty ());
4411 
4412  m_actionZoomIn->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
4413  m_actionZoomOut->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
4414 }
4415 
4416 void MainWindow::updateCoordSystem(CoordSystemIndex coordSystemIndex)
4417 {
4418  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateCoordSystem";
4419 
4420  // Set current curve in the Document and in the MainWindow combobox together so they are in sync. Setting
4421  // the selected curve prevents a crash in updateTransformationAndItsDependencies
4422  m_cmdMediator->document().setCoordSystemIndex (coordSystemIndex);
4423  loadCurveListFromCmdMediator ();
4424 
4425  updateTransformationAndItsDependencies(); // Transformation state may have changed
4426  updateSettingsAxesChecker(m_cmdMediator->document().modelAxesChecker()); // Axes checker dependes on transformation state
4427 
4428  // Nice trick for showing that a new coordinate system is in effect is to show the axes checker
4429  m_transformationStateContext->updateAxesChecker (*m_cmdMediator,
4430  m_transformation);
4431 
4433 }
4434 
4435 void MainWindow::updateDigitizeStateIfSoftwareTriggered (DigitizeState digitizeState)
4436 {
4437  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
4438 
4439  switch (digitizeState) {
4440  case DIGITIZE_STATE_AXIS:
4441  m_actionDigitizeAxis->setChecked(true);
4442  slotDigitizeAxis(); // Call the slot that the setChecked call fails to trigger
4443  break;
4444 
4445  case DIGITIZE_STATE_COLOR_PICKER:
4446  m_actionDigitizeColorPicker->setChecked(true);
4447  slotDigitizeColorPicker(); // Call the slot that the setChecked call fails to trigger
4448  break;
4449 
4450  case DIGITIZE_STATE_CURVE:
4451  m_actionDigitizeCurve->setChecked(true);
4452  slotDigitizeCurve(); // Call the slot that the setChecked call fails to trigger
4453  break;
4454 
4455  case DIGITIZE_STATE_EMPTY:
4456  break;
4457 
4458  case DIGITIZE_STATE_POINT_MATCH:
4459  m_actionDigitizePointMatch->setChecked(true);
4460  slotDigitizePointMatch(); // Call the slot that the setChecked call fails to trigger
4461  break;
4462 
4463  case DIGITIZE_STATE_SCALE:
4464  m_actionDigitizeScale->setChecked(true);
4465  slotDigitizeScale(); // Call the slot that the setChecked call fails to trigger
4466  break;
4467 
4468  case DIGITIZE_STATE_SEGMENT:
4469  m_actionDigitizeSegment->setChecked(true);
4470  slotDigitizeSegment(); // Call the slot that the setChecked call fails to trigger
4471  break;
4472 
4473  case DIGITIZE_STATE_SELECT:
4474  m_actionDigitizeSelect->setChecked(true);
4475  slotDigitizeSelect(); // Call the slot that the setChecked call fails to trigger
4476  break;
4477 
4478  default:
4479  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
4480  break;
4481  }
4482 }
4483 
4484 void MainWindow::updateFittingWindow ()
4485 {
4486  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateFittingWindow";
4487 
4488  if (m_cmdMediator != 0 &&
4489  m_cmbCurve != 0) {
4490 
4491  // Update fitting window
4492  m_dockFittingWindow->update (*m_cmdMediator,
4493  m_modelMainWindow,
4494  m_cmbCurve->currentText (),
4495  m_transformation);
4496  }
4497 }
4498 
4499 void MainWindow::updateGeometryWindow ()
4500 {
4501  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGeometryWindow";
4502 
4503  if (m_cmdMediator != 0 &&
4504  m_cmbCurve != 0) {
4505 
4506  // Update geometry window
4507  m_dockGeometryWindow->update (*m_cmdMediator,
4508  m_modelMainWindow,
4509  m_cmbCurve->currentText (),
4510  m_transformation);
4511  }
4512 }
4513 
4515 {
4516  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGraphicsLinesToMatchGraphicsPoints";
4517 
4519  m_transformation);
4520 }
4521 
4522 void MainWindow::updateGridLines ()
4523 {
4524  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGridLines";
4525 
4526  // Remove old grid lines
4527  m_gridLines.clear ();
4528 
4529  // Create new grid lines
4530  GridLineFactory factory (*m_scene,
4531  m_cmdMediator->document().modelCoords());
4532  factory.createGridLinesForEvenlySpacedGrid (m_cmdMediator->document().modelGridDisplay(),
4533  m_cmdMediator->document(),
4534  m_modelMainWindow,
4535  m_transformation,
4536  m_gridLines);
4537 
4538  m_gridLines.setVisible (m_actionViewGridLines->isChecked());
4539 }
4540 
4541 void MainWindow::updateHighlightOpacity ()
4542 {
4543  if (m_cmdMediator != 0) {
4544 
4545  // Update the QGraphicsScene with the populated Curves. This requires the points in the Document to be already updated
4546  // by updateAfterCommandStatusBarCoords
4547  m_scene->updateAfterCommand (*m_cmdMediator,
4548  m_modelMainWindow.highlightOpacity(),
4549  m_dockGeometryWindow);
4550  }
4551 }
4552 
4553 void MainWindow::updateRecentFileList()
4554 {
4555  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateRecentFileList";
4556 
4557 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
4558  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
4559  QStringList recentFilePaths = settings.value(SETTINGS_RECENT_FILE_LIST).toStringList();
4560 
4561  // Determine the desired size of the path list
4562  unsigned int count = recentFilePaths.size();
4563  if (count > MAX_RECENT_FILE_LIST_SIZE) {
4564  count = MAX_RECENT_FILE_LIST_SIZE;
4565  }
4566 
4567  // Add visible entries
4568  unsigned int i;
4569  for (i = 0; i < count; i++) {
4570  QString strippedName = QFileInfo (recentFilePaths.at(i)).fileName();
4571  m_actionRecentFiles.at (i)->setText (strippedName);
4572  m_actionRecentFiles.at (i)->setData (recentFilePaths.at (i));
4573  m_actionRecentFiles.at (i)->setVisible (true);
4574  }
4575 
4576  // Hide any extra entries
4577  for (i = count; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
4578  m_actionRecentFiles.at (i)->setVisible (false);
4579  }
4580 #endif
4581 }
4582 
4584 {
4585  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsAxesChecker";
4586 
4587  m_cmdMediator->document().setModelAxesChecker(modelAxesChecker);
4588  if (m_transformation.transformIsDefined()) {
4589  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_DEFINED,
4590  *m_cmdMediator,
4591  m_transformation,
4592  m_cmbCurve->currentText());
4593  } else {
4594  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
4595  *m_cmdMediator,
4596  m_transformation,
4597  m_cmbCurve->currentText());
4598  }
4599 }
4600 
4602 {
4603  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsColorFilter";
4604 
4605  m_cmdMediator->document().setModelColorFilter(modelColorFilter);
4606  m_backgroundStateContext->updateColorFilter (m_transformation,
4607  m_cmdMediator->document().modelGridRemoval(),
4608  modelColorFilter,
4609  m_cmbCurve->currentText());
4610  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
4612 }
4613 
4615 {
4616  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCoords";
4617 
4618  m_cmdMediator->document().setModelCoords(modelCoords);
4619 }
4620 
4622 {
4623  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveAddRemove";
4624 
4625  m_cmdMediator->document().setCurvesGraphs (curvesGraphs);
4626  loadCurveListFromCmdMediator();
4628 }
4629 
4631 {
4632  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveStyles";
4633 
4634  m_scene->updateCurveStyles(modelCurveStyles);
4635  m_cmdMediator->document().setModelCurveStyles(modelCurveStyles);
4637 }
4638 
4640 {
4641  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsDigitizeCurve";
4642 
4643  m_cmdMediator->document().setModelDigitizeCurve(modelDigitizeCurve);
4644  m_digitizeStateContext->updateModelDigitizeCurve (m_cmdMediator,
4645  modelDigitizeCurve);
4646 }
4647 
4649 {
4650  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsExportFormat";
4651 
4652  m_cmdMediator->document().setModelExport (modelExport);
4653 }
4654 
4656 {
4657  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGeneral";
4658 
4659  m_cmdMediator->document().setModelGeneral(modelGeneral);
4660 }
4661 
4663 {
4664  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridDisplay";
4665 
4666  m_cmdMediator->document().setModelGridDisplay(modelGridDisplay);
4667  updateGridLines ();
4668 }
4669 
4671 {
4672  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridRemoval";
4673 
4674  m_cmdMediator->document().setModelGridRemoval(modelGridRemoval);
4675 }
4676 
4678 {
4679  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
4680 
4681  if (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_ONLY ||
4682  m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) {
4683 
4684  m_actionZoomIn->setShortcut (tr (""));
4685  m_actionZoomOut->setShortcut (tr (""));
4686 
4687  } else {
4688 
4689  m_actionZoomIn->setShortcut (tr ("+"));
4690  m_actionZoomOut->setShortcut (tr ("-"));
4691 
4692  }
4693 
4694  if ((m_scene != 0) &&
4695  (m_cmdMediator != 0)) {
4696  m_scene->updateCurveStyles(m_cmdMediator->document().modelCurveStyles());
4697  }
4698 
4699  updateHighlightOpacity();
4700  updateWindowTitle();
4701  updateFittingWindow(); // Forward the drag and drop choice
4702  updateGeometryWindow(); // Forward the drag and drop choice
4703 }
4704 
4706 {
4707  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
4708 
4709  m_modelMainWindow = modelMainWindow;
4711 }
4712 
4714 {
4715  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsPointMatch";
4716 
4717  m_cmdMediator->document().setModelPointMatch(modelPointMatch);
4718 }
4719 
4721 {
4722  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsSegments";
4723 
4724  m_cmdMediator->document().setModelSegments(modelSegments);
4725  m_digitizeStateContext->updateModelSegments(modelSegments);
4726 }
4727 
4728 void MainWindow::updateSmallDialogs ()
4729 {
4730  m_dlgSettingsAxesChecker->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4731  m_dlgSettingsColorFilter->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4732  m_dlgSettingsCoords->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4733  m_dlgSettingsCurveAddRemove->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4734  m_dlgSettingsCurveProperties->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4735  m_dlgSettingsDigitizeCurve->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4736  m_dlgSettingsExportFormat->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4737  m_dlgSettingsGeneral->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4738  m_dlgSettingsGridDisplay->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4739  m_dlgSettingsGridRemoval->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4740  m_dlgSettingsMainWindow->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4741  m_dlgSettingsPointMatch->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4742  m_dlgSettingsSegments->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4743 }
4744 
4745 void MainWindow::updateTransformationAndItsDependencies()
4746 {
4747  m_transformation.update (!m_currentFile.isEmpty (),
4748  *m_cmdMediator,
4749  m_modelMainWindow);
4750 
4751  // Grid removal is affected by new transformation above
4752  m_backgroundStateContext->setCurveSelected (m_transformation,
4753  m_cmdMediator->document().modelGridRemoval(),
4754  m_cmdMediator->document().modelColorFilter(),
4755  m_cmbCurve->currentText ());
4756 
4757  // Grid display is also affected by new transformation above, if there was a transition into defined state
4758  // in which case that transition triggered the initialization of the grid display parameters
4759  updateGridLines();
4760 }
4761 
4762 void MainWindow::updateViewedCurves ()
4763 {
4764  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewedCurves";
4765 
4766  if (m_actionViewCurvesAll->isChecked ()) {
4767 
4768  m_scene->showCurves (true, true);
4769 
4770  } else if (m_actionViewCurvesSelected->isChecked ()) {
4771 
4772  m_scene->showCurves (true, false, selectedGraphCurve ());
4773 
4774  } else if (m_actionViewCurvesNone->isChecked ()) {
4775 
4776  m_scene->showCurves (false);
4777 
4778  } else {
4779  ENGAUGE_ASSERT (false);
4780  }
4781 }
4782 
4784 {
4785  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewsOfSettings";
4786 
4787  QString activeCurve = m_digitizeStateContext->activeCurve ();
4788 
4789  updateViewsOfSettings (activeCurve);
4790 }
4791 
4792 void MainWindow::updateViewsOfSettings (const QString &activeCurve)
4793 {
4794  if (activeCurve.isEmpty ()) {
4795 
4796  m_viewPointStyle->unsetPointStyle ();
4797  m_viewSegmentFilter->unsetColorFilterSettings ();
4798 
4799 
4800  } else {
4801 
4802  PointStyle pointStyle = m_cmdMediator->document().modelCurveStyles().curveStyle(activeCurve).pointStyle();
4803  m_viewPointStyle->setPointStyle (pointStyle);
4804 
4805  ColorFilterSettings colorFilterSettings = m_cmdMediator->document().modelColorFilter().colorFilterSettings(activeCurve);
4806  m_viewSegmentFilter->setColorFilterSettings (colorFilterSettings,
4807  m_cmdMediator->pixmap ());
4808 
4809  }
4810 }
4811 
4812 void MainWindow::updateWindowTitle ()
4813 {
4814  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateWindowTitle";
4815 
4816  const QString PLACEHOLDER ("[*]");
4817 
4818  QString title = QString (tr ("Engauge Digitizer %1")
4819  .arg (VERSION_NUMBER));
4820 
4821  QString fileNameMaybeStripped;
4822  if (!m_currentFileWithPathAndFileExtension.isEmpty()) {
4823 
4824  QFileInfo fileInfo (m_currentFileWithPathAndFileExtension);
4825 
4826  switch (m_modelMainWindow.mainTitleBarFormat())
4827  {
4828  case MAIN_TITLE_BAR_FORMAT_NO_PATH:
4829  fileNameMaybeStripped = fileInfo.baseName(); // Remove file extension and path for "clean look"
4830  break;
4831 
4832  case MAIN_TITLE_BAR_FORMAT_PATH:
4833  fileNameMaybeStripped = m_currentFileWithPathAndFileExtension;
4834  break;
4835  }
4836 
4837  title += QString (": %1")
4838  .arg (fileNameMaybeStripped);
4839  }
4840 
4841  // To prevent "QWidget::setWindowModified: The window title does not contain a [*] placeholder" warnings,
4842  // we always append a placeholder
4843  title += PLACEHOLDER;
4844 
4845  setWindowTitle (title);
4846 }
4847 
4849 {
4850  ENGAUGE_CHECK_PTR (m_view);
4851  return *m_view;
4852 }
4853 
4855 {
4856  ENGAUGE_CHECK_PTR (m_view);
4857  return *m_view;
4858 }
4859 
4860 void MainWindow::writeCheckpointToLogFile ()
4861 {
4862  // Document
4863  QString checkpointDoc;
4864  QTextStream strDoc (&checkpointDoc);
4865  m_cmdMediator->document().printStream(INDENTATION_PAST_TIMESTAMP,
4866  strDoc);
4867 
4868  // Scene
4869  QString checkpointScene;
4870  QTextStream strScene (&checkpointScene);
4871  m_scene->printStream (INDENTATION_PAST_TIMESTAMP,
4872  strScene);
4873 
4874  // Skip slow string manipulation if BEFORE call to LOG4CPP_DEBUG_S
4875  if (mainCat->getPriority() == log4cpp::Priority::DEBUG) {
4876 
4877  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::writeCheckpointToLogFile\n"
4878  << "--------------DOCUMENT CHECKPOINT START----------" << "\n"
4879  << checkpointDoc.toLatin1().data()
4880  << "---------------DOCUMENT CHECKPOINT END-----------" << "\n"
4881  << "----------------SCENE CHECKPOINT START-----------" << "\n"
4882  << checkpointScene.toLatin1().data()
4883  << "-----------------SCENE CHECKPOINT END------------" ;
4884  }
4885 }
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.
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...
void coordTextForStatusBar(QPointF cursorScreen, QString &coordsScreen, QString &coordsGraph, QString &resolutionGraph, bool usingScaleBar)
Return string descriptions of cursor coordinates for status bar.
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...
bool modeMap() const
True if document scale is set using a scale bar, otherwise using axis points.
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.