Engauge Digitizer  2
MainWindow.cpp
1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5  ******************************************************************************************************/
6 
7 #include "BackgroundImage.h"
8 #include "BackgroundStateContext.h"
9 #include "ChecklistGuide.h"
10 #include "ChecklistGuideWizard.h"
11 #include "CmdAddPointsGraph.h"
12 #include "CmdCopy.h"
13 #include "CmdCut.h"
14 #include "CmdDelete.h"
15 #include "CmdMediator.h"
16 #include "CmdSelectCoordSystem.h"
17 #include "CmdStackShadow.h"
18 #include "ColorFilter.h"
19 #include "CreateFacade.h"
20 #include "Curve.h"
21 #include "DataKey.h"
22 #include "DigitizeStateContext.h"
23 #include "DlgAbout.h"
24 #include "DlgErrorReportLocal.h"
25 #include "DlgImportAdvanced.h"
26 #include "DlgRequiresTransform.h"
27 #include "DlgSettingsAxesChecker.h"
28 #include "DlgSettingsColorFilter.h"
29 #include "DlgSettingsCoords.h"
30 #include "DlgSettingsCurveList.h"
31 #include "DlgSettingsCurveProperties.h"
32 #include "DlgSettingsDigitizeCurve.h"
33 #include "DlgSettingsExportFormat.h"
34 #include "DlgSettingsGeneral.h"
35 #include "DlgSettingsGridDisplay.h"
36 #include "DlgSettingsGridRemoval.h"
37 #include "DlgSettingsMainWindow.h"
38 #include "DlgSettingsPointMatch.h"
39 #include "DlgSettingsSegments.h"
40 #include "DocumentScrub.h"
41 #include "DocumentSerialize.h"
42 #include "EngaugeAssert.h"
43 #include "EnumsToQt.h"
44 #include "ExportImageForRegression.h"
45 #include "ExportToFile.h"
46 #include "FileCmdScript.h"
47 #include "FittingCurve.h"
48 #include "FittingWindow.h"
49 #include "GeometryWindow.h"
50 #include "Ghosts.h"
51 #include "GraphicsItemsExtractor.h"
52 #include "GraphicsItemType.h"
53 #include "GraphicsScene.h"
54 #include "GraphicsView.h"
55 #include "GridLineFactory.h"
56 #include "GridLineLimiter.h"
57 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
58 #include "HelpWindow.h"
59 #endif
60 #include "ImportImageExtensions.h"
61 #ifdef ENGAUGE_JPEG2000
62 #include "Jpeg2000.h"
63 #endif // ENGAUGE_JPEG2000
64 #include "LoadFileInfo.h"
65 #ifdef NETWORKING
66 #include "LoadImageFromUrl.h"
67 #endif
68 #include "Logger.h"
69 #include "MainDirectoryPersist.h"
70 #include "MainTitleBarFormat.h"
71 #include "MainWindow.h"
72 #include "MimePointsImport.h"
73 #ifdef NETWORKING
74 #include "NetworkClient.h"
75 #endif
76 #include "NonPdf.h"
77 #ifdef ENGAUGE_PDF
78 #include "Pdf.h"
79 #endif // ENGAUGE_PDF
80 #include "PdfResolution.h"
81 #include <QAction>
82 #include <QApplication>
83 #include <QClipboard>
84 #include <QCloseEvent>
85 #include <QComboBox>
86 #include <QDebug>
87 #include <QDesktopServices>
88 #include <QDockWidget>
89 #include <QDomDocument>
90 #include <QFileDialog>
91 #include <QFileInfo>
92 #include <QImageReader>
93 #include <QKeyEvent>
94 #include <QKeySequence>
95 #include <qmath.h>
96 #include <QMessageBox>
97 #include <QMouseEvent>
98 #include <QPrintDialog>
99 #include <QPrinter>
100 #include <QProcess>
101 #include <QPushButton>
102 #include <QSettings>
103 #include <QSignalMapper>
104 #include <QTextStream>
105 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
106 #include <QtHelp>
107 #endif
108 #include <QTimer>
109 #include <QToolBar>
110 #include <QToolButton>
111 #include "QtToString.h"
112 #include <QVBoxLayout>
113 #include <QWhatsThis>
114 #include <QXmlStreamReader>
115 #include <QXmlStreamWriter>
116 #include "ScaleBarAxisPointsUnite.h"
117 #include "Settings.h"
118 #include "StatusBar.h"
119 #include "TransformationStateContext.h"
120 #include "TutorialDlg.h"
121 #include "Version.h"
122 #include "ViewPointStyle.h"
123 #include "ViewSegmentFilter.h"
124 #include "ZoomFactor.h"
125 #include "ZoomFactorInitial.h"
126 #include "ZoomTransition.h"
127 
128 const QString EMPTY_FILENAME ("");
129 const char *ENGAUGE_FILENAME_DESCRIPTION = "Engauge Document";
130 const QString ENGAUGE_FILENAME_EXTENSION ("dig");
131 const int REGRESSION_INTERVAL = 400; // Milliseconds
132 const unsigned int MAX_RECENT_FILE_LIST_SIZE = 8;
133 
134 MainWindow::MainWindow(const QString &errorReportFile,
135  const QString &fileCmdScriptFile,
136  bool isRegressionTest,
137  bool isGnuplot,
138  bool isReset,
139  bool isExportOnly,
140  bool isExtractImageOnly,
141  const QString &extractImageOnlyExtension,
142  const QStringList &loadStartupFiles,
143  const QStringList &commandLineWithoutLoadStartupFiles,
144  QWidget *parent) :
145  QMainWindow(parent),
146  m_isDocumentExported (false),
147  m_engaugeFile (EMPTY_FILENAME),
148  m_currentFile (EMPTY_FILENAME),
149  m_layout (0),
150  m_scene (0),
151  m_view (0),
152  m_loadImageFromUrl (0),
153  m_cmdMediator (0),
154  m_digitizeStateContext (0),
155  m_transformationStateContext (0),
156  m_backgroundStateContext (0),
157  m_networkClient (0),
158  m_isGnuplot (isGnuplot),
159  m_commandLineWithoutLoadStartupFiles (commandLineWithoutLoadStartupFiles),
160  m_ghosts (0),
161  m_timerRegressionErrorReport(0),
162  m_fileCmdScript (0),
163  m_isErrorReportRegressionTest (isRegressionTest),
164  m_timerRegressionFileCmdScript(0),
165  m_fittingCurve (0),
166  m_isExportOnly (isExportOnly),
167  m_isExtractImageOnly (isExtractImageOnly),
168  m_extractImageOnlyExtension (extractImageOnlyExtension)
169 {
170  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::MainWindow"
171  << " curDir=" << QDir::currentPath().toLatin1().data();
172 
173 #if defined(OSX_DEBUG) || defined(OSX_RELEASE)
174  qApp->setApplicationName ("Engauge Digitizer");
175  qApp->setOrganizationDomain ("Mark Mitchell");
176 #endif
177 
179 
180  m_startupDirectory = QDir::currentPath();
181 
182  setCurrentFile ("");
183 
184  CreateFacade createFacade;
185  createFacade.create (*this);
186 
187  updateControls ();
188 
189  settingsRead (isReset); // This changes the current directory when not regression testing
190  setCurrentFile ("");
191  setUnifiedTitleAndToolBarOnMac(true);
192 
193  installEventFilter(this);
194 
195  // Start regression scripting if appropriate. Regression scripts assume current directory is the original
196  // current directory, so we temporarily reset the current directory
197  QString originalPath = QDir::currentPath();
198  QDir::setCurrent (m_startupDirectory);
199  if (isExportOnly) {
200  m_loadStartupFiles = loadStartupFiles;
201  m_regressionFile = exportRegressionFilenameFromInputFilename (loadStartupFiles.first ()); // For regression test
202  slotLoadStartupFiles ();
203  slotFileExport (); // Export one file. QProcess::startDetached will be called for each remaining file
204  exit (0);
205  } else if (isExtractImageOnly) {
206  m_loadStartupFiles = loadStartupFiles;
207  m_regressionFile = exportRegressionFilenameFromInputFilename (loadStartupFiles.first ()); // For regression test
208  slotLoadStartupFiles ();
209  handlerFileExtractImage (); // Extract one file. QProcess::startDetached will be called for each remaining file
210  exit (0);
211  } else if (!errorReportFile.isEmpty()) {
212  loadErrorReportFile(errorReportFile);
213  if (m_isErrorReportRegressionTest) {
214  startRegressionTestErrorReport(errorReportFile);
215  }
216  } else if (!fileCmdScriptFile.isEmpty()) {
217  m_fileCmdScript = new FileCmdScript (fileCmdScriptFile);
218  startRegressionTestFileCmdScript();
219  } else {
220 
221  // Save file names for later, after gui becomes available. The file names are dropped if error report file is specified
222  // since only one of the two modes is available at any time, for simplicity
223  m_loadStartupFiles = loadStartupFiles;
224  }
225  QDir::setCurrent (originalPath);
226 }
227 
228 MainWindow::~MainWindow()
229 {
230  delete m_fileCmdScript;
231 }
232 
233 void MainWindow::addDockWindow (QDockWidget *dockWidget,
234  QSettings &settings,
235  const QString &settingsTokenArea,
236  const QString &settingsTokenGeometry,
237  Qt::DockWidgetArea dockWidgetArea)
238 {
239  // Checklist guide is docked or undocked. Default is docked so it does not get overlooked by the user (which
240  // can happen if it opens elsewhere). The user may not know it can be undocked, but at least can resize or
241  // hide it if he/she needs more room for the main window.
242  const bool DOCKED_EQUALS_NOT_FLOATING = false;
243  Qt::DockWidgetArea area = (Qt::DockWidgetArea) settings.value (settingsTokenArea,
244  Qt::NoDockWidgetArea).toInt();
245 
246  if (area == Qt::NoDockWidgetArea) {
247 
248  addDockWidget (dockWidgetArea,
249  dockWidget); // Add on the right to prevent error message, then immediately make undocked
250  dockWidget->setFloating(DOCKED_EQUALS_NOT_FLOATING);
251  if (settings.contains (settingsTokenGeometry)) {
252  dockWidget->restoreGeometry (settings.value (settingsTokenGeometry).toByteArray());
253  }
254 
255  } else {
256 
257  addDockWidget (area,
258  dockWidget);
259 
260  }
261 }
262 
263 void MainWindow::applyZoomFactorAfterLoad()
264 {
265  ZoomFactor zoomFactor;
266  ZoomFactorInitial zoomFactorInitial = m_modelMainWindow.zoomFactorInitial();
267 
268  if (m_zoomMapFromInitial.contains (zoomFactorInitial)) {
269  zoomFactor = m_zoomMapFromInitial [zoomFactorInitial];
270  } else if (zoomFactorInitial == ZOOM_INITIAL_PREVIOUS) {
271  zoomFactor = currentZoomFactor ();
272  } else {
273  ENGAUGE_ASSERT (false);
274  zoomFactor = currentZoomFactor();
275  }
276 
277  slotViewZoom (zoomFactor);
278 }
279 
280 void MainWindow::closeEvent(QCloseEvent *event)
281 {
282  if (maybeSave()) {
283  settingsWrite ();
284  event->accept ();
285  } else {
286  event->ignore ();
287  }
288 }
289 
291 {
292  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileClose";
293 
294  setWindowModified (false); // Prevent popup query asking if changes should be saved
295  slotFileClose();
296 }
297 
298 void MainWindow::cmdFileExport(const QString &fileName)
299 {
300  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileExport";
301 
302  ExportToFile exportStrategy;
303  fileExport(fileName,
304  exportStrategy);
305 }
306 
307 void MainWindow::cmdFileImport(const QString &fileName)
308 {
309  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileImport";
310 
311  m_regressionFile = exportRegressionFilenameFromInputFilename (fileName);
312  fileImport (fileName,
313  IMPORT_TYPE_SIMPLE);
314 }
315 
316 void MainWindow::cmdFileOpen(const QString &fileName)
317 {
318  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileOpen";
319 
320  m_regressionFile = exportRegressionFilenameFromInputFilename (fileName);
321  loadDocumentFile(fileName);
322 }
323 
325 {
326  // We do not check m_cmdMediator with ENGAUGE_CHECK_PTR since calling code is expected to deal with null pointer at startup
327  return m_cmdMediator;
328 }
329 
330 ZoomFactor MainWindow::currentZoomFactor () const
331 {
332  // Find the zoom control that is checked
333  for (int z = 0; z < NUMBER_ZOOM_FACTORS; z++) {
334  ZoomFactor zoomFactor = (ZoomFactor) z;
335  if (m_zoomMapToAction [zoomFactor]->isChecked ()) {
336  // This zoom control is checked
337  return zoomFactor;
338  }
339  }
340 
341  ENGAUGE_ASSERT (false);
342  return ZOOM_1_TO_1;
343 }
344 
345 bool MainWindow::eventFilter(QObject *target, QEvent *event)
346 {
347  if (event->type () == QEvent::KeyPress) {
348 
349  QKeyEvent *eventKeyPress = (QKeyEvent *) event;
350 
351  // Special shortcuts. All of these are probably only useful for debugging and/or regression testing
352  if ((eventKeyPress->key() == Qt::Key_E) &&
353  ((eventKeyPress->modifiers() & Qt::ShiftModifier) != 0) &&
354  ((eventKeyPress->modifiers() & Qt::ControlModifier) != 0)) {
355 
356  saveErrorReportFileAndExit ("Shift+Control+E",
357  __FILE__,
358  __LINE__,
359  "userTriggered");
360 
361  }
362  }
363 
364  return QObject::eventFilter (target, event);
365 }
366 
367 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
368 void MainWindow::exportAllCoordinateSystemsAfterRegressionTests()
369 {
370  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::exportAllCoordinateSystemsAfterRegressionTests curDir=" << QDir::currentPath().toLatin1().data();
371 
372  // Output the regression test results. One file is output for every coordinate system
373  for (CoordSystemIndex index = 0; index < m_cmdMediator->document().coordSystemCount(); index++) {
374 
375  updateCoordSystem (index); // Switch to the specified coordinate system
376 
377  QString regressionFile = QString ("%1_%2")
378  .arg (m_regressionFile)
379  .arg (index + 1); // Append the coordinate system index
380 
381  // Normally we just export to a file, but when regression testing the export will fail since coordinates are not defined. To
382  // get an export file when regression testing, we just output the image size
383  if (m_isErrorReportRegressionTest && !m_transformation.transformIsDefined()) {
384 
385  ExportImageForRegression exportStrategy (m_cmdMediator->pixmap ());
386  exportStrategy.fileExport (regressionFile);
387 
388  } else {
389 
390  ExportToFile exportStrategy;
391 
392  fileExport (regressionFile,
393  exportStrategy);
394  }
395  }
396 }
397 #endif
398 
399 QString MainWindow::exportRegressionFilenameFromInputFilename (const QString &fileName) const
400 {
401  QString outFileName = fileName;
402 
403  outFileName = outFileName.replace (".xml", ".csv_actual", Qt::CaseInsensitive); // Applies when extension is xml
404  outFileName = outFileName.replace (".dig", ".csv_actual", Qt::CaseInsensitive); // Applies when extension is dig
405  outFileName = outFileName.replace (".pdf", ".csv_actual", Qt::CaseInsensitive); // Applies when extension is pdf
406 
407  return outFileName;
408 }
409 
410 void MainWindow::fileExport(const QString &fileName,
411  ExportToFile exportStrategy)
412 {
413  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileExport"
414  << " curDir=" << QDir::currentPath().toLatin1().data()
415  << " fileName=" << fileName.toLatin1().data();
416 
417  QFile file (fileName);
418  if (file.open(QIODevice::WriteOnly)) {
419 
420  QTextStream str (&file);
421 
422  DocumentModelExportFormat modelExportFormat = modelExportOverride (m_cmdMediator->document().modelExport(),
423  exportStrategy,
424  fileName);
425  exportStrategy.exportToFile (modelExportFormat,
426  m_cmdMediator->document(),
427  m_modelMainWindow,
428  transformation (),
429  str);
430 
431  m_isDocumentExported = true; // Remember that export was performed
432 
433  updateChecklistGuide ();
434  m_statusBar->showTemporaryMessage("File saved");
435 
436  } else {
437 
438  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::fileExport"
439  << " file=" << fileName.toLatin1().data()
440  << " curDir=" << QDir::currentPath().toLatin1().data();
441  QMessageBox::critical (0,
442  engaugeWindowTitle(),
443  tr ("Unable to export to file") + " " + fileName);
444  }
445 }
446 
447 void MainWindow::fileExtractImage (const QString &fileName)
448 {
449  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileExtractImage"
450  << " curDir=" << QDir::currentPath().toLatin1().data()
451  << " fileName=" << fileName.toLatin1().data();
452 
453  QFile file (fileName);
454  if (file.open(QIODevice::WriteOnly)) {
455 
456  QPixmap pixmap = m_cmdMediator->pixmap();
457  pixmap.save (&file);
458 
459  // Generate a checksum file if performing a regression test
460  if (m_isErrorReportRegressionTest) {
461  QString csvFile = QString ("%1_1")
462  .arg (exportRegressionFilenameFromInputFilename (m_regressionFile));
463 
464  // Generate csv file with only checksum. Since QProcess cannot handle pipes, we let shell execute it
465  QProcess process;
466  process.start ("bash -c \"cksum " + fileName + " | awk '{print $1}' > " + csvFile + "\"");
467  process.waitForFinished (-1);
468  }
469 
470  } else {
471 
472  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::fileExtractImage"
473  << " file=" << fileName.toLatin1().data()
474  << " curDir=" << QDir::currentPath().toLatin1().data();
475  QMessageBox::critical (0,
476  engaugeWindowTitle(),
477  tr ("Unable to extract image to file") + " " + fileName);
478  }
479 }
480 
481 void MainWindow::fileImport (const QString &fileName,
482  ImportType importType)
483 {
484  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileImport"
485  << " fileName=" << fileName.toLatin1 ().data ()
486  << " curDir=" << QDir::currentPath().toLatin1().data()
487  << " importType=" << importType;
488 
489  QString originalFileOld = m_originalFile;
490  bool originalFileWasImported = m_originalFileWasImported;
491 
492  m_originalFile = fileName; // Make this available for logging in case an error occurs during the load
493  m_originalFileWasImported = true;
494 
495  if (importType == IMPORT_TYPE_ADVANCED) {
496 
497  // Remove any existing points, axes checker(s) and such from the previous Document so they do not appear in setupAfterLoadNewDocument
498  // when previewing for IMAGE_TYPE_ADVANCED
499  slotFileClose();
500 
501  // Restore the background just closed by slotFileClose. This is required so when the image is loaded for preview, it will appear
502  m_backgroundStateContext->setBackgroundImage(BACKGROUND_IMAGE_ORIGINAL);
503  }
504 
505  QImage image;
506  bool loaded = false;
507 
508 #ifdef ENGAUGE_JPEG2000
509  Jpeg2000 jpeg2000;
510  loaded = jpeg2000.load (fileName,
511  image);
512 #endif // ENGAUGE_JPEG2000
513 
514 #ifdef ENGAUGE_PDF
515  if (!loaded) {
516 
517  Pdf pdf;
518  PdfReturn pdfReturn = pdf.load (fileName,
519  image,
520  m_modelMainWindow.pdfResolution(),
521  m_modelMainWindow.importCropping(),
522  m_isErrorReportRegressionTest);
523  if (pdfReturn == PDF_RETURN_CANCELED) {
524 
525  // User canceled so exit immediately
526  return;
527 
528  }
529 
530  loaded = (pdfReturn == PDF_RETURN_SUCCESS);
531  }
532 #endif // ENGAUGE_PDF
533 
534  if (!loaded) {
535  NonPdf nonPdf;
536  NonPdfReturn nonPdfReturn = nonPdf.load (fileName,
537  image,
538  m_modelMainWindow.importCropping(),
539  m_isErrorReportRegressionTest);
540  if (nonPdfReturn == NON_PDF_RETURN_CANCELED) {
541 
542  // User canceled so exit immediately
543  return;
544 
545  }
546 
547  loaded = (nonPdfReturn == NON_PDF_RETURN_SUCCESS);
548  }
549 
550  if (!loaded) {
551  QString msg = QString("%1 %2 %3 %4.")
552  .arg (tr ("Cannot read file"))
553  .arg (fileName)
554  .arg (tr ("from directory"))
555  .arg (QDir::currentPath());
556 #ifdef WIN32
557  if (fileName.contains ("???")) {
558 
559  // At this point the file name is filled with question marks in Windows if it had letter from
560  // more than one alphabet (e.g. latin '.dig' suffix and cyrillic basename)
561  // in which case we cannot recover the original file without user intervention
562  msg += QObject::tr ("The file appears to have characters from multiple language "
563  "alphabets, which does not work in the Windows command line");
564  }
565 #endif
566  QMessageBox::warning (this,
567  engaugeWindowTitle(),
568  msg);
569 
570  // Reset
571  m_originalFile = originalFileOld;
572  m_originalFileWasImported = originalFileWasImported;
573 
574  } else {
575 
576  loaded = loadImage (fileName,
577  image,
578  importType);
579 
580  if (!loaded) {
581 
582  // Failed
583  if (importType == IMPORT_TYPE_ADVANCED) {
584 
585  // User cancelled after another file was imported so it could be previewed. In anticipation of the loading-for-preview,
586  // we closed the current Document at the top of this method so we cannot reload. So, the only option is to close again
587  // so the half-imported current Document is removed
588  slotFileClose();
589 
590  } else {
591 
592  // Reset
593  m_originalFile = originalFileOld;
594  m_originalFileWasImported = originalFileWasImported;
595  }
596  }
597  }
598 }
599 
600 void MainWindow::fileImportWithPrompts (ImportType importType)
601 {
602  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileImportWithPrompts"
603  << " importType=" << importType;
604 
605  // Skip maybeSave method for IMPORT_TYPE_REPLACE_IMAGE since open file dialog is enough to allow user to cancel the operation, and
606  // since no information is lost in that case
607  bool okToContinue = true;
608  if (importType != IMPORT_TYPE_IMAGE_REPLACE) {
609  okToContinue = maybeSave ();
610  }
611 
612  if (okToContinue) {
613 
614  QString filter;
615  QTextStream str (&filter);
616 
617  ImportImageExtensions importImageExtensions;
618  QStringList supportedImageFormatStrings = importImageExtensions.fileExtensionsWithAsterisks ();
619 
620  str << "Image Files (" << supportedImageFormatStrings.join (" ") << ")";
621 
622  // Allow selection of files with strange suffixes in case the file extension was changed. Since
623  // the default is the first filter, we add this afterwards (it is the off-nominal case)
624  str << ";; All Files (*.*)";
625 
626  MainDirectoryPersist directoryPersist;
627  QString fileName = QFileDialog::getOpenFileName (this,
628  tr("Import Image"),
629  directoryPersist.getDirectoryImportOpen ().path (),
630  filter);
631  if (!fileName.isEmpty ()) {
632 
633  directoryPersist.setDirectoryImportOpenFromFilename (fileName);
634 
635  // We import the file BEFORE asking the number of coordinate systems, so user can see how many there are
636  fileImport (fileName,
637  importType);
638  }
639  }
640 }
641 
642 QString MainWindow::fileNameForExportOnly () const
643 {
644  ExportToFile exportStrategy;
645 
646  QString fileName;
647  if (m_isErrorReportRegressionTest) {
648 
649  // Regression test has a specific file extension
650  fileName = QString ("%1_1")
651  .arg (exportRegressionFilenameFromInputFilename (m_regressionFile));
652 
653  } else {
654 
655  // User requested export-only mode so just change file extension
656  QString dir = QFileInfo (m_currentFileWithPathAndFileExtension).absolutePath();
657  fileName = QString ("%1/%2.%3")
658  .arg (dir)
659  .arg (m_currentFile)
660  .arg (exportStrategy.fileExtensionCsv ());
661  }
662 
663  return fileName;
664 }
665 
666 QString MainWindow::fileNameForExtractImageOnly () const
667 {
668  // User requested export-only mode so just change file extension
669  QString dir = QFileInfo (m_currentFileWithPathAndFileExtension).absolutePath();
670  QString fileName = QString ("%1/%2.%3")
671  .arg (dir)
672  .arg (m_currentFile)
673  .arg (m_extractImageOnlyExtension);
674 
675  return fileName;
676 }
677 
678 void MainWindow::filePaste (ImportType importType)
679 {
680  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::filePaste"
681  << " importType=" << importType;
682 
683  QString originalFileOld = m_originalFile;
684  bool originalFileWasImported = m_originalFileWasImported;
685 
686  QString fileName ("clipboard");
687  m_originalFile = fileName; // Make this available for logging in case an error occurs during the load
688  m_originalFileWasImported = true;
689 
690  if (importType == IMPORT_TYPE_ADVANCED) {
691 
692  // Remove any existing points, axes checker(s) and such from the previous Document so they do not appear in setupAfterLoadNewDocument
693  // when previewing for IMAGE_TYPE_ADVANCED
694  slotFileClose();
695 
696  // Restore the background just closed by slotFileClose. This is required so when the image is loaded for preview, it will appear
697  m_backgroundStateContext->setBackgroundImage(BACKGROUND_IMAGE_ORIGINAL);
698  }
699 
700  // An image was in the clipboard when this method was called but it may have disappeared
701  QImage image = QApplication::clipboard()->image();
702 
703  bool loaded = false;
704  if (!loaded) {
705  loaded = !image.isNull();
706  }
707 
708  if (!loaded) {
709  QMessageBox::warning (this,
710  engaugeWindowTitle(),
711  QString("%1 %2 %3 %4.")
712  .arg (tr ("Cannot read file"))
713  .arg (fileName)
714  .arg (tr ("from directory"))
715  .arg (QDir::currentPath ()));
716 
717  // Reset
718  m_originalFile = originalFileOld;
719  m_originalFileWasImported = originalFileWasImported;
720 
721  } else {
722 
723  loaded = loadImage (fileName,
724  image,
725  importType);
726 
727  if (!loaded) {
728 
729  // Failed
730  if (importType == IMPORT_TYPE_ADVANCED) {
731 
732  // User cancelled after another file was imported so it could be previewed. In anticipation of the loading-for-preview,
733  // we closed the current Document at the top of this method so we cannot reload. So, the only option is to close again
734  // so the half-imported current Document is removed
735  slotFileClose();
736 
737  } else {
738 
739  // Reset
740  m_originalFile = originalFileOld;
741  m_originalFileWasImported = originalFileWasImported;
742  }
743  }
744  }
745 }
746 
747 void MainWindow::ghostsCreate ()
748 {
749  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::ghostsCreate";
750 
751  ENGAUGE_ASSERT (m_ghosts == 0);
752  m_ghosts = new Ghosts (m_cmdMediator->document().coordSystemIndex());
753 
754  for (unsigned int index = 0; index < m_cmdMediator->document().coordSystemCount(); index++) {
755 
756  // Skip this coordinate system if it is the selected coordinate system since it will be displayed anyway, so no ghosts are required
757  if (index != m_ghosts->coordSystemIndexToBeRestored ()) {
758 
759  updateCoordSystem (index);
760 
761  // Take a snapshot of the graphics items
762  m_ghosts->captureGraphicsItems (*m_scene);
763  }
764  }
765 
766  // Restore the coordinate system that was originally selected, so its points/lines are visible
768 
769  // Make visible ghosts
770  m_ghosts->createGhosts (*m_scene);
771 }
772 
773 void MainWindow::ghostsDestroy ()
774 {
775  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::ghostsDestroy";
776 
777  ENGAUGE_CHECK_PTR (m_ghosts);
778 
779  m_ghosts->destroyGhosts(*m_scene);
780 
781  delete m_ghosts;
782  m_ghosts = 0;
783 }
784 
785 void MainWindow::handlerFileExtractImage ()
786 {
787  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::handlerFileExtractImage";
788 
789  if (m_isExtractImageOnly) {
790  QString fileName = fileNameForExtractImageOnly ();
791 
792  MainDirectoryPersist directoryPersist;
793 
794  directoryPersist.setDirectoryExportSaveFromFilename(fileName);
795  fileExtractImage(fileName);
796  }
797 }
798 
800 {
801  return m_backgroundStateContext->imageForCurveState();
802 }
803 
805 {
806  return m_isGnuplot;
807 }
808 
809 void MainWindow::loadCoordSystemListFromCmdMediator ()
810 {
811  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadCoordSystemListFromCmdMediator";
812 
813  m_cmbCoordSystem->clear();
814 
815  unsigned int numberCoordSystem = m_cmdMediator->document().coordSystemCount();
816 
817  for (unsigned int i = 0; i < numberCoordSystem; i++) {
818  int index1Based = i + 1;
819  m_cmbCoordSystem->addItem (QString::number (index1Based),
820  QVariant (i));
821  }
822 
823  // Always start with the first entry selected
824  m_cmbCoordSystem->setCurrentIndex (0);
825 
826  // Disable the controls if there is only one entry. Hopefully the user will not even notice it, thus simplifying the interface
827  bool enable = (m_cmbCoordSystem->count() > 1);
828  m_cmbCoordSystem->setEnabled (enable);
829  m_btnShowAll->setEnabled (enable);
830  m_btnPrintAll->setEnabled (enable);
831 }
832 
833 void MainWindow::loadCurveListFromCmdMediator ()
834 {
835  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadCurveListFromCmdMediator";
836 
837  m_cmbCurve->clear ();
838  QStringList curvesGraphsNames = m_cmdMediator->curvesGraphsNames ();
839  QStringList::iterator itr;
840  for (itr = curvesGraphsNames.begin (); itr != curvesGraphsNames.end (); itr++) {
841 
842  QString curvesGraphName = *itr;
843  m_cmbCurve->addItem (curvesGraphName);
844  }
845 
846  // Select the curve that is associated with the current coordinate system
847  m_cmbCurve->setCurrentText (m_cmdMediator->selectedCurveName ());
848 }
849 
850 void MainWindow::loadDocumentFile (const QString &fileName)
851 {
852  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadDocumentFile fileName=" << fileName.toLatin1 ().data ();
853 
854  QApplication::setOverrideCursor(Qt::WaitCursor);
855  CmdMediator *cmdMediator = new CmdMediator (*this,
856  fileName);
857 
858  if (cmdMediator->successfulRead ()) {
859 
860  setCurrentPathFromFile (fileName);
861  rebuildRecentFileListForCurrentFile(fileName);
862  m_currentFile = fileName; // This enables the FileSaveAs menu option
863 
864  delete m_cmdMediator;
865 
866  m_cmdMediator = cmdMediator;
867  setupAfterLoadNewDocument (fileName,
868  tr ("File opened"),
869  IMPORT_TYPE_SIMPLE);
870 
871  // Start select mode
872  m_actionDigitizeSelect->setChecked (true); // We assume user wants to first select existing stuff
873  slotDigitizeSelect(); // Trigger transition so cursor gets updated immediately
874 
875  m_engaugeFile = fileName;
876  m_originalFile = fileName; // This is needed by updateAfterCommand below if an error report is generated
877  m_originalFileWasImported = false;
878 
879  updateGridLines ();
880  updateAfterCommand (); // Enable Save button now that m_engaugeFile is set
881 
882  QApplication::restoreOverrideCursor();
883 
884  } else {
885 
886  QApplication::restoreOverrideCursor();
887 
888  QMessageBox::warning (this,
889  engaugeWindowTitle(),
890  QString("%1 %2 %3 %4:\n%5.")
891  .arg (tr ("Cannot read file"))
892  .arg (fileName)
893  .arg (tr ("from directory"))
894  .arg (QDir::currentPath ())
896  delete cmdMediator;
897 
898  }
899 }
900 
901 void MainWindow::loadErrorReportFile(const QString &errorReportFile)
902 {
903  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadErrorReportFile"
904  << " file=" << errorReportFile.toLatin1().data();
905 
906  QFile file (errorReportFile);
907  if (!file.exists()) {
908  // Convert path from relative to absolute so file-not-found errors are easier to fix
909  QFileInfo fileInfo (errorReportFile);
910 
911  QMessageBox::critical (this,
912  engaugeWindowTitle(),
913  tr ("File not found") + ": " + fileInfo.absoluteFilePath());
914  exit (-1);
915  }
916 
917  // Open the error report file as if it was a regular Document file
918  QXmlStreamReader reader (&file);
919  file.open(QIODevice::ReadOnly | QIODevice::Text);
920  m_cmdMediator = new CmdMediator(*this,
921  errorReportFile);
922 
923  // Load the commands into the shadow command stack
924  m_cmdStackShadow->loadCommands (*this,
925  m_cmdMediator->document(),
926  reader);
927  file.close();
928 
929  setupAfterLoadNewDocument (errorReportFile,
930  tr ("Error report opened"),
931  IMPORT_TYPE_SIMPLE);
932 
933  // Start select mode
934  m_actionDigitizeSelect->setChecked (true); // We assume user wants to first select existing stuff
935  slotDigitizeSelect(); // Trigger transition so cursor gets updated immediately
936 
938 }
939 
940 bool MainWindow::loadImage (const QString &fileName,
941  const QImage &image,
942  ImportType importType)
943 {
944  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImage"
945  << " fileName=" << fileName.toLatin1 ().data ()
946  << " importType=" << importType;
947 
948  bool success;
949  if (importType == IMPORT_TYPE_IMAGE_REPLACE) {
950  success = loadImageReplacingImage (fileName,
951  image,
952  importType);
953  } else {
954  success = loadImageNewDocument (fileName,
955  image,
956  importType);
957  }
958 
959  return success;
960 }
961 
962 bool MainWindow::loadImageNewDocument (const QString &fileName,
963  const QImage &image,
964  ImportType importType)
965 {
966  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImageNewDocument"
967  << " fileName=" << fileName.toLatin1 ().data ()
968  << " importType=" << importType;
969 
970  ENGAUGE_ASSERT (importType != IMPORT_TYPE_IMAGE_REPLACE);
971 
972  QApplication::setOverrideCursor(Qt::WaitCursor);
973  CmdMediator *cmdMediator = new CmdMediator (*this,
974  image);
975  QApplication::restoreOverrideCursor();
976 
977  setCurrentPathFromFile (fileName);
978  // We do not call rebuildRecentFileListForCurrentFile for an image file, so only proper Engauge document files appear in the recent file list
979  m_engaugeFile = EMPTY_FILENAME; // Forces first Save to be treated as Save As
980 
981  delete m_cmdMediator;
982 
983  m_cmdMediator = cmdMediator;
984  bool accepted = setupAfterLoadNewDocument (fileName,
985  tr ("File imported"),
986  importType);
987 
988  if (accepted) {
989 
990  // Show the wizard if user selected it and we are not running a script
991  if (m_actionHelpChecklistGuideWizard->isChecked () &&
992  (m_fileCmdScript == 0)) {
993 
994  // Show wizard
995  ChecklistGuideWizard *wizard = new ChecklistGuideWizard (*this,
996  m_cmdMediator->document().coordSystemCount());
997  if (wizard->exec() == QDialog::Accepted) {
998 
999  for (CoordSystemIndex coordSystemIndex = 0; coordSystemIndex < m_cmdMediator->document().coordSystemCount(); coordSystemIndex++) {
1000 
1001  // Populate the checklist guide
1002  m_dockChecklistGuide->setTemplateHtml (wizard->templateHtml(coordSystemIndex),
1003  wizard->curveNames(coordSystemIndex));
1004 
1005  // Update Document
1006  CurvesGraphs curvesGraphs;
1007  wizard->populateCurvesGraphs (coordSystemIndex,
1008  curvesGraphs);
1009  m_cmdMediator->document().setCurvesGraphs(curvesGraphs);
1010  }
1011 
1012  // Unhide the checklist guide
1013  m_actionViewChecklistGuide->setChecked (true);
1014 
1015  // Update the curve dropdown
1016  loadCurveListFromCmdMediator();
1017 
1018  // Update the CoordSystem dropdown
1019  loadCoordSystemListFromCmdMediator();
1020  }
1021  delete wizard;
1022  }
1023 
1024  // Start axis mode
1025  m_actionDigitizeAxis->setChecked (true); // We assume user first wants to digitize axis points
1026 
1027  // Trigger transition so cursor gets updated immediately
1028  if (modeMap ()) {
1029  slotDigitizeScale ();
1030  } else if (modeGraph ()) {
1031  slotDigitizeAxis ();
1032  }
1033 
1034  updateControls ();
1035  }
1036 
1037  return accepted;
1038 }
1039 
1040 bool MainWindow::loadImageReplacingImage (const QString &fileName,
1041  const QImage &image,
1042  ImportType importType)
1043 {
1044  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImageReplacingImage"
1045  << " fileName=" << fileName.toLatin1 ().data ()
1046  << " importType=" << importType;
1047 
1048  ENGAUGE_ASSERT (importType == IMPORT_TYPE_IMAGE_REPLACE);
1049 
1050  setCurrentPathFromFile (fileName);
1051  // We do not call rebuildRecentFileListForCurrentFile for an image file, so only proper Engauge document files appear in the recent file list
1052  m_engaugeFile = EMPTY_FILENAME; // Forces first Save to be treated as Save As
1053 
1054  ENGAUGE_ASSERT (m_cmdMediator != 0); // Menu option should only be available when a document is currently open
1055 
1056  m_cmdMediator->document().setPixmap (image);
1057 
1058  bool accepted = setupAfterLoadReplacingImage (fileName,
1059  tr ("File imported"),
1060  importType);
1061 
1062  // No checklist guide wizard is displayed when just replacing the image
1063 
1064  return accepted;
1065 }
1066 
1067 void MainWindow::loadInputFileForErrorReport(QDomDocument &domInputFile) const
1068 {
1069  QFile file (m_originalFile);
1070 
1071  // File should be available for opening, if not then the dom will be left empty. We assume it has not been
1072  // modified since opened
1073  if (!file.open (QIODevice::ReadOnly)) {
1074  return;
1075  }
1076 
1077  domInputFile.setContent (&file);
1078  file.close();
1079 }
1080 
1081 void MainWindow::loadToolTips()
1082 {
1083  if (m_actionViewToolTips->isChecked ()) {
1084 
1085  // Show tool tips
1086  m_actionDigitizeSelect->setToolTip (m_actionDigitizeSelect->text());
1087  m_actionDigitizeAxis->setToolTip (m_actionDigitizeAxis->text());
1088  m_actionDigitizeScale->setToolTip (m_actionDigitizeScale->text());
1089  m_actionDigitizeCurve->setToolTip (m_actionDigitizeCurve->text());
1090  m_actionDigitizePointMatch->setToolTip (m_actionDigitizePointMatch->text());
1091  m_actionDigitizeColorPicker->setToolTip (m_actionDigitizeColorPicker->text());
1092  m_actionDigitizeSegment->setToolTip (m_actionDigitizeSegment->text());
1093  m_cmbBackground->setToolTip (tr ("Background image."));
1094  m_cmbCurve->setToolTip (tr ("Currently selected curve."));
1095  m_viewPointStyle->setToolTip (tr ("Point style for currently selected curve."));
1096  m_viewSegmentFilter->setToolTip (tr ("Segment Fill filter for currently selected curve."));
1097 
1098  } else {
1099 
1100  // Remove any previous tool tips
1101  m_actionDigitizeSelect->setToolTip ("");
1102  m_actionDigitizeAxis->setToolTip ("");
1103  m_actionDigitizeScale->setToolTip ("");
1104  m_actionDigitizeCurve->setToolTip ("");
1105  m_actionDigitizePointMatch->setToolTip ("");
1106  m_actionDigitizeColorPicker->setToolTip ("");
1107  m_actionDigitizeSegment->setToolTip ("");
1108  m_cmbBackground->setToolTip ("");
1109  m_cmbCurve->setToolTip ("");
1110  m_viewPointStyle->setToolTip ("");
1111  m_viewSegmentFilter->setToolTip ("");
1112 
1113  }
1114 }
1115 
1116 bool MainWindow::modeGraph () const
1117 {
1118  bool success = false;
1119 
1120  if (m_cmdMediator != 0) {
1121  success = (m_cmdMediator->document().documentAxesPointsRequired() != DOCUMENT_AXES_POINTS_REQUIRED_2);
1122  }
1123 
1124  return success;
1125 }
1126 
1127 bool MainWindow::modeMap () const
1128 {
1129  bool success = false;
1130 
1131  if (m_cmdMediator != 0) {
1132  success = (m_cmdMediator->document().documentAxesPointsRequired() == DOCUMENT_AXES_POINTS_REQUIRED_2);
1133  }
1134 
1135  return success;
1136 }
1137 
1138 bool MainWindow::maybeSave()
1139 {
1140  if (m_cmdMediator != 0) {
1141  if (m_cmdMediator->isModified()) {
1142  QMessageBox::StandardButton ret = QMessageBox::warning (this,
1143  engaugeWindowTitle(),
1144  tr("The document has been modified.\n"
1145  "Do you want to save your changes?"),
1146  QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
1147  if (ret == QMessageBox::Save) {
1148  return slotFileSave();
1149  } else if (ret == QMessageBox::Cancel) {
1150  return false;
1151  }
1152  }
1153  }
1154 
1155  return true;
1156 }
1157 
1158 DocumentModelExportFormat MainWindow::modelExportOverride (const DocumentModelExportFormat &modelExportFormatBefore,
1159  const ExportToFile &exportStrategy,
1160  const QString &fileName) const
1161 {
1162  DocumentModelExportFormat modelExportFormatAfter = modelExportFormatBefore;
1163 
1164  // See if delimiter setting overrides commas/tabs for files with csv/tsv file extensions respectively
1165  if (!modelExportFormatAfter.overrideCsvTsv()) {
1166 
1167  // Extract file extensions
1168  QString csvExtension = QString (".%1")
1169  .arg (exportStrategy.fileExtensionCsv());
1170  QString tsvExtension = QString (".%1")
1171  .arg (exportStrategy.fileExtensionTsv());
1172  QString fileExtensionVersusCsv = fileName.right (csvExtension.size());
1173  QString fileExtensionVersusTsv = fileName.right (tsvExtension.size());
1174 
1175  // Override if CSV or TSV was selected. We cannot use QFileDialog::selectedNameFilter() since that is
1176  // broken in Linux, so we use the file extension
1177  if (csvExtension.compare (fileExtensionVersusCsv, Qt::CaseInsensitive) == 0) {
1178  modelExportFormatAfter.setDelimiter (EXPORT_DELIMITER_COMMA);
1179  } else if (tsvExtension.compare (fileExtensionVersusTsv, Qt::CaseInsensitive) == 0) {
1180  modelExportFormatAfter.setDelimiter (EXPORT_DELIMITER_TAB);
1181  }
1182  }
1183 
1184  return modelExportFormatAfter;
1185 }
1186 
1188 {
1189  return m_modelMainWindow;
1190 }
1191 
1192 void MainWindow::rebuildRecentFileListForCurrentFile(const QString &filePath)
1193 {
1194  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::rebuildRecentFileListForCurrentFile";
1195 
1196  setWindowFilePath (filePath);
1197 
1198  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
1199  QStringList recentFilePaths = settings.value (SETTINGS_RECENT_FILE_LIST).toStringList();
1200  recentFilePaths.removeAll (filePath); // Remove previous instance of the current filePath
1201  recentFilePaths.prepend (filePath); // Insert current filePath at start
1202  while (recentFilePaths.count () > (int) MAX_RECENT_FILE_LIST_SIZE) {
1203  recentFilePaths.removeLast (); // Remove entry since the number of entries exceeds the limit
1204  }
1205  settings.setValue (SETTINGS_RECENT_FILE_LIST, recentFilePaths);
1206 
1207  updateRecentFileList();
1208 }
1209 
1210 void MainWindow::resizeEvent(QResizeEvent * /* event */)
1211 {
1212  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::resizeEvent";
1213 
1214  if (m_actionZoomFill->isChecked ()) {
1215  slotViewZoomFactor (ZOOM_FILL);
1216  }
1217 }
1218 
1219 bool MainWindow::saveDocumentFile (const QString &fileName)
1220 {
1221  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::saveDocumentFile fileName=" << fileName.toLatin1 ().data ();
1222 
1223  QFile file(fileName);
1224  if (!file.open(QFile::WriteOnly)) {
1225  QMessageBox::warning (this,
1226  engaugeWindowTitle(),
1227  QString ("%1 %2: \n%3.")
1228  .arg(tr ("Cannot write file"))
1229  .arg(fileName)
1230  .arg(file.errorString()));
1231  return false;
1232  }
1233 
1234  rebuildRecentFileListForCurrentFile (fileName);
1235 
1236  QApplication::setOverrideCursor (Qt::WaitCursor);
1237  QXmlStreamWriter writer(&file);
1238  writer.setAutoFormatting(true);
1239  writer.writeStartDocument();
1240  writer.writeDTD("<!DOCTYPE engauge>");
1241  m_cmdMediator->document().saveXml(writer);
1242  writer.writeEndDocument();
1243  QApplication::restoreOverrideCursor ();
1244 
1245  // Notify the undo stack that the current state is now considered "clean". This will automatically trigger a
1246  // signal back to this class that will update the modified marker in the title bar
1247  m_cmdMediator->setClean ();
1248 
1249  setCurrentFile(fileName);
1250  m_engaugeFile = fileName;
1251  updateAfterCommand (); // Enable Save button now that m_engaugeFile is set
1252  m_statusBar->showTemporaryMessage("File saved");
1253 
1254  return true;
1255 }
1256 
1257 void MainWindow::saveErrorReportFileAndExit (const char *context,
1258  const char *file,
1259  int line,
1260  const char *comment)
1261 {
1262  // Skip if currently performing a regression test - in which case the preferred behavior is to let the current test fail and
1263  // continue on to execute the remaining tests
1264  if ((m_cmdMediator != 0) && !m_isErrorReportRegressionTest) {
1265 
1266  QString report = saveErrorReportFileAndExitXml (context,
1267  file,
1268  line,
1269  comment);
1270 
1271  DlgErrorReportLocal dlg (report);
1272  if (dlg.exec() == QDialog::Accepted) {
1273  QFileDialog dlg;
1274 
1275  QString fileName = dlg.getSaveFileName (this,
1276  tr("Save"),
1277  "error_report.xml");
1278  if (!fileName.isEmpty ()) {
1279  // Save the error report
1280  QFile fileError (fileName);
1281  QTextStream str (&fileError);
1282  fileError.open (QIODevice::WriteOnly | QIODevice::Text);
1283  str << report;
1284  fileError.close ();
1285  }
1286  }
1287 
1288  exit (-1);
1289  }
1290 }
1291 
1292 QString MainWindow::saveErrorReportFileAndExitXml (const char *context,
1293  const char *file,
1294  int line,
1295  const char *comment) const
1296 {
1297  const bool DEEP_COPY = true;
1298 
1299  QString xmlErrorReport;
1300  QXmlStreamWriter writer (&xmlErrorReport);
1301  writer.setAutoFormatting(true);
1302 
1303  // Entire error report contains metadata, commands and other details
1304  writer.writeStartElement(DOCUMENT_SERIALIZE_ERROR_REPORT);
1305 
1306  // Version
1307  writer.writeStartElement(DOCUMENT_SERIALIZE_APPLICATION);
1308  writer.writeAttribute(DOCUMENT_SERIALIZE_APPLICATION_VERSION_NUMBER, VERSION_NUMBER);
1309  writer.writeEndElement();
1310 
1311  // Document
1312  // Insert snapshot xml into writer stream, by reading from reader stream. Highest level of snapshot is DOCUMENT_SERIALIZE_APPLICATION
1313  QXmlStreamReader reader (m_startingDocumentSnapshot);
1314  while (!reader.atEnd ()) {
1315  reader.readNext ();
1316  if (reader.tokenType() != QXmlStreamReader::StartDocument &&
1317  reader.tokenType() != QXmlStreamReader::EndDocument &&
1318  reader.tokenType() != QXmlStreamReader::Invalid) {
1319  writer.writeCurrentToken (reader);
1320  }
1321  }
1322 
1323  // Operating system
1324  writer.writeStartElement(DOCUMENT_SERIALIZE_OPERATING_SYSTEM);
1325  writer.writeAttribute(DOCUMENT_SERIALIZE_OPERATING_SYSTEM_ENDIAN, EndianToString (QSysInfo::ByteOrder));
1326  writer.writeAttribute(DOCUMENT_SERIALIZE_OPERATING_SYSTEM_WORD_SIZE, QString::number (QSysInfo::WordSize));
1327  writer.writeEndElement();
1328 
1329  // Placeholder for original file, before the commands in the command stack were applied
1330  writer.writeStartElement(DOCUMENT_SERIALIZE_FILE);
1331  writer.writeAttribute(DOCUMENT_SERIALIZE_FILE_IMPORTED,
1332  m_originalFileWasImported ? DOCUMENT_SERIALIZE_BOOL_TRUE : DOCUMENT_SERIALIZE_BOOL_FALSE);
1333  writer.writeEndElement();
1334 
1335  // Commands
1336  m_cmdMediator->saveXml(writer);
1337 
1338  // Error
1339  writer.writeStartElement(DOCUMENT_SERIALIZE_ERROR);
1340  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_CONTEXT, context);
1341  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_FILE, file);
1342  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_LINE, QString::number (line));
1343  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_COMMENT, comment);
1344  writer.writeEndElement();
1345 
1346  writer.writeEndElement();
1347 
1348  // Put string into DOM
1349  QDomDocument domErrorReport ("ErrorReport");
1350  domErrorReport.setContent (xmlErrorReport);
1351 
1352  // Postprocessing
1353  if (!m_originalFileWasImported) {
1354 
1355  // Insert the original file into its placeholder, by manipulating the source and target xml as DOM documents. Very early
1356  // in the loading process, the original file may not be specified yet (m_originalFile is empty)
1357  QDomDocument domInputFile;
1358  loadInputFileForErrorReport (domInputFile);
1359  QDomDocumentFragment fragmentFileFrom = domErrorReport.createDocumentFragment();
1360  if (!domInputFile.isNull()) {
1361  fragmentFileFrom.appendChild (domErrorReport.importNode (domInputFile.documentElement(), DEEP_COPY));
1362  }
1363  QDomNodeList nodesFileTo = domErrorReport.elementsByTagName (DOCUMENT_SERIALIZE_FILE);
1364  if (nodesFileTo.count () > 0) {
1365  QDomNode nodeFileTo = nodesFileTo.at (0);
1366  nodeFileTo.appendChild (fragmentFileFrom);
1367  }
1368 
1369  // Replace DOCUMENT_SERIALIZE_IMAGE by same node with CDATA removed, since:
1370  // 1) it is very big and working with smaller files, especially in emails, is easier
1371  // 2) removing the image better preserves user's privacy
1372  // 3) having the actual image does not help that much when debugging
1373  QDomNodeList nodesDocument = domErrorReport.elementsByTagName (DOCUMENT_SERIALIZE_DOCUMENT);
1374  for (int i = 0 ; i < nodesDocument.count(); i++) {
1375  QDomNode nodeDocument = nodesDocument.at (i);
1376  QDomElement elemImage = nodeDocument.firstChildElement(DOCUMENT_SERIALIZE_IMAGE);
1377  if (!elemImage.isNull()) {
1378 
1379  // Get old image attributes so we can create an empty document with the same size
1380  if (elemImage.hasAttribute (DOCUMENT_SERIALIZE_IMAGE_WIDTH) &&
1381  elemImage.hasAttribute (DOCUMENT_SERIALIZE_IMAGE_HEIGHT)) {
1382 
1383  int width = elemImage.attribute(DOCUMENT_SERIALIZE_IMAGE_WIDTH).toInt();
1384  int height = elemImage.attribute(DOCUMENT_SERIALIZE_IMAGE_HEIGHT).toInt();
1385 
1386  QDomNode nodeReplacement;
1387  QDomElement elemReplacement = nodeReplacement.toElement();
1388  elemReplacement.setAttribute (DOCUMENT_SERIALIZE_IMAGE_WIDTH, width);
1389  elemReplacement.setAttribute (DOCUMENT_SERIALIZE_IMAGE_HEIGHT, height);
1390 
1391  // Replace with the new and then remove the old
1392  nodeDocument.insertBefore (nodeReplacement,
1393  elemImage);
1394  nodeDocument.removeChild(elemImage);
1395  }
1396  }
1397  }
1398  }
1399 
1400  return domErrorReport.toString();
1401 }
1402 
1403 void MainWindow::saveStartingDocumentSnapshot()
1404 {
1405  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::saveStartingDocumentSnapshot";
1406 
1407  QXmlStreamWriter writer (&m_startingDocumentSnapshot);
1408  writer.setAutoFormatting (true);
1409  m_cmdMediator->document().saveXml (writer);
1410 }
1411 
1413 {
1414  ENGAUGE_CHECK_PTR (m_scene);
1415  return *m_scene;
1416 }
1417 
1418 BackgroundImage MainWindow::selectOriginal(BackgroundImage backgroundImage)
1419 {
1420  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::selectBackgroundOriginal";
1421 
1422  BackgroundImage previousBackground = (BackgroundImage) m_cmbBackground->currentData().toInt();
1423 
1424  int index = m_cmbBackground->findData (backgroundImage);
1425  ENGAUGE_ASSERT (index >= 0);
1426 
1427  m_cmbBackground->setCurrentIndex(index);
1428 
1429  return previousBackground;
1430 }
1431 
1433 {
1434  return m_cmbCurve->currentText ();
1435 }
1436 
1437 void MainWindow::setCurrentFile (const QString &fileName)
1438 {
1439  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setCurrentFile";
1440 
1441  QString fileNameStripped;
1442  if (!fileName.isEmpty()) {
1443 
1444  // Strip out path and file extension. We use completeBaseName rather than baseName so
1445  // files with multiple periods are handled correctly - all but last suffix gets kept
1446  QFileInfo fileInfo (fileName);
1447  fileNameStripped = fileInfo.completeBaseName();
1448  }
1449 
1450  m_currentFile = fileNameStripped;
1451  m_currentFileWithPathAndFileExtension = fileName;
1452 
1453  updateWindowTitle ();
1454 }
1455 
1456 void MainWindow::setCurrentPathFromFile (const QString &fileName)
1457 {
1458  QDir dir = QFileInfo (fileName).absoluteDir();
1459 
1460  if (dir.exists ()) {
1461 
1462  bool success = QDir::setCurrent (dir.absolutePath ()); // Return to chosen directory the next time
1463  ENGAUGE_ASSERT (success);
1464 
1465  } else {
1466 
1467  // File was a url so it is irrelevant to the current directory
1468  }
1469 }
1470 
1471 void MainWindow::setNonFillZoomFactor (ZoomFactor newZoomFactor)
1472 {
1473  ENGAUGE_ASSERT (newZoomFactor != ZOOM_FILL);
1474 
1475  // Update controls and apply zoom factor
1476  m_zoomMapToAction [newZoomFactor]->setChecked (true);
1477  slotViewZoomFactor (newZoomFactor);
1478 }
1479 
1480 void MainWindow::setPixmap (const QString &curveSelected,
1481  const QPixmap &pixmap)
1482 {
1483  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setPixmap";
1484 
1485  m_digitizeStateContext->setImageIsLoaded (m_cmdMediator,
1486  true);
1487 
1488  // We cannot reliably use m_cmbCurve->currentText below for the selected curve since that control
1489  // can be pointing to a curve that no longer exists so this method requires curveSelected as an argument
1490  m_backgroundStateContext->setPixmap (m_isGnuplot,
1491  m_transformation,
1492  m_cmdMediator->document().modelGridRemoval(),
1493  m_cmdMediator->document().modelColorFilter(),
1494  pixmap,
1495  curveSelected);
1496 }
1497 
1498 void MainWindow::settingsRead (bool isReset)
1499 {
1500  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
1501 
1502  if (isReset) {
1503  // Delete all settings. Default values are specified, later, for each settings as it is loaded
1504  settings.clear ();
1505  }
1506 
1507  settingsReadEnvironment (settings);
1508  settingsReadMainWindow (settings);
1509 }
1510 
1511 void MainWindow::settingsReadEnvironment (QSettings &settings)
1512 {
1513  settings.beginGroup (SETTINGS_GROUP_ENVIRONMENT);
1514  QDir::setCurrent (settings.value (SETTINGS_CURRENT_DIRECTORY,
1515  QDir::currentPath ()).toString ());
1516  settings.endGroup ();
1517 }
1518 
1519 void MainWindow::settingsReadMainWindow (QSettings &settings)
1520 {
1521  settings.beginGroup(SETTINGS_GROUP_MAIN_WINDOW);
1522 
1523  // Main window geometry
1524  resize (settings.value (SETTINGS_SIZE,
1525  QSize (600, 600)).toSize ());
1526  move (settings.value (SETTINGS_POS,
1527  QPoint (200, 200)).toPoint ());
1528 
1529  // Help window geometry
1530 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
1531  QSize helpSize = settings.value (SETTINGS_HELP_SIZE,
1532  QSize (900, 600)).toSize();
1533  m_helpWindow->resize (helpSize);
1534  if (settings.contains (SETTINGS_HELP_POS)) {
1535  QPoint helpPos = settings.value (SETTINGS_HELP_POS).toPoint();
1536  m_helpWindow->move (helpPos);
1537  }
1538 #endif
1539 
1540  // Checklist guide wizard
1541  m_actionHelpChecklistGuideWizard->setChecked (settings.value (SETTINGS_CHECKLIST_GUIDE_WIZARD,
1542  true).toBool ());
1543 
1544  // Background toolbar visibility
1545  bool viewBackgroundToolBar = settings.value (SETTINGS_VIEW_BACKGROUND_TOOLBAR,
1546  true).toBool ();
1547  m_actionViewBackground->setChecked (viewBackgroundToolBar);
1548  m_toolBackground->setVisible (viewBackgroundToolBar);
1549  BackgroundImage backgroundImage = (BackgroundImage) settings.value (SETTINGS_BACKGROUND_IMAGE,
1550  BACKGROUND_IMAGE_FILTERED).toInt ();
1551  int indexBackground = m_cmbBackground->findData (QVariant (backgroundImage));
1552  m_cmbBackground->setCurrentIndex (indexBackground);
1553 
1554  // Digitize toolbar visibility
1555  bool viewDigitizeToolBar = settings.value (SETTINGS_VIEW_DIGITIZE_TOOLBAR,
1556  true).toBool ();
1557  m_actionViewDigitize->setChecked (viewDigitizeToolBar);
1558  m_toolDigitize->setVisible (viewDigitizeToolBar);
1559 
1560  // Views toolbar visibility
1561  bool viewSettingsViewsToolBar = settings.value (SETTINGS_VIEW_SETTINGS_VIEWS_TOOLBAR,
1562  true).toBool ();
1563  m_actionViewSettingsViews->setChecked (viewSettingsViewsToolBar);
1564  m_toolSettingsViews->setVisible (viewSettingsViewsToolBar);
1565 
1566  // Coordinate system toolbar visibility
1567  bool viewCoordSystemToolbar = settings.value (SETTINGS_VIEW_COORD_SYSTEM_TOOLBAR,
1568  false).toBool ();
1569  m_actionViewCoordSystem->setChecked (viewCoordSystemToolbar);
1570  m_toolCoordSystem->setVisible (viewCoordSystemToolbar);
1571 
1572  // Tooltips visibility
1573  bool viewToolTips = settings.value (SETTINGS_VIEW_TOOL_TIPS,
1574  true).toBool ();
1575  m_actionViewToolTips->setChecked (viewToolTips);
1576  loadToolTips ();
1577 
1578  // Statusbar visibility
1579  StatusBarMode statusBarMode = (StatusBarMode) settings.value (SETTINGS_VIEW_STATUS_BAR,
1580  false).toInt ();
1581  m_statusBar->setStatusBarMode (statusBarMode);
1582  m_actionStatusNever->setChecked (statusBarMode == STATUS_BAR_MODE_NEVER);
1583  m_actionStatusTemporary->setChecked (statusBarMode == STATUS_BAR_MODE_TEMPORARY);
1584  m_actionStatusAlways->setChecked (statusBarMode == STATUS_BAR_MODE_ALWAYS);
1585 
1586  addDockWindow (m_dockChecklistGuide,
1587  settings,
1588  SETTINGS_CHECKLIST_GUIDE_DOCK_AREA,
1589  SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY,
1590  Qt::RightDockWidgetArea);
1591  addDockWindow (m_dockFittingWindow,
1592  settings,
1593  SETTINGS_FITTING_WINDOW_DOCK_AREA,
1594  SETTINGS_FITTING_WINDOW_DOCK_GEOMETRY,
1595  Qt::RightDockWidgetArea);
1596  addDockWindow (m_dockGeometryWindow,
1597  settings,
1598  SETTINGS_GEOMETRY_WINDOW_DOCK_AREA,
1599  SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY,
1600  Qt::RightDockWidgetArea);
1601 
1602  // Main window settings. Preference for initial zoom factor is 100%, rather than fill mode, for issue #25. Some or all
1603  // settings are saved to the application AND saved to m_modelMainWindow for use in DlgSettingsMainWindow. Note that
1604  // TranslatorContainer has previously extracted the locale from the settings
1605  QLocale localeDefault;
1606  QLocale::Language language = (QLocale::Language) settings.value (SETTINGS_LOCALE_LANGUAGE,
1607  QVariant (localeDefault.language())).toInt();
1608  QLocale::Country country = (QLocale::Country) settings.value (SETTINGS_LOCALE_COUNTRY,
1609  QVariant (localeDefault.country())).toInt();
1610  QLocale locale (language,
1611  country);
1612  slotViewZoom ((ZoomFactor) settings.value (SETTINGS_ZOOM_FACTOR,
1613  QVariant (ZOOM_1_TO_1)).toInt());
1614  m_modelMainWindow.setLocale (locale);
1615  m_modelMainWindow.setZoomFactorInitial((ZoomFactorInitial) settings.value (SETTINGS_ZOOM_FACTOR_INITIAL,
1616  QVariant (DEFAULT_ZOOM_FACTOR_INITIAL)).toInt());
1617  m_modelMainWindow.setZoomControl ((ZoomControl) settings.value (SETTINGS_ZOOM_CONTROL,
1618  QVariant (ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)).toInt());
1619  m_modelMainWindow.setMainTitleBarFormat ((MainTitleBarFormat) settings.value (SETTINGS_MAIN_TITLE_BAR_FORMAT,
1620  QVariant (MAIN_TITLE_BAR_FORMAT_PATH)).toInt());
1621  m_modelMainWindow.setPdfResolution (settings.value (SETTINGS_IMPORT_PDF_RESOLUTION,
1622  QVariant (DEFAULT_IMPORT_PDF_RESOLUTION)).toInt ());
1623  m_modelMainWindow.setImportCropping ((ImportCropping) settings.value (SETTINGS_IMPORT_CROPPING,
1624  QVariant (DEFAULT_IMPORT_CROPPING)).toInt ());
1625  m_modelMainWindow.setMaximumGridLines (settings.value (SETTINGS_MAXIMUM_GRID_LINES,
1626  QVariant (DEFAULT_MAXIMUM_GRID_LINES)).toInt ());
1627  m_modelMainWindow.setHighlightOpacity (settings.value (SETTINGS_HIGHLIGHT_OPACITY,
1628  QVariant (DEFAULT_HIGHLIGHT_OPACITY)).toDouble ());
1629  m_modelMainWindow.setSmallDialogs (settings.value (SETTINGS_SMALL_DIALOGS,
1630  QVariant (DEFAULT_SMALL_DIALOGS)).toBool ());
1631  m_modelMainWindow.setDragDropExport (settings.value (SETTINGS_DRAG_DROP_EXPORT,
1632  QVariant (DEFAULT_DRAG_DROP_EXPORT)).toBool ());
1633  m_modelMainWindow.setSignificantDigits (settings.value (SETTINGS_SIGNIFICANT_DIGITS,
1634  QVariant (DEFAULT_SIGNIFICANT_DIGITS)).toInt ());
1635 
1637  updateSmallDialogs();
1638 
1639  settings.endGroup();
1640 }
1641 
1642 void MainWindow::settingsWrite ()
1643 {
1644  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
1645 
1646  settings.beginGroup (SETTINGS_GROUP_ENVIRONMENT);
1647  settings.setValue (SETTINGS_CURRENT_DIRECTORY, QDir::currentPath ());
1648  settings.endGroup ();
1649 
1650  settings.beginGroup (SETTINGS_GROUP_MAIN_WINDOW);
1651  settings.setValue (SETTINGS_SIZE, size ());
1652  settings.setValue (SETTINGS_POS, pos ());
1653 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
1654  settings.setValue (SETTINGS_HELP_SIZE, m_helpWindow->size());
1655  settings.setValue (SETTINGS_HELP_POS, m_helpWindow->pos ());
1656 #endif
1657  if (m_dockChecklistGuide->isFloating()) {
1658 
1659  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, Qt::NoDockWidgetArea);
1660  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY, m_dockChecklistGuide->saveGeometry ());
1661 
1662  } else {
1663 
1664  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, dockWidgetArea (m_dockChecklistGuide));
1665 
1666  }
1667  if (m_dockFittingWindow->isFloating()) {
1668 
1669  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_AREA, Qt::NoDockWidgetArea);
1670  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_GEOMETRY, m_dockFittingWindow->saveGeometry());
1671  } else {
1672 
1673  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_AREA, dockWidgetArea (m_dockFittingWindow));
1674  }
1675  if (m_dockGeometryWindow->isFloating()) {
1676 
1677  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, Qt::NoDockWidgetArea);
1678  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY, m_dockGeometryWindow->saveGeometry ());
1679 
1680  } else {
1681 
1682  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, dockWidgetArea (m_dockGeometryWindow));
1683 
1684  }
1685  settings.setValue (SETTINGS_BACKGROUND_IMAGE, m_cmbBackground->currentData().toInt());
1686  settings.setValue (SETTINGS_CHECKLIST_GUIDE_WIZARD, m_actionHelpChecklistGuideWizard->isChecked ());
1687  settings.setValue (SETTINGS_DRAG_DROP_EXPORT, m_modelMainWindow.dragDropExport ());
1688  settings.setValue (SETTINGS_HIGHLIGHT_OPACITY, m_modelMainWindow.highlightOpacity());
1689  settings.setValue (SETTINGS_IMPORT_CROPPING, m_modelMainWindow.importCropping());
1690  settings.setValue (SETTINGS_IMPORT_PDF_RESOLUTION, m_modelMainWindow.pdfResolution ());
1691  settings.setValue (SETTINGS_LOCALE_LANGUAGE, m_modelMainWindow.locale().language());
1692  settings.setValue (SETTINGS_LOCALE_COUNTRY, m_modelMainWindow.locale().country());
1693  settings.setValue (SETTINGS_MAIN_TITLE_BAR_FORMAT, m_modelMainWindow.mainTitleBarFormat());
1694  settings.setValue (SETTINGS_MAXIMUM_GRID_LINES, m_modelMainWindow.maximumGridLines());
1695  settings.setValue (SETTINGS_SMALL_DIALOGS, m_modelMainWindow.smallDialogs());
1696  settings.setValue (SETTINGS_VIEW_BACKGROUND_TOOLBAR, m_actionViewBackground->isChecked());
1697  settings.setValue (SETTINGS_VIEW_DIGITIZE_TOOLBAR, m_actionViewDigitize->isChecked ());
1698  settings.setValue (SETTINGS_VIEW_STATUS_BAR, m_statusBar->statusBarMode ());
1699  settings.setValue (SETTINGS_VIEW_SETTINGS_VIEWS_TOOLBAR, m_actionViewSettingsViews->isChecked ());
1700  settings.setValue (SETTINGS_VIEW_COORD_SYSTEM_TOOLBAR, m_actionViewCoordSystem->isChecked ());
1701  settings.setValue (SETTINGS_VIEW_TOOL_TIPS, m_actionViewToolTips->isChecked ());
1702  settings.setValue (SETTINGS_ZOOM_CONTROL, m_modelMainWindow.zoomControl());
1703  settings.setValue (SETTINGS_ZOOM_FACTOR, currentZoomFactor ());
1704  settings.setValue (SETTINGS_ZOOM_FACTOR_INITIAL, m_modelMainWindow.zoomFactorInitial());
1705  settings.endGroup ();
1706 }
1707 
1708 bool MainWindow::setupAfterLoadNewDocument (const QString &fileName,
1709  const QString &temporaryMessage ,
1710  ImportType importType)
1711 {
1712  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setupAfterLoadNewDocument"
1713  << " file=" << fileName.toLatin1().data()
1714  << " message=" << temporaryMessage.toLatin1().data()
1715  << " importType=" << importType;
1716 
1717  // The steps in this method should theoretically be a superset of the steps in setupAfterLoadNewDocument. Therefore, any
1718  // changes to this method should be considered for application to the other method also
1719 
1720  const QString EMPTY_CURVE_NAME_TO_SKIP_BACKGROUND_PROCESSING; // For bootstrapping the preview
1721 
1722  // At this point the code assumes CmdMediator for the NEW Document is already stored in m_cmdMediator
1723 
1724  m_digitizeStateContext->resetOnLoad (m_cmdMediator); // Before setPixmap
1725  m_backgroundStateContext->setCurveSelected (m_isGnuplot,
1726  m_transformation,
1727  m_cmdMediator->document().modelGridRemoval(),
1728  m_cmdMediator->document().modelColorFilter(),
1729  EMPTY_CURVE_NAME_TO_SKIP_BACKGROUND_PROCESSING); // Before setPixmap
1730  setPixmap (m_cmdMediator->document().curvesGraphsNames().first(),
1731  m_cmdMediator->pixmap ()); // Set background immediately so it is visible as a preview when any dialogs are displayed
1732 
1733  // Image is visible now so the user can refer to it when we ask for the number of coordinate systems. Note that the Document
1734  // may already have multiple CoordSystem if user loaded a file that had multiple CoordSystem entries
1735  if (importType == IMPORT_TYPE_ADVANCED) {
1736 
1737  applyZoomFactorAfterLoad(); // Apply the currently selected zoom factor
1738 
1739  DlgImportAdvanced dlgImportAdvanced (*this);
1740  dlgImportAdvanced.exec();
1741 
1742  if (dlgImportAdvanced.result() == QDialog::Rejected) {
1743  return false;
1744  }
1745 
1746  int numberCoordSystem = dlgImportAdvanced.numberCoordSystem();
1747  m_cmdMediator->document().addCoordSystems (numberCoordSystem - 1);
1748  m_cmdMediator->setDocumentAxesPointsRequired (dlgImportAdvanced.documentAxesPointsRequired());
1749  }
1750 
1751  m_transformation.resetOnLoad();
1752  m_transformationStateContext->resetOnLoad();
1753  m_scene->resetOnLoad();
1754 
1755  connect (m_actionEditUndo, SIGNAL (triggered ()), m_cmdMediator, SLOT (undo ()));
1756  connect (m_actionEditUndo, SIGNAL (triggered ()), m_cmdStackShadow, SLOT (slotUndo ()));
1757  connect (m_actionEditRedo, SIGNAL (triggered ()), m_cmdMediator, SLOT (redo ())); // No effect until CmdMediator::undo and CmdStackShadow::slotUndo get called
1758  connect (m_actionEditRedo, SIGNAL (triggered ()), m_cmdStackShadow, SLOT (slotRedo ())); // No effect after CmdMediator::undo and CmdStackShadow::slotUndo get called
1759  connect (m_cmdMediator, SIGNAL (canRedoChanged(bool)), this, SLOT (slotCanRedoChanged (bool)));
1760  connect (m_cmdMediator, SIGNAL (canUndoChanged(bool)), this, SLOT (slotCanUndoChanged (bool)));
1761  connect (m_cmdMediator, SIGNAL (redoTextChanged (const QString &)), this, SLOT (slotRedoTextChanged (const QString &)));
1762  connect (m_cmdMediator, SIGNAL (undoTextChanged (const QString &)), this, SLOT (slotUndoTextChanged (const QString &)));
1763  loadCurveListFromCmdMediator ();
1764  loadCoordSystemListFromCmdMediator ();
1766 
1767  m_isDocumentExported = false;
1768 
1769  // Background must be set (by setPixmap) before slotViewZoomFactor which relies on the background. At this point
1770  // the transformation is undefined (unless the code is changed) so grid removal will not work
1771  // but updateTransformationAndItsDependencies will call this again to fix that issue. Note that the selected
1772  // curve name was set (by setCurveSelected) earlier before the call to setPixmap
1773  m_backgroundStateContext->setCurveSelected (m_isGnuplot,
1774  m_transformation,
1775  m_cmdMediator->document().modelGridRemoval(),
1776  m_cmdMediator->document().modelColorFilter(),
1777  m_cmbCurve->currentText ());
1778  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) m_cmbBackground->currentIndex ());
1779 
1780  applyZoomFactorAfterLoad(); // Zoom factor must be reapplied after background image is set, to have any effect
1781 
1782  setCurrentFile(fileName);
1783  m_statusBar->showTemporaryMessage (temporaryMessage);
1784  m_statusBar->wakeUp ();
1785 
1786  saveStartingDocumentSnapshot();
1787 
1788  updateAfterCommand(); // Replace stale points by points in new Document
1789 
1790  return true;
1791 }
1792 
1793 bool MainWindow::setupAfterLoadReplacingImage (const QString &fileName,
1794  const QString &temporaryMessage ,
1795  ImportType importType)
1796 {
1797  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setupAfterLoadReplacingImage"
1798  << " file=" << fileName.toLatin1().data()
1799  << " message=" << temporaryMessage.toLatin1().data()
1800  << " importType=" << importType;
1801 
1802  // The steps in this method should theoretically be just a subset of the steps in setupAfterLoadNewDocument
1803 
1804  // After this point there should be no commands in CmdMediator, since we effectively have a new document
1805  m_cmdMediator->clear();
1806 
1807  setPixmap (m_cmdMediator->document().curvesGraphsNames().first(),
1808  m_cmdMediator->pixmap ()); // Set background immediately so it is visible as a preview when any dialogs are displayed
1809 
1810  m_isDocumentExported = false;
1811 
1812  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) m_cmbBackground->currentIndex ());
1813 
1814  applyZoomFactorAfterLoad(); // Zoom factor must be reapplied after background image is set, to have any effect
1815 
1816  setCurrentFile(fileName);
1817  m_statusBar->showTemporaryMessage (temporaryMessage);
1818  m_statusBar->wakeUp ();
1819 
1820  saveStartingDocumentSnapshot();
1821 
1822  updateAfterCommand(); // Replace stale points by points in new Document
1823 
1824  return true;
1825 }
1826 
1827 void MainWindow::showEvent (QShowEvent *event)
1828 {
1829  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::showEvent"
1830  << " files=" << m_loadStartupFiles.join (",").toLatin1().data();
1831 
1832  QMainWindow::showEvent (event);
1833 
1834  if (m_loadStartupFiles.count() > 0) {
1835 
1836  m_timerLoadStartupFiles = new QTimer;
1837  m_timerLoadStartupFiles->setSingleShot (true);
1838  connect (m_timerLoadStartupFiles, SIGNAL (timeout ()), this, SLOT (slotLoadStartupFiles ()));
1839  m_timerLoadStartupFiles->start (0); // Zero delay still waits until execution finishes and gui is available
1840 
1841  }
1842 }
1843 
1844 void MainWindow::showTemporaryMessage (const QString &temporaryMessage)
1845 {
1846  m_statusBar->showTemporaryMessage (temporaryMessage);
1847 }
1848 
1849 void MainWindow::slotBtnPrintAll ()
1850 {
1851  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnPrintAll";
1852 
1853  ghostsCreate ();
1854 
1855  QPrinter printer (QPrinter::HighResolution);
1856  QPrintDialog dlg (&printer, this);
1857  if (dlg.exec() == QDialog::Accepted) {
1858  QPainter painter (&printer);
1859  m_view->render (&painter);
1860  painter.end();
1861  }
1862 
1863  ghostsDestroy ();
1864 }
1865 
1866 void MainWindow::slotBtnShowAllPressed ()
1867 {
1868  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnShowAllPressed";
1869 
1870  // Start of press-release sequence
1871  ghostsCreate ();
1872 }
1873 
1874 void MainWindow::slotBtnShowAllReleased ()
1875 {
1876  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnShowAllReleased";
1877 
1878  // End of press-release sequence
1879  ghostsDestroy ();
1880 }
1881 
1882 void MainWindow::slotCanRedoChanged (bool canRedo)
1883 {
1884  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotCanRedoChanged";
1885 
1886  m_actionEditRedo->setEnabled (canRedo || m_cmdStackShadow->canRedo());
1887 }
1888 
1889 void MainWindow::slotCanUndoChanged (bool canUndo)
1890 {
1891  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotCanUndoChanged";
1892 
1893  m_actionEditUndo->setEnabled (canUndo);
1894 }
1895 
1896 void MainWindow::slotChecklistClosed()
1897 {
1898  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotChecklistClosed";
1899 
1900  m_actionViewChecklistGuide->setChecked (false);
1901 }
1902 
1903 void MainWindow::slotCleanChanged(bool clean)
1904 {
1905  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCleanChanged";
1906 
1907  setWindowModified (!clean);
1908 }
1909 
1910 void MainWindow::slotCmbBackground(int currentIndex)
1911 {
1912  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbBackground";
1913 
1914  switch (currentIndex) {
1915  case BACKGROUND_IMAGE_NONE:
1916  if (!m_actionViewBackgroundNone->isChecked()) {
1917  m_actionViewBackgroundNone->toggle();
1918  }
1919  break;
1920 
1921  case BACKGROUND_IMAGE_ORIGINAL:
1922  if (!m_actionViewBackgroundOriginal->isChecked ()) {
1923  m_actionViewBackgroundOriginal->toggle();
1924  }
1925  break;
1926 
1927  case BACKGROUND_IMAGE_FILTERED:
1928  if (!m_actionViewBackgroundFiltered->isChecked ()) {
1929  m_actionViewBackgroundFiltered->toggle();
1930  }
1931  break;
1932  }
1933 
1934  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) currentIndex);
1935 }
1936 
1937 void MainWindow::slotCmbCoordSystem(int index)
1938 {
1939  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbCoordSystem";
1940 
1941  CmdSelectCoordSystem *cmd = new CmdSelectCoordSystem (*this,
1942  m_cmdMediator->document(),
1943  index);
1944 
1945  m_cmdMediator->push (cmd);
1946 }
1947 
1948 void MainWindow::slotCmbCurve(int /* index */)
1949 {
1950  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbCurve";
1951 
1952  m_backgroundStateContext->setCurveSelected (m_isGnuplot,
1953  m_transformation,
1954  m_cmdMediator->document().modelGridRemoval(),
1955  m_cmdMediator->document().modelColorFilter(),
1956  m_cmbCurve->currentText ());
1957  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
1958  m_cmdMediator->setSelectedCurveName (m_cmbCurve->currentText ()); // Save for next time current coordinate system returns
1959 
1960  updateViewedCurves();
1962  updateFittingWindow();
1963  updateGeometryWindow();
1964 }
1965 
1966 void MainWindow::slotContextMenuEventAxis (QString pointIdentifier)
1967 {
1968  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventAxis point=" << pointIdentifier.toLatin1 ().data ();
1969 
1970  m_digitizeStateContext->handleContextMenuEventAxis (m_cmdMediator,
1971  pointIdentifier);
1972 }
1973 
1974 void MainWindow::slotContextMenuEventGraph (QStringList pointIdentifiers)
1975 {
1976  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventGraph point=" << pointIdentifiers.join(",").toLatin1 ().data ();
1977 
1978  m_digitizeStateContext->handleContextMenuEventGraph (m_cmdMediator,
1979  pointIdentifiers);
1980 }
1981 
1982 void MainWindow::slotDigitizeAxis ()
1983 {
1984  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeAxis";
1985 
1986  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
1987  DIGITIZE_STATE_AXIS);
1988  m_cmbCurve->setEnabled (false); // Graph curve is irrelevant in this mode
1989  m_viewPointStyle->setEnabled (true); // Point style is important in this mode
1990  m_viewSegmentFilter->setEnabled (true); // Filtering is important in this mode
1991  updateControls (); // For Paste which is state dependent
1992 }
1993 
1994 void MainWindow::slotDigitizeColorPicker ()
1995 {
1996  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeColorPicker";
1997 
1998  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
1999  DIGITIZE_STATE_COLOR_PICKER);
2000  m_cmbCurve->setEnabled (true);
2001  m_viewPointStyle->setEnabled (true);
2002  m_viewSegmentFilter->setEnabled (true);
2003  updateControls (); // For Paste which is state dependent
2004 }
2005 
2006 void MainWindow::slotDigitizeCurve ()
2007 {
2008  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeCurve";
2009 
2010  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2011  DIGITIZE_STATE_CURVE);
2012  m_cmbCurve->setEnabled (true);
2013  m_viewPointStyle->setEnabled (true);
2014  m_viewSegmentFilter->setEnabled (true);
2015  updateControls (); // For Paste which is state dependent
2016 }
2017 
2018 void MainWindow::slotDigitizePointMatch ()
2019 {
2020  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizePointMatch";
2021 
2022  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2023  DIGITIZE_STATE_POINT_MATCH);
2024  m_cmbCurve->setEnabled (true);
2025  m_viewPointStyle->setEnabled (true);
2026  m_viewSegmentFilter->setEnabled (true);
2027  updateControls (); // For Paste which is state dependent
2028 }
2029 
2030 void MainWindow::slotDigitizeScale ()
2031 {
2032  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeScale";
2033 
2034  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2035  DIGITIZE_STATE_SCALE);
2036  m_cmbCurve->setEnabled (false);
2037  m_viewPointStyle->setEnabled (false);
2038  m_viewSegmentFilter->setEnabled (false);
2039  updateControls (); // For Paste which is state dependent
2040 }
2041 
2042 void MainWindow::slotDigitizeSegment ()
2043 {
2044  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeSegment";
2045 
2046  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2047  DIGITIZE_STATE_SEGMENT);
2048  m_cmbCurve->setEnabled (true);
2049  m_viewPointStyle->setEnabled (true);
2050  m_viewSegmentFilter->setEnabled (true);
2051  updateControls (); // For Paste which is state dependent
2052 }
2053 
2054 void MainWindow::slotDigitizeSelect ()
2055 {
2056  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeSelect";
2057 
2058  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2059  DIGITIZE_STATE_SELECT);
2060  m_cmbCurve->setEnabled (false);
2061  m_viewPointStyle->setEnabled (false);
2062  m_viewSegmentFilter->setEnabled (false);
2063  updateControls (); // For Paste which is state dependent
2064 }
2065 
2066 void MainWindow::slotEditCopy ()
2067 {
2068  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCopy";
2069 
2070  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
2071  bool tableFittingIsActive, tableFittingIsCopyable;
2072  bool tableGeometryIsActive, tableGeometryIsCopyable;
2073  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
2074  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
2075 
2076  if (tableFittingIsActive) {
2077 
2078  // Send to FittingWindow
2079  m_dockFittingWindow->doCopy ();
2080 
2081  } else if (tableGeometryIsActive) {
2082 
2083  // Send to GeometryWindow
2084  m_dockGeometryWindow->doCopy ();
2085 
2086  } else {
2087 
2088  // Process curve points in main window
2089  GraphicsItemsExtractor graphicsItemsExtractor;
2090  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
2091  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
2092 
2093  CmdCopy *cmd = new CmdCopy (*this,
2094  m_cmdMediator->document(),
2095  pointIdentifiers);
2096  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
2097  cmd);
2098  }
2099 }
2100 
2101 void MainWindow::slotEditCut ()
2102 {
2103  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCut";
2104 
2105  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
2106  bool tableFittingIsActive, tableFittingIsCopyable;
2107  bool tableGeometryIsActive, tableGeometryIsCopyable;
2108  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
2109  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
2110 
2111  if (tableFittingIsActive || tableGeometryIsActive) {
2112 
2113  // Cannot delete from fitting or geometry windows
2114 
2115  } else {
2116 
2117  // Process curve points in main window
2118  GraphicsItemsExtractor graphicsItemsExtractor;
2119  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
2120  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
2121 
2122  CmdCut *cmd = new CmdCut (*this,
2123  m_cmdMediator->document(),
2124  pointIdentifiers);
2125  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
2126  cmd);
2127  }
2128 }
2129 
2130 void MainWindow::slotEditDelete ()
2131 {
2132  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditDelete";
2133 
2134  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
2135  bool tableFittingIsActive, tableFittingIsCopyable;
2136  bool tableGeometryIsActive, tableGeometryIsCopyable;
2137  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
2138  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
2139 
2140  if (tableFittingIsActive || tableGeometryIsActive) {
2141 
2142  // Cannot delete from fitting or geometry windows
2143 
2144  } else {
2145 
2146  // If this is a map, which has a scale bar with two axis points, then selection of just one axis point
2147  // for deletion should result in deletion of the other point also so this object will enforce that. Otherwise
2148  // this class has no effect below
2149  ScaleBarAxisPointsUnite scaleBarAxisPoints;
2150 
2151  // Process curve points in main window
2152  GraphicsItemsExtractor graphicsItemsExtractor;
2153  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
2154  QStringList pointIdentifiers = scaleBarAxisPoints.unite (m_cmdMediator,
2155  graphicsItemsExtractor.selectedPointIdentifiers (items));
2156 
2157  CmdDelete *cmd = new CmdDelete (*this,
2158  m_cmdMediator->document(),
2159  pointIdentifiers);
2160  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
2161  cmd);
2162  }
2163 }
2164 
2165 void MainWindow::slotEditMenu ()
2166 {
2167  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditMenu";
2168 
2169  m_actionEditPasteAsNew->setEnabled (!QApplication::clipboard()->image().isNull());
2170  m_actionEditPasteAsNewAdvanced->setEnabled (!QApplication::clipboard()->image().isNull());
2171 }
2172 
2173 void MainWindow::slotEditPaste ()
2174 {
2175  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPaste";
2176 
2177  QList<QPoint> points;
2178  QList<double> ordinals;
2179 
2180  MimePointsImport mimePointsImport;
2181  mimePointsImport.retrievePoints (m_transformation,
2182  points,
2183  ordinals);
2184 
2185  CmdAddPointsGraph *cmd = new CmdAddPointsGraph (*this,
2186  m_cmdMediator->document(),
2187  m_cmbCurve->currentText (),
2188  points,
2189  ordinals);
2190  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
2191  cmd);
2192 }
2193 
2194 void MainWindow::slotEditPasteAsNew ()
2195 {
2196  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPasteAsNew";
2197 
2198  filePaste (IMPORT_TYPE_SIMPLE);
2199 }
2200 
2201 void MainWindow::slotEditPasteAsNewAdvanced ()
2202 {
2203  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPasteAsNewAdvanced";
2204 
2205  filePaste (IMPORT_TYPE_ADVANCED);
2206 }
2207 
2208 void MainWindow::slotFileClose()
2209 {
2210  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileClose";
2211 
2212  if (maybeSave ()) {
2213 
2214  // Transition from defined to undefined. This must be after the clearing of the screen
2215  // since the axes checker screen item (and maybe others) must still exist
2216  m_transformationStateContext->triggerStateTransition(m_isGnuplot,
2217  TRANSFORMATION_STATE_UNDEFINED,
2218  *m_cmdMediator,
2219  m_transformation,
2220  selectedGraphCurve());
2221 
2222  // Transition to empty state so an inadvertent mouse press does not trigger, for example,
2223  // the creation of an axis point on a non-existent GraphicsScene (=crash)
2224  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
2225  DIGITIZE_STATE_EMPTY);
2226 
2227  // Deallocate fitted curve
2228  if (m_fittingCurve != 0) {
2229  m_scene->removeItem (m_fittingCurve);
2230  m_fittingCurve = 0;
2231  }
2232 
2233  // Remove screen objects
2234  m_scene->resetOnLoad ();
2235 
2236  // Remove background
2237  m_backgroundStateContext->close ();
2238 
2239  // Remove scroll bars if they exist
2240  m_scene->setSceneRect (QRectF (0, 0, 1, 1));
2241 
2242  // Remove stale data from fitting window
2243  m_dockFittingWindow->clear ();
2244 
2245  // Remove stale data from geometry window
2246  m_dockGeometryWindow->clear ();
2247 
2248  // Deallocate Document
2249  delete m_cmdMediator;
2250 
2251  // Remove file information
2252  m_cmdMediator = 0;
2253  m_currentFile = "";
2254  m_engaugeFile = "";
2255  setWindowTitle (engaugeWindowTitle ());
2256 
2257  m_gridLines.clear();
2258  updateControls();
2259  }
2260 }
2261 
2262 void MainWindow::slotFileExport ()
2263 {
2264  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileExport";
2265 
2266  if (m_transformation.transformIsDefined()) {
2267 
2268  MainDirectoryPersist directoryPersist;
2269  ExportToFile exportStrategy;
2270 
2271  QString fileName;
2272  if (m_isExportOnly) {
2273  fileName = fileNameForExportOnly ();
2274  } else {
2275 
2276  QString filter = QString ("%1;;%2;;All files (*.*)")
2277  .arg (exportStrategy.filterCsv ())
2278  .arg (exportStrategy.filterTsv ());
2279 
2280  // OSX sandbox requires, for the default, a non-empty filename
2281  QString defaultFileName = QString ("%1/%2.%3")
2282  .arg (directoryPersist.getDirectoryExportSave().path ())
2283  .arg (m_currentFile)
2284  .arg (exportStrategy.fileExtensionCsv ());
2285  QFileDialog dlg;
2286  QString filterCsv = exportStrategy.filterCsv ();
2287 
2288  fileName = dlg.getSaveFileName (this,
2289  tr("Export"),
2290  defaultFileName,
2291  filter,
2292  &filterCsv);
2293  }
2294 
2295  if (!fileName.isEmpty ()) {
2296 
2297  directoryPersist.setDirectoryExportSaveFromFilename(fileName);
2298  fileExport(fileName,
2299  exportStrategy);
2300  }
2301  } else {
2302  DlgRequiresTransform dlg ("Export");
2303  dlg.exec ();
2304  }
2305 }
2306 
2307 void MainWindow::slotFileImport ()
2308 {
2309  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImport";
2310 
2311  fileImportWithPrompts (IMPORT_TYPE_SIMPLE);
2312 }
2313 
2314 void MainWindow::slotFileImportAdvanced ()
2315 {
2316  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportAdvanced";
2317 
2318  fileImportWithPrompts (IMPORT_TYPE_ADVANCED);
2319 }
2320 
2321 void MainWindow::slotFileImportDraggedImage(QImage image)
2322 {
2323  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportDraggedImage";
2324 
2325  // No need to check return value from loadImage since there are no prompts that give the user a chance to cancel
2326  loadImage ("",
2327  image,
2328  IMPORT_TYPE_SIMPLE);
2329 }
2330 
2331 void MainWindow::slotFileImportDraggedImageUrl(QUrl url)
2332 {
2333  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportDraggedImageUrl url=" << url.toString ().toLatin1 ().data ();
2334 
2335 #ifdef NETWORKING
2336  m_loadImageFromUrl->startLoadImage (url);
2337 #endif
2338 }
2339 
2340 void MainWindow::slotFileImportImage(QString fileName, QImage image)
2341 {
2342  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportImage fileName=" << fileName.toLatin1 ().data ();
2343 
2344  // No need to check return value from loadImage since there are no prompts that give the user a chance to cancel
2345  loadImage (fileName,
2346  image,
2347  IMPORT_TYPE_SIMPLE);
2348 }
2349 
2350 void MainWindow::slotFileImportImageReplace ()
2351 {
2352  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportImageReplace";
2353 
2354  fileImportWithPrompts (IMPORT_TYPE_IMAGE_REPLACE);
2355 }
2356 
2357 void MainWindow::slotFileOpen()
2358 {
2359  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileOpen";
2360 
2361  if (maybeSave ()) {
2362 
2363  // Allow selection of files with strange suffixes in case the file extension was changed. Since
2364  // the default is the first filter, the wildcard filter is added afterwards (it is the off-nominal case)
2365  QString filter = QString ("%1 (*.%2);; All Files (*.*)")
2366  .arg (ENGAUGE_FILENAME_DESCRIPTION)
2367  .arg (ENGAUGE_FILENAME_EXTENSION);
2368 
2369  MainDirectoryPersist directoryPersist;
2370  QString fileName = QFileDialog::getOpenFileName (this,
2371  tr("Open Document"),
2372  directoryPersist.getDirectoryImportOpen ().path (),
2373  filter);
2374  if (!fileName.isEmpty ()) {
2375 
2376  directoryPersist.setDirectoryImportOpenFromFilename (fileName);
2377  loadDocumentFile (fileName);
2378 
2379  }
2380  }
2381 }
2382 
2383 void MainWindow::slotFileOpenDraggedDigFile (QString fileName)
2384 {
2385  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileOpenDraggedDigFile";
2386 
2387  loadDocumentFile (fileName);
2388 }
2389 
2390 void MainWindow::slotFilePrint()
2391 {
2392  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFilePrint";
2393 
2394  QPrinter printer (QPrinter::HighResolution);
2395  QPrintDialog dlg (&printer, this);
2396  if (dlg.exec() == QDialog::Accepted) {
2397  QPainter painter (&printer);
2398  m_view->render (&painter);
2399  painter.end();
2400  }
2401 }
2402 
2403 bool MainWindow::slotFileSave()
2404 {
2405  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileSave";
2406 
2407  if (m_engaugeFile.isEmpty()) {
2408  return slotFileSaveAs();
2409  } else {
2410  return saveDocumentFile (m_engaugeFile);
2411  }
2412 }
2413 
2414 bool MainWindow::slotFileSaveAs()
2415 {
2416  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileSaveAs";
2417 
2418  // Append engauge file extension if it is not already there
2419  QString filenameDefault = m_currentFile;
2420  if (!m_currentFile.endsWith (ENGAUGE_FILENAME_EXTENSION)) {
2421  filenameDefault = QString ("%1.%2")
2422  .arg (m_currentFile)
2423  .arg (ENGAUGE_FILENAME_EXTENSION);
2424  }
2425 
2426  if (!m_engaugeFile.isEmpty()) {
2427  filenameDefault = m_engaugeFile;
2428  }
2429 
2430  QString filterDigitizer = QString ("%1 (*.%2)")
2431  .arg (ENGAUGE_FILENAME_DESCRIPTION)
2432  .arg (ENGAUGE_FILENAME_EXTENSION);
2433  QString filterAll ("All files (*. *)");
2434 
2435  QStringList filters;
2436  filters << filterDigitizer;
2437  filters << filterAll;
2438 
2439  MainDirectoryPersist directoryPersist;
2440 
2441  QFileDialog dlg(this);
2442  dlg.setFileMode (QFileDialog::AnyFile);
2443  dlg.selectNameFilter (filterDigitizer);
2444  dlg.setNameFilters (filters);
2445 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
2446  // Prevent hang in OSX
2447  dlg.setWindowModality(Qt::WindowModal);
2448 #endif
2449  dlg.setAcceptMode(QFileDialog::AcceptSave);
2450  dlg.selectFile(filenameDefault);
2451  dlg.setDirectory (directoryPersist.getDirectoryExportSave ());
2452  if (dlg.exec()) {
2453 
2454  QStringList files = dlg.selectedFiles();
2455  directoryPersist.setDirectoryExportSaveFromFilename (files.at(0));
2456  return saveDocumentFile(files.at(0));
2457  }
2458 
2459  return false;
2460 }
2461 
2462 void MainWindow::slotFittingWindowClosed()
2463 {
2464  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFittingWindowClosed";
2465 
2466  m_actionViewFittingWindow->setChecked (false);
2467 }
2468 
2469 void MainWindow::slotFittingWindowCurveFit(FittingCurveCoefficients fittingCurveCoef,
2470  double xMin,
2471  double xMax,
2472  bool isLogXTheta,
2473  bool isLogYRadius)
2474 {
2475  // Do not output elements in fittingCurveCoef here since that list may be empty
2476  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFittingWindowCurveFit"
2477  << " order=" << fittingCurveCoef.size() - 1;
2478 
2479  if (m_fittingCurve != 0) {
2480  m_scene->removeItem (m_fittingCurve);
2481  delete m_fittingCurve;
2482  }
2483 
2484  m_fittingCurve = new FittingCurve (fittingCurveCoef,
2485  xMin,
2486  xMax,
2487  isLogXTheta,
2488  isLogYRadius,
2489  m_transformation);
2490  m_fittingCurve->setVisible (m_actionViewFittingWindow->isChecked ());
2491  m_scene->addItem (m_fittingCurve);
2492 }
2493 
2494 void MainWindow::slotGeometryWindowClosed()
2495 {
2496  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotGeometryWindowClosed";
2497 
2498  m_actionViewGeometryWindow->setChecked (false);
2499 }
2500 
2501 void MainWindow::slotHelpAbout()
2502 {
2503  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpAbout";
2504 
2505  DlgAbout dlg (*this);
2506  dlg.exec ();
2507 }
2508 
2509 void MainWindow::slotHelpTutorial()
2510 {
2511  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpTutorial";
2512 
2513  m_tutorialDlg->show ();
2514  m_tutorialDlg->exec ();
2515 }
2516 
2517 void MainWindow::slotKeyPress (Qt::Key key,
2518  bool atLeastOneSelectedItem)
2519 {
2520  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotKeyPress"
2521  << " key=" << QKeySequence (key).toString().toLatin1 ().data ()
2522  << " atLeastOneSelectedItem=" << (atLeastOneSelectedItem ? "true" : "false");
2523 
2524  m_digitizeStateContext->handleKeyPress (m_cmdMediator,
2525  key,
2526  atLeastOneSelectedItem);
2527 }
2528 
2529 void MainWindow::slotLoadStartupFiles ()
2530 {
2531  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotLoadStartupFiles";
2532 
2533  ENGAUGE_ASSERT (m_loadStartupFiles.count() > 0);
2534 
2535  QString fileName = m_loadStartupFiles.front(); // Get next file name
2536  m_loadStartupFiles.pop_front(); // Remove next file name
2537 
2538  // Load next file into this instance of Engauge
2539  LoadFileInfo loadFileInfo;
2540  if (loadFileInfo.loadsAsDigFile(fileName)) {
2541 
2542  loadDocumentFile (fileName);
2543 
2544  } else {
2545 
2546  fileImport (fileName,
2547  IMPORT_TYPE_SIMPLE);
2548 
2549  }
2550 
2551  if (m_loadStartupFiles.count() > 0) {
2552 
2553  // Fork off another instance of this application to handle the remaining files recursively. New process
2554  // is detached so killing/terminating this process does not automatically kill the child process(es) also
2555  QProcess::startDetached (QCoreApplication::applicationFilePath(),
2556  m_commandLineWithoutLoadStartupFiles + m_loadStartupFiles);
2557  }
2558 }
2559 
2560 void MainWindow::slotMouseMove (QPointF pos)
2561 {
2562 // LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotMouseMove pos=" << QPointFToString (pos).toLatin1 ().data ();
2563 
2564  // Ignore mouse moves before Document is loaded
2565  if (m_cmdMediator != 0) {
2566 
2567  // Get status bar coordinates
2568  QString coordsScreen, coordsGraph, resolutionGraph;
2569  m_transformation.coordTextForStatusBar (pos,
2570  coordsScreen,
2571  coordsGraph,
2572  resolutionGraph,
2573  modeMap ());
2574 
2575  // Update status bar coordinates
2576  m_statusBar->setCoordinates (coordsScreen,
2577  coordsGraph,
2578  resolutionGraph);
2579 
2580  // There used to be a call to updateGraphicsLinesToMatchGraphicsPoints here, but that resulted
2581  // in hundreds of gratuitous log messages as the cursor was moved around, and nothing important happened
2582 
2583  m_digitizeStateContext->handleMouseMove (m_cmdMediator,
2584  pos);
2585  }
2586 }
2587 
2588 void MainWindow::slotMousePress (QPointF pos)
2589 {
2590  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMousePress";
2591 
2592  m_scene->resetPositionHasChangedFlags();
2593 
2594  m_digitizeStateContext->handleMousePress (m_cmdMediator,
2595  pos);
2596 }
2597 
2598 void MainWindow::slotMouseRelease (QPointF pos)
2599 {
2600  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMouseRelease";
2601 
2602  if (pos.x() < 0 || pos.y() < 0) {
2603 
2604  // Cursor is outside the image so drop this event. However, call updateControls since this may be
2605  // a click-and-drag to select in which case the controls (especially Copy and Cut) reflect the new selection
2606  updateControls ();
2607 
2608  } else {
2609 
2610  // Cursor is within the image so process this as a normal mouse release
2611  m_digitizeStateContext->handleMouseRelease (m_cmdMediator,
2612  pos);
2613  }
2614 }
2615 
2616 void MainWindow::slotRecentFileAction ()
2617 {
2618  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileAction";
2619 
2620  QAction *action = qobject_cast<QAction*>(sender ());
2621 
2622  if (action) {
2623  QString fileName = action->data().toString();
2624  loadDocumentFile (fileName);
2625  }
2626 }
2627 
2628 void MainWindow::slotRecentFileClear ()
2629 {
2630  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileClear";
2631 
2632  QStringList emptyList;
2633 
2634  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
2635  settings.setValue (SETTINGS_RECENT_FILE_LIST,
2636  emptyList);
2637 
2638  updateRecentFileList();
2639 }
2640 
2641 void MainWindow::slotRedoTextChanged (const QString &text)
2642 {
2643  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotRedoTextChanged";
2644 
2645  QString completeText ("Redo");
2646  if (!text.isEmpty ()) {
2647  completeText += QString (" \"%1\"").arg (text);
2648  }
2649  m_actionEditRedo->setText (completeText);
2650 }
2651 
2652 void MainWindow::slotSettingsAxesChecker ()
2653 {
2654  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsAxesChecker";
2655 
2656  m_dlgSettingsAxesChecker->load (*m_cmdMediator);
2657  m_dlgSettingsAxesChecker->show ();
2658 }
2659 
2660 void MainWindow::slotSettingsColorFilter ()
2661 {
2662  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsColorFilter";
2663 
2664  m_dlgSettingsColorFilter->load (*m_cmdMediator);
2665  m_dlgSettingsColorFilter->show ();
2666 }
2667 
2668 void MainWindow::slotSettingsCoords ()
2669 {
2670  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCoords";
2671 
2672  m_dlgSettingsCoords->load (*m_cmdMediator);
2673  m_dlgSettingsCoords->show ();
2674 }
2675 
2676 void MainWindow::slotSettingsCurveList ()
2677 {
2678  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveList";
2679 
2680  m_dlgSettingsCurveList->load (*m_cmdMediator);
2681  m_dlgSettingsCurveList->show ();
2682 }
2683 
2684 void MainWindow::slotSettingsCurveProperties ()
2685 {
2686  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveProperties";
2687 
2688  m_dlgSettingsCurveProperties->load (*m_cmdMediator);
2689  m_dlgSettingsCurveProperties->setCurveName (selectedGraphCurve ());
2690  m_dlgSettingsCurveProperties->show ();
2691 }
2692 
2693 void MainWindow::slotSettingsDigitizeCurve ()
2694 {
2695  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsDigitizeCurve";
2696 
2697  m_dlgSettingsDigitizeCurve->load (*m_cmdMediator);
2698  m_dlgSettingsDigitizeCurve->show ();
2699 }
2700 
2701 void MainWindow::slotSettingsExportFormat ()
2702 {
2703  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsExportFormat";
2704 
2705  if (transformIsDefined()) {
2706  m_dlgSettingsExportFormat->load (*m_cmdMediator);
2707  m_dlgSettingsExportFormat->show ();
2708  } else {
2709  DlgRequiresTransform dlg ("Export settings");
2710  dlg.exec();
2711  }
2712 }
2713 
2714 void MainWindow::slotSettingsGeneral ()
2715 {
2716  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGeneral";
2717 
2718  m_dlgSettingsGeneral->load (*m_cmdMediator);
2719  m_dlgSettingsGeneral->show ();
2720 }
2721 
2722 void MainWindow::slotSettingsGridDisplay()
2723 {
2724  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridDisplay";
2725 
2726  m_dlgSettingsGridDisplay->load (*m_cmdMediator);
2727  m_dlgSettingsGridDisplay->show ();
2728 }
2729 
2730 void MainWindow::slotSettingsGridRemoval ()
2731 {
2732  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridRemoval";
2733 
2734  m_dlgSettingsGridRemoval->load (*m_cmdMediator);
2735  m_dlgSettingsGridRemoval->show ();
2736 }
2737 
2738 void MainWindow::slotSettingsPointMatch ()
2739 {
2740  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsPointMatch";
2741 
2742  m_dlgSettingsPointMatch->load (*m_cmdMediator);
2743  m_dlgSettingsPointMatch->show ();
2744 }
2745 
2746 void MainWindow::slotSettingsSegments ()
2747 {
2748  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsSegments";
2749 
2750  m_dlgSettingsSegments->load (*m_cmdMediator);
2751  m_dlgSettingsSegments->show ();
2752 }
2753 
2754 void MainWindow::slotTableStatusChange ()
2755 {
2756  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTableStatusChange";
2757 
2758  // This slot is called when either window in FittingWindow or GeometryWindow loses/gains focus. This is
2759  // so the Copy menu item can be updated
2760  updateControls ();
2761 }
2762 
2763 void MainWindow::slotSettingsMainWindow ()
2764 {
2765  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsMainWindow";
2766 
2767  m_dlgSettingsMainWindow->loadMainWindowModel (*m_cmdMediator,
2768  m_modelMainWindow);
2769  m_dlgSettingsMainWindow->show ();
2770 }
2771 
2772 void MainWindow::slotTimeoutRegressionErrorReport ()
2773 {
2774  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionErrorReport"
2775  << " cmdStackIndex=" << m_cmdMediator->index()
2776  << " cmdStackCount=" << m_cmdMediator->count();
2777 
2778  if (m_cmdStackShadow->canRedo()) {
2779 
2780  // Always reset current directory before the command. This guarantees the upcoming redo step will work
2781  QDir::setCurrent (m_startupDirectory);
2782 
2783  m_cmdStackShadow->slotRedo();
2784 
2785  // Always reset current directory after the command. This guarantees the final export to file will work
2786  QDir::setCurrent (m_startupDirectory);
2787 
2788  } else {
2789 
2790 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
2791  exportAllCoordinateSystemsAfterRegressionTests ();
2792 #endif
2793 
2794  // Regression test has finished so exit. We unset the dirty flag so there is no prompt
2795  m_cmdMediator->setClean();
2796  close();
2797 
2798  }
2799 }
2800 
2801 void MainWindow::slotTimeoutRegressionFileCmdScript ()
2802 {
2803  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionFileCmdScript";
2804 
2805  if (m_fileCmdScript->canRedo()) {
2806 
2807  // Always reset current directory before the command. This guarantees the upcoming redo step will work
2808  QDir::setCurrent (m_startupDirectory);
2809 
2810  m_fileCmdScript->redo(*this);
2811 
2812  // Always reset current directory after the command. This guarantees the final export to file will work
2813  QDir::setCurrent (m_startupDirectory);
2814 
2815  } else {
2816 
2817  // Script file might already have closed the Document so export only if last was not closed
2818  if (m_cmdMediator != 0) {
2819 
2820 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
2821  exportAllCoordinateSystemsAfterRegressionTests ();
2822 #endif
2823 
2824  // We unset the dirty flag so there is no "Save changes?" prompt
2825  m_cmdMediator->setClean();
2826 
2827  }
2828 
2829  // Regression test has finished so exit
2830  close();
2831 
2832  }
2833 }
2834 
2835 void MainWindow::slotUndoTextChanged (const QString &text)
2836 {
2837  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotUndoTextChanged";
2838 
2839  QString completeText ("Undo");
2840  if (!text.isEmpty ()) {
2841  completeText += QString (" \"%1\"").arg (text);
2842  }
2843  m_actionEditUndo->setText (completeText);
2844 }
2845 
2846 void MainWindow::slotViewGridLines ()
2847 {
2848  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotViewGridLines";
2849 
2850  updateGridLines ();
2851 }
2852 
2853 void MainWindow::slotViewGroupBackground(QAction *action)
2854 {
2855  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupBackground";
2856 
2857  // Set the combobox
2858  BackgroundImage backgroundImage;
2859  int indexBackground;
2860  if (action == m_actionViewBackgroundNone) {
2861  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_NONE));
2862  backgroundImage = BACKGROUND_IMAGE_NONE;
2863  } else if (action == m_actionViewBackgroundOriginal) {
2864  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
2865  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
2866  } else if (action == m_actionViewBackgroundFiltered) {
2867  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_FILTERED));
2868  backgroundImage = BACKGROUND_IMAGE_FILTERED;
2869  } else {
2870  ENGAUGE_ASSERT (false);
2871 
2872  // Defaults if assert is disabled so execution continues
2873  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
2874  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
2875  }
2876 
2877  m_cmbBackground->setCurrentIndex (indexBackground);
2878  m_backgroundStateContext->setBackgroundImage (backgroundImage);
2879 }
2880 
2881 void MainWindow::slotViewGroupCurves(QAction * /* action */)
2882 {
2883  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupCurves";
2884 
2885  updateViewedCurves ();
2886 }
2887 
2888 void MainWindow::slotViewGroupStatus(QAction *action)
2889 {
2890  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupStatus";
2891 
2892  ENGAUGE_CHECK_PTR (m_statusBar); // At startup, make sure status bar is already set up when View menu gets initialized
2893 
2894  if (action == m_actionStatusNever) {
2895  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_NEVER);
2896  } else if (action == m_actionStatusTemporary) {
2897  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_TEMPORARY);
2898  } else {
2899  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_ALWAYS);
2900  }
2901 }
2902 
2903 void MainWindow::slotViewToolBarBackground ()
2904 {
2905  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarBackground";
2906 
2907  if (m_actionViewBackground->isChecked ()) {
2908  m_toolBackground->show();
2909  } else {
2910  m_toolBackground->hide();
2911  }
2912 }
2913 
2914 void MainWindow::slotViewToolBarChecklistGuide ()
2915 {
2916  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarChecklistGuide";
2917 
2918  if (m_actionViewChecklistGuide->isChecked ()) {
2919  m_dockChecklistGuide->show();
2920  } else {
2921  m_dockChecklistGuide->hide();
2922  }
2923 }
2924 
2925 void MainWindow::slotViewToolBarCoordSystem ()
2926 {
2927  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarCoordSystem";
2928 
2929  if (m_actionViewCoordSystem->isChecked ()) {
2930  m_toolCoordSystem->show();
2931  } else {
2932  m_toolCoordSystem->hide();
2933  }
2934 }
2935 
2936 void MainWindow::slotViewToolBarDigitize ()
2937 {
2938  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarDigitize";
2939 
2940  if (m_actionViewDigitize->isChecked ()) {
2941  m_toolDigitize->show();
2942  } else {
2943  m_toolDigitize->hide();
2944  }
2945 }
2946 
2947 void MainWindow::slotViewToolBarFittingWindow()
2948 {
2949  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarFittingWindow";
2950 
2951  if (m_actionViewFittingWindow->isChecked()) {
2952  m_dockFittingWindow->show ();
2953  if (m_fittingCurve != 0) {
2954  m_fittingCurve->setVisible (true);
2955  }
2956  } else {
2957  m_dockFittingWindow->hide ();
2958  if (m_fittingCurve != 0) {
2959  m_fittingCurve->setVisible (false);
2960  }
2961  }
2962 }
2963 
2964 void MainWindow::slotViewToolBarGeometryWindow ()
2965 {
2966  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarGeometryWindow";
2967 
2968  if (m_actionViewGeometryWindow->isChecked ()) {
2969  m_dockGeometryWindow->show();
2970  } else {
2971  m_dockGeometryWindow->hide();
2972  }
2973 }
2974 
2975 void MainWindow::slotViewToolBarSettingsViews ()
2976 {
2977  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarSettingsViews";
2978 
2979  if (m_actionViewSettingsViews->isChecked ()) {
2980  m_toolSettingsViews->show();
2981  } else {
2982  m_toolSettingsViews->hide();
2983  }
2984 }
2985 
2986 void MainWindow::slotViewToolTips ()
2987 {
2988  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolTips";
2989 
2990  loadToolTips();
2991 }
2992 
2993 void MainWindow::slotViewZoom (int zoom)
2994 {
2995  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom";
2996 
2997  // Update zoom controls and apply the zoom factor
2998  ZoomFactor zoomFactor = (ZoomFactor) zoom;
2999  m_zoomMapToAction [zoomFactor]->setChecked (true);
3000  slotViewZoomFactor ((ZoomFactor) zoom);
3001 }
3002 
3003 void MainWindow::slotViewZoomFactor (ZoomFactor zoomFactor)
3004 {
3005  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomFactor";
3006 
3007  if (zoomFactor == ZOOM_FILL) {
3008  m_backgroundStateContext->fitInView (*m_view);
3009  } else {
3010 
3011  ZoomTransition zoomTransition;
3012  double factor = zoomTransition.mapToFactor (zoomFactor);
3013 
3014  QTransform transform;
3015  transform.scale (factor, factor);
3016  m_view->setTransform (transform);
3017  }
3018 
3019  emit signalZoom(zoomFactor);
3020 }
3021 
3022 void MainWindow::slotViewZoomFactorInt (int zoom)
3023 {
3024  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomFactorInt";
3025 
3026  slotViewZoomFactor ((ZoomFactor) zoom);
3027 }
3028 
3029 void MainWindow::slotViewZoomIn ()
3030 {
3031  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomIn";
3032 
3033  ZoomTransition zoomTransition;
3034  ZoomFactor zoomFactorNew = zoomTransition.zoomIn (currentZoomFactor (),
3035  m_view->transform ().m11 (),
3036  m_view->transform ().m22 (),
3037  m_actionZoomFill->isChecked ());
3038  setNonFillZoomFactor (zoomFactorNew);
3039 }
3040 
3041 
3042 void MainWindow::slotViewZoomInFromWheelEvent ()
3043 {
3044  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomInFromWheelEvent";
3045 
3046  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
3047  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
3048 
3049  // Anchor the zoom to the cursor position
3050  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
3051 
3052  // Forward this event
3053  slotViewZoomIn ();
3054 
3055  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
3056  }
3057 }
3058 
3059 void MainWindow::slotViewZoomOut ()
3060 {
3061  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOut";
3062 
3063  // Try to zoom out
3064  ZoomTransition zoomTransition;
3065  ZoomFactor zoomFactorNew = zoomTransition.zoomOut (currentZoomFactor (),
3066  m_view->transform ().m11 (),
3067  m_view->transform ().m22 (),
3068  m_actionZoomFill->isChecked ());
3069  setNonFillZoomFactor (zoomFactorNew);
3070 }
3071 
3072 void MainWindow::slotViewZoomOutFromWheelEvent ()
3073 {
3074  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOutFromWheelEvent";
3075 
3076  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
3077  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
3078 
3079  // Anchor the zoom to the cursor position
3080  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
3081 
3082  // Forward this event
3083  slotViewZoomOut ();
3084 
3085  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
3086  }
3087 }
3088 
3089 void MainWindow::startRegressionTestErrorReport(const QString &regressionInputFile)
3090 {
3091  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestErrorReport";
3092 
3093  // In order for point-deleting commands to work (CmdCut, CmdDelete) in the regression tests, we need to
3094  // reset the Point identifier index here:
3095  // 1) after loading of the file which has increased the index value to greater than 0
3096  // 2) before running any commands since those commands implicitly assume the index is zero
3098 
3099  // Save output/export file name
3100  m_regressionFile = exportRegressionFilenameFromInputFilename (regressionInputFile);
3101 
3102  m_timerRegressionErrorReport = new QTimer();
3103  m_timerRegressionErrorReport->setSingleShot(false);
3104  connect (m_timerRegressionErrorReport, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionErrorReport()));
3105 
3106  m_timerRegressionErrorReport->start(REGRESSION_INTERVAL);
3107 }
3108 
3109 void MainWindow::startRegressionTestFileCmdScript()
3110 {
3111  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestFileCmdScript";
3112 
3113  m_timerRegressionFileCmdScript = new QTimer();
3114  m_timerRegressionFileCmdScript->setSingleShot(false);
3115  connect (m_timerRegressionFileCmdScript, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionFileCmdScript()));
3116 
3117  m_timerRegressionFileCmdScript->start(REGRESSION_INTERVAL);
3118 }
3119 
3121 {
3122  return m_transformation;
3123 }
3124 
3126 {
3127  return m_transformation.transformIsDefined();
3128 }
3129 
3131 {
3132  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommand";
3133 
3134  ENGAUGE_CHECK_PTR (m_cmdMediator);
3135 
3136  // Update transformation stuff, including the graph coordinates of every point in the Document, so coordinates in
3137  // status bar are up to date. Point coordinates in Document are also updated
3138  updateAfterCommandStatusBarCoords ();
3139 
3140  updateHighlightOpacity ();
3141 
3142  // Update graphics. Effectively, these steps do very little (just needed for highlight opacity)
3143  m_digitizeStateContext->updateAfterPointAddition (); // May or may not be needed due to point addition
3144 
3145  updateControls ();
3146  updateChecklistGuide ();
3147  updateFittingWindow ();
3148  updateGeometryWindow();
3149 
3150  // Final actions at the end of a redo/undo are:
3151  // 1) checkpoint the Document and GraphicsScene to log files so proper state can be verified
3152  // 2) run sanity check on state
3153  writeCheckpointToLogFile ();
3154  DocumentScrub docScrub;
3155  docScrub.check (*this,
3156  m_cmdMediator->document ());
3157 
3158  // Since focus may have drifted over to Geometry Window or some other control we se focus on the GraphicsView
3159  // so the cursor is appropriate for the current state (otherwise it often ends up as default arrow)
3160  m_view->setFocus ();
3161 }
3162 
3163 void MainWindow::updateAfterCommandStatusBarCoords ()
3164 {
3165  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommandStatusBarCoords";
3166 
3167  // For some reason, mapFromGlobal(QCursor::pos) differs from event->pos by a little bit. We must compensate for
3168  // this so cursor coordinates in status bar match the DlgEditPointAxis inputs initially. After the mouse moves
3169  // the problem disappears since event->pos is available and QCursor::pos is no longer needed
3170  const QPoint HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT (1, 1);
3171 
3172  Transformation m_transformationBefore (m_transformation);
3173 
3174  updateTransformationAndItsDependencies();
3175 
3176  // Trigger state transitions for transformation if appropriate
3177  if (!m_transformationBefore.transformIsDefined() && m_transformation.transformIsDefined()) {
3178 
3179  // Transition from undefined to defined
3180  m_transformationStateContext->triggerStateTransition(m_isGnuplot,
3181  TRANSFORMATION_STATE_DEFINED,
3182  *m_cmdMediator,
3183  m_transformation,
3184  selectedGraphCurve());
3185 
3186  } else if (m_transformationBefore.transformIsDefined() && !m_transformation.transformIsDefined()) {
3187 
3188  // Transition from defined to undefined
3189  m_transformationStateContext->triggerStateTransition(m_isGnuplot,
3190  TRANSFORMATION_STATE_UNDEFINED,
3191  *m_cmdMediator,
3192  m_transformation,
3193  selectedGraphCurve());
3194 
3195  } else if (m_transformation.transformIsDefined() && (m_transformationBefore != m_transformation)) {
3196 
3197  // There was not a define/undefined or undefined/defined transition, but the transformation changed so we
3198  // need to update the Checker
3199  m_transformationStateContext->updateAxesChecker(*m_cmdMediator,
3200  m_transformation);
3201 
3202  }
3203 
3204  QPoint posLocal = m_view->mapFromGlobal (QCursor::pos ()) - HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT;
3205  QPointF posScreen = m_view->mapToScene (posLocal);
3206 
3207  slotMouseMove (posScreen); // Update the status bar coordinates to reflect the newly updated transformation
3208 }
3209 
3211 {
3212  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterMouseRelease";
3213 
3214  updateControls ();
3215 }
3216 
3217 void MainWindow::updateChecklistGuide ()
3218 {
3219  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateChecklistGuide";
3220 
3221  m_dockChecklistGuide->update (*m_cmdMediator,
3222  m_isDocumentExported);
3223 }
3224 
3225 void MainWindow::updateControls ()
3226 {
3227  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateControls"
3228  << " selectedItems=" << m_scene->selectedItems().count();
3229 
3230  m_cmbBackground->setEnabled (!m_currentFile.isEmpty ());
3231 
3232  m_actionImportImageReplace->setEnabled (m_cmdMediator != 0);
3233 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
3234  m_menuFileOpenRecent->setEnabled ((m_actionRecentFiles.count () > 0) &&
3235  (m_actionRecentFiles.at(0)->isVisible ())); // Need at least one visible recent file entry
3236 #endif
3237  m_actionClose->setEnabled (!m_currentFile.isEmpty ());
3238  m_actionSave->setEnabled (!m_currentFile.isEmpty ());
3239  m_actionSaveAs->setEnabled (!m_currentFile.isEmpty ());
3240  m_actionExport->setEnabled (!m_currentFile.isEmpty ());
3241  m_actionPrint->setEnabled (!m_currentFile.isEmpty ());
3242 
3243  if (m_cmdMediator == 0) {
3244  m_actionEditUndo->setEnabled (false);
3245  m_actionEditRedo->setEnabled (false);
3246  } else {
3247  m_actionEditUndo->setEnabled (m_cmdMediator->canUndo ());
3248  m_actionEditRedo->setEnabled (m_cmdMediator->canRedo () || m_cmdStackShadow->canRedo ());
3249  }
3250  bool tableFittingIsActive, tableFittingIsCopyable;
3251  bool tableGeometryIsActive, tableGeometryIsCopyable;
3252  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
3253  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
3254  m_actionEditCut->setEnabled (!tableFittingIsActive &&
3255  !tableGeometryIsActive &&
3256  m_scene->selectedItems().count () > 0);
3257  m_actionEditCopy->setEnabled ((!tableFittingIsActive && !tableGeometryIsActive && m_scene->selectedItems().count () > 0) ||
3258  (tableFittingIsActive && tableFittingIsCopyable) ||
3259  (tableGeometryIsActive && tableGeometryIsCopyable));
3260  m_actionEditPaste->setEnabled (m_digitizeStateContext->canPaste (m_transformation,
3261  m_view->size ()));
3262  m_actionEditDelete->setEnabled (!tableFittingIsActive &&
3263  !tableGeometryIsActive &&
3264  m_scene->selectedItems().count () > 0);
3265  // m_actionEditPasteAsNew and m_actionEditPasteAsNewAdvanced are updated when m_menuEdit is about to be shown
3266 
3267  m_actionDigitizeAxis->setEnabled (modeGraph ());
3268  m_actionDigitizeScale->setEnabled (modeMap ());
3269  m_actionDigitizeCurve ->setEnabled (!m_currentFile.isEmpty ());
3270  m_actionDigitizePointMatch->setEnabled (!m_currentFile.isEmpty ());
3271  m_actionDigitizeColorPicker->setEnabled (!m_currentFile.isEmpty ());
3272  m_actionDigitizeSegment->setEnabled (!m_currentFile.isEmpty ());
3273  m_actionDigitizeSelect->setEnabled (!m_currentFile.isEmpty ());
3274  if (m_transformation.transformIsDefined()) {
3275  m_actionViewGridLines->setEnabled (true);
3276  } else {
3277  m_actionViewGridLines->setEnabled (false);
3278  m_actionViewGridLines->setChecked (false);
3279  }
3280  m_actionViewBackground->setEnabled (!m_currentFile.isEmpty());
3281  m_actionViewChecklistGuide->setEnabled (!m_dockChecklistGuide->browserIsEmpty());
3282  m_actionViewDigitize->setEnabled (!m_currentFile.isEmpty ());
3283  m_actionViewSettingsViews->setEnabled (!m_currentFile.isEmpty ());
3284 
3285  m_actionSettingsCoords->setEnabled (!m_currentFile.isEmpty ());
3286  m_actionSettingsCurveList->setEnabled (!m_currentFile.isEmpty ());
3287  m_actionSettingsCurveProperties->setEnabled (!m_currentFile.isEmpty ());
3288  m_actionSettingsDigitizeCurve->setEnabled (!m_currentFile.isEmpty ());
3289  m_actionSettingsExport->setEnabled (!m_currentFile.isEmpty ());
3290  m_actionSettingsColorFilter->setEnabled (!m_currentFile.isEmpty ());
3291  m_actionSettingsAxesChecker->setEnabled (!m_currentFile.isEmpty ());
3292  m_actionSettingsGridDisplay->setEnabled (!m_currentFile.isEmpty () && m_transformation.transformIsDefined());
3293  m_actionSettingsGridRemoval->setEnabled (!m_currentFile.isEmpty ());
3294  m_actionSettingsPointMatch->setEnabled (!m_currentFile.isEmpty ());
3295  m_actionSettingsSegments->setEnabled (!m_currentFile.isEmpty ());
3296  m_actionSettingsGeneral->setEnabled (!m_currentFile.isEmpty ());
3297 
3298  m_groupBackground->setEnabled (!m_currentFile.isEmpty ());
3299  m_groupCurves->setEnabled (!m_currentFile.isEmpty ());
3300  m_groupZoom->setEnabled (!m_currentFile.isEmpty ());
3301 
3302  m_actionZoomIn->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
3303  m_actionZoomOut->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
3304 }
3305 
3306 void MainWindow::updateCoordSystem(CoordSystemIndex coordSystemIndex)
3307 {
3308  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateCoordSystem";
3309 
3310  // Set current curve in the Document and in the MainWindow combobox together so they are in sync. Setting
3311  // the selected curve prevents a crash in updateTransformationAndItsDependencies
3312  m_cmdMediator->document().setCoordSystemIndex (coordSystemIndex);
3313  loadCurveListFromCmdMediator ();
3314 
3315  updateTransformationAndItsDependencies(); // Transformation state may have changed
3316  updateSettingsAxesChecker(m_cmdMediator->document().modelAxesChecker()); // Axes checker dependes on transformation state
3317 
3318  // Nice trick for showing that a new coordinate system is in effect is to show the axes checker
3319  m_transformationStateContext->updateAxesChecker (*m_cmdMediator,
3320  m_transformation);
3321 
3323 }
3324 
3325 void MainWindow::updateDigitizeStateIfSoftwareTriggered (DigitizeState digitizeState)
3326 {
3327  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
3328 
3329  switch (digitizeState) {
3330  case DIGITIZE_STATE_AXIS:
3331  m_actionDigitizeAxis->setChecked(true);
3332  slotDigitizeAxis(); // Call the slot that the setChecked call fails to trigger
3333  break;
3334 
3335  case DIGITIZE_STATE_COLOR_PICKER:
3336  m_actionDigitizeColorPicker->setChecked(true);
3337  slotDigitizeColorPicker(); // Call the slot that the setChecked call fails to trigger
3338  break;
3339 
3340  case DIGITIZE_STATE_CURVE:
3341  m_actionDigitizeCurve->setChecked(true);
3342  slotDigitizeCurve(); // Call the slot that the setChecked call fails to trigger
3343  break;
3344 
3345  case DIGITIZE_STATE_EMPTY:
3346  break;
3347 
3348  case DIGITIZE_STATE_POINT_MATCH:
3349  m_actionDigitizePointMatch->setChecked(true);
3350  slotDigitizePointMatch(); // Call the slot that the setChecked call fails to trigger
3351  break;
3352 
3353  case DIGITIZE_STATE_SCALE:
3354  m_actionDigitizeScale->setChecked(true);
3355  slotDigitizeScale(); // Call the slot that the setChecked call fails to trigger
3356  break;
3357 
3358  case DIGITIZE_STATE_SEGMENT:
3359  m_actionDigitizeSegment->setChecked(true);
3360  slotDigitizeSegment(); // Call the slot that the setChecked call fails to trigger
3361  break;
3362 
3363  case DIGITIZE_STATE_SELECT:
3364  m_actionDigitizeSelect->setChecked(true);
3365  slotDigitizeSelect(); // Call the slot that the setChecked call fails to trigger
3366  break;
3367 
3368  default:
3369  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
3370  break;
3371  }
3372 }
3373 
3374 void MainWindow::updateFittingWindow ()
3375 {
3376  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateFittingWindow";
3377 
3378  if (m_cmdMediator != 0 &&
3379  m_cmbCurve != 0) {
3380 
3381  // Update fitting window
3382  m_dockFittingWindow->update (*m_cmdMediator,
3383  m_modelMainWindow,
3384  m_cmbCurve->currentText (),
3385  m_transformation);
3386  }
3387 }
3388 
3389 void MainWindow::updateGeometryWindow ()
3390 {
3391  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGeometryWindow";
3392 
3393  if (m_cmdMediator != 0 &&
3394  m_cmbCurve != 0) {
3395 
3396  // Update geometry window
3397  m_dockGeometryWindow->update (*m_cmdMediator,
3398  m_modelMainWindow,
3399  m_cmbCurve->currentText (),
3400  m_transformation);
3401  }
3402 }
3403 
3405 {
3406  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGraphicsLinesToMatchGraphicsPoints";
3407 
3409  m_transformation);
3410 }
3411 
3412 void MainWindow::updateGridLines ()
3413 {
3414  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGridLines";
3415 
3416  // Remove old grid lines
3417  m_gridLines.clear ();
3418 
3419  // Create new grid lines
3420  GridLineFactory factory (*m_scene,
3421  m_cmdMediator->document().modelCoords());
3422  factory.createGridLinesForEvenlySpacedGrid (m_cmdMediator->document().modelGridDisplay(),
3423  m_cmdMediator->document(),
3424  m_modelMainWindow,
3425  m_transformation,
3426  m_gridLines);
3427 
3428  m_gridLines.setVisible (m_actionViewGridLines->isChecked());
3429 }
3430 
3431 void MainWindow::updateHighlightOpacity ()
3432 {
3433  if (m_cmdMediator != 0) {
3434 
3435  // Update the QGraphicsScene with the populated Curves. This requires the points in the Document to be already updated
3436  // by updateAfterCommandStatusBarCoords
3437  m_scene->updateAfterCommand (*m_cmdMediator,
3438  m_modelMainWindow.highlightOpacity(),
3439  m_dockGeometryWindow,
3440  m_transformation);
3441  }
3442 }
3443 
3444 void MainWindow::updateRecentFileList()
3445 {
3446  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateRecentFileList";
3447 
3448 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
3449  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
3450  QStringList recentFilePaths = settings.value(SETTINGS_RECENT_FILE_LIST).toStringList();
3451 
3452  // Determine the desired size of the path list
3453  unsigned int count = recentFilePaths.size();
3454  if (count > MAX_RECENT_FILE_LIST_SIZE) {
3455  count = MAX_RECENT_FILE_LIST_SIZE;
3456  }
3457 
3458  // Add visible entries
3459  unsigned int i;
3460  for (i = 0; i < count; i++) {
3461  QString strippedName = QFileInfo (recentFilePaths.at(i)).fileName();
3462  m_actionRecentFiles.at (i)->setText (strippedName);
3463  m_actionRecentFiles.at (i)->setData (recentFilePaths.at (i));
3464  m_actionRecentFiles.at (i)->setVisible (true);
3465  }
3466 
3467  // Hide any extra entries
3468  for (i = count; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
3469  m_actionRecentFiles.at (i)->setVisible (false);
3470  }
3471 #endif
3472 }
3473 
3475 {
3476  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsAxesChecker";
3477 
3478  m_cmdMediator->document().setModelAxesChecker(modelAxesChecker);
3479  if (m_transformation.transformIsDefined()) {
3480  m_transformationStateContext->triggerStateTransition(m_isGnuplot,
3481  TRANSFORMATION_STATE_DEFINED,
3482  *m_cmdMediator,
3483  m_transformation,
3484  m_cmbCurve->currentText());
3485  } else {
3486  m_transformationStateContext->triggerStateTransition(m_isGnuplot,
3487  TRANSFORMATION_STATE_UNDEFINED,
3488  *m_cmdMediator,
3489  m_transformation,
3490  m_cmbCurve->currentText());
3491  }
3492 }
3493 
3495 {
3496  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsColorFilter";
3497 
3498  m_cmdMediator->document().setModelColorFilter(modelColorFilter);
3499  m_backgroundStateContext->updateColorFilter (m_isGnuplot,
3500  m_transformation,
3501  m_cmdMediator->document().modelGridRemoval(),
3502  modelColorFilter,
3503  m_cmbCurve->currentText());
3504  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
3506 }
3507 
3509 {
3510  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCoords";
3511 
3512  m_cmdMediator->document().setModelCoords(modelCoords);
3513 }
3514 
3516 {
3517  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveList";
3518 
3519  m_cmdMediator->document().setCurvesGraphs (curvesGraphs);
3520  loadCurveListFromCmdMediator();
3522 }
3523 
3525 {
3526  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveStyles";
3527 
3528  m_scene->updateCurveStyles(modelCurveStyles);
3529  m_cmdMediator->document().setModelCurveStyles(modelCurveStyles);
3531 }
3532 
3534 {
3535  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsDigitizeCurve";
3536 
3537  m_cmdMediator->document().setModelDigitizeCurve(modelDigitizeCurve);
3538  m_digitizeStateContext->updateModelDigitizeCurve (m_cmdMediator,
3539  modelDigitizeCurve);
3540 }
3541 
3543 {
3544  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsExportFormat";
3545 
3546  m_cmdMediator->document().setModelExport (modelExport);
3547 }
3548 
3550 {
3551  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGeneral";
3552 
3553  m_cmdMediator->document().setModelGeneral(modelGeneral);
3554 }
3555 
3557 {
3558  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridDisplay";
3559 
3560  m_cmdMediator->document().setModelGridDisplay(modelGridDisplay);
3561  updateGridLines ();
3562 }
3563 
3565 {
3566  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridRemoval";
3567 
3568  m_cmdMediator->document().setModelGridRemoval(modelGridRemoval);
3569 }
3570 
3571 void MainWindow::updateSettingsMainWindow()
3572 {
3573  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
3574 
3575  if (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_ONLY ||
3576  m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) {
3577 
3578  m_actionZoomIn->setShortcut (tr (""));
3579  m_actionZoomOut->setShortcut (tr (""));
3580 
3581  } else {
3582 
3583  m_actionZoomIn->setShortcut (tr ("+"));
3584  m_actionZoomOut->setShortcut (tr ("-"));
3585 
3586  }
3587 
3588  if ((m_scene != 0) &&
3589  (m_cmdMediator != 0)) {
3590  m_scene->updateCurveStyles(m_cmdMediator->document().modelCurveStyles());
3591  }
3592 
3593  updateHighlightOpacity();
3594  updateWindowTitle();
3595  updateFittingWindow(); // Forward the drag and drop choice
3596  updateGeometryWindow(); // Forward the drag and drop choice
3597 }
3598 
3600 {
3601  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
3602 
3603  m_modelMainWindow = modelMainWindow;
3605 }
3606 
3608 {
3609  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsPointMatch";
3610 
3611  m_cmdMediator->document().setModelPointMatch(modelPointMatch);
3612 }
3613 
3615 {
3616  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsSegments";
3617 
3618  m_cmdMediator->document().setModelSegments(modelSegments);
3619  m_digitizeStateContext->updateModelSegments(modelSegments);
3620 }
3621 
3622 void MainWindow::updateSmallDialogs ()
3623 {
3624  m_dlgSettingsAxesChecker->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3625  m_dlgSettingsColorFilter->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3626  m_dlgSettingsCoords->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3627  m_dlgSettingsCurveList->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3628  m_dlgSettingsCurveProperties->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3629  m_dlgSettingsDigitizeCurve->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3630  m_dlgSettingsExportFormat->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3631  m_dlgSettingsGeneral->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3632  m_dlgSettingsGridDisplay->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3633  m_dlgSettingsGridRemoval->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3634  m_dlgSettingsMainWindow->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3635  m_dlgSettingsPointMatch->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3636  m_dlgSettingsSegments->setSmallDialogs (m_modelMainWindow.smallDialogs ());
3637 }
3638 
3639 void MainWindow::updateTransformationAndItsDependencies()
3640 {
3641  m_transformation.update (!m_currentFile.isEmpty (),
3642  *m_cmdMediator,
3643  m_modelMainWindow);
3644 
3645  // Grid removal is affected by new transformation above
3646  m_backgroundStateContext->setCurveSelected (m_isGnuplot,
3647  m_transformation,
3648  m_cmdMediator->document().modelGridRemoval(),
3649  m_cmdMediator->document().modelColorFilter(),
3650  m_cmbCurve->currentText ());
3651 
3652  // Grid display is also affected by new transformation above, if there was a transition into defined state
3653  // in which case that transition triggered the initialization of the grid display parameters
3654  updateGridLines();
3655 }
3656 
3657 void MainWindow::updateViewedCurves ()
3658 {
3659  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewedCurves";
3660 
3661  if (m_actionViewCurvesAll->isChecked ()) {
3662 
3663  m_scene->showCurves (true, true);
3664 
3665  } else if (m_actionViewCurvesSelected->isChecked ()) {
3666 
3667  m_scene->showCurves (true, false, selectedGraphCurve ());
3668 
3669  } else if (m_actionViewCurvesNone->isChecked ()) {
3670 
3671  m_scene->showCurves (false);
3672 
3673  } else {
3674  ENGAUGE_ASSERT (false);
3675  }
3676 }
3677 
3679 {
3680  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewsOfSettings";
3681 
3682  QString activeCurve = m_digitizeStateContext->activeCurve ();
3683 
3684  updateViewsOfSettings (activeCurve);
3685 }
3686 
3687 void MainWindow::updateViewsOfSettings (const QString &activeCurve)
3688 {
3689  if (activeCurve.isEmpty ()) {
3690 
3691  m_viewPointStyle->unsetPointStyle ();
3692  m_viewSegmentFilter->unsetColorFilterSettings ();
3693 
3694 
3695  } else {
3696 
3697  PointStyle pointStyle = m_cmdMediator->document().modelCurveStyles().curveStyle(activeCurve).pointStyle();
3698  m_viewPointStyle->setPointStyle (pointStyle);
3699 
3700  ColorFilterSettings colorFilterSettings = m_cmdMediator->document().modelColorFilter().colorFilterSettings(activeCurve);
3701  m_viewSegmentFilter->setColorFilterSettings (colorFilterSettings,
3702  m_cmdMediator->pixmap ());
3703 
3704  }
3705 }
3706 
3707 void MainWindow::updateWindowTitle ()
3708 {
3709  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateWindowTitle";
3710 
3711  const QString PLACEHOLDER ("[*]");
3712 
3713  QString title = QString ("%1 %2")
3714  .arg (tr ("Engauge Digitizer"))
3715  .arg (VERSION_NUMBER);
3716 
3717  QString fileNameMaybeStripped;
3718  if (!m_currentFileWithPathAndFileExtension.isEmpty()) {
3719 
3720  QFileInfo fileInfo (m_currentFileWithPathAndFileExtension);
3721 
3722  switch (m_modelMainWindow.mainTitleBarFormat())
3723  {
3724  case MAIN_TITLE_BAR_FORMAT_NO_PATH:
3725  // Remove file extension and path for "clean look". We use completeBaseName rather than baseName so
3726  // files with multiple periods are handled correctly - all but last suffix gets kept
3727  fileNameMaybeStripped = fileInfo.completeBaseName();
3728  break;
3729 
3730  case MAIN_TITLE_BAR_FORMAT_PATH:
3731  fileNameMaybeStripped = m_currentFileWithPathAndFileExtension;
3732  break;
3733  }
3734 
3735  title += QString (": %1")
3736  .arg (fileNameMaybeStripped);
3737  }
3738 
3739  // To prevent "QWidget::setWindowModified: The window title does not contain a [*] placeholder" warnings,
3740  // we always append a placeholder
3741  title += PLACEHOLDER;
3742 
3743  setWindowTitle (title);
3744 }
3745 
3747 {
3748  ENGAUGE_CHECK_PTR (m_view);
3749  return *m_view;
3750 }
3751 
3753 {
3754  ENGAUGE_CHECK_PTR (m_view);
3755  return *m_view;
3756 }
3757 
3758 void MainWindow::writeCheckpointToLogFile ()
3759 {
3760  // Document
3761  QString checkpointDoc;
3762  QTextStream strDoc (&checkpointDoc);
3763  m_cmdMediator->document().printStream(INDENTATION_PAST_TIMESTAMP,
3764  strDoc);
3765 
3766  // Scene
3767  QString checkpointScene;
3768  QTextStream strScene (&checkpointScene);
3769  m_scene->printStream (INDENTATION_PAST_TIMESTAMP,
3770  strScene);
3771 
3772  // Skip slow string manipulation if BEFORE call to LOG4CPP_DEBUG_S
3773  if (mainCat->getPriority() == log4cpp::Priority::DEBUG) {
3774 
3775  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::writeCheckpointToLogFile\n"
3776  << "--------------DOCUMENT CHECKPOINT START----------" << "\n"
3777  << checkpointDoc.toLatin1().data()
3778  << "---------------DOCUMENT CHECKPOINT END-----------" << "\n"
3779  << "----------------SCENE CHECKPOINT START-----------" << "\n"
3780  << checkpointScene.toLatin1().data()
3781  << "-----------------SCENE CHECKPOINT END------------" ;
3782  }
3783 }
void addCoordSystems(unsigned int numberCoordSystemToAdd)
Add some number (0 or more) of additional coordinate systems.
Definition: Document.cpp:146
bool canRedo() const
Return true if there is a command available.
void load(CmdMediator &cmdMediator)
Load settings from Document.
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...
Definition: MainWindow.cpp:799
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 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
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:225
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:947
void setModelGridRemoval(const DocumentModelGridRemoval &modelGridRemoval)
Set method for DocumentModelGridRemoval.
Definition: Document.cpp:1024
Dialog for saving error report for later transmission to the developers.
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:478
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
Wrapper around OpenJPEG library, in C, for opening jpeg2000 files.
Definition: Jpeg2000.h:26
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:1031
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
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:1010
void setEnabled(bool enabled)
Show the style with semi-transparency or full-transparency to indicate if associated Curve is active ...
void setSignificantDigits(int significantDigits)
Set method for significant digits.
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:733
Wrapper around the QImage class for read and importing non-PDF files.
Definition: NonPdf.h:26
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:1038
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 updateColorFilter(bool isGnuplot, const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const DocumentModelColorFilter &colorFilter, const QString &curveSelected)
Apply color filter settings.
void updateAfterMouseRelease()
Call MainWindow::updateControls (which is private) after the very specific case - a mouse press/relea...
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 saveErrorReportFileAndExit(const char *comment, const char *file, int line, const char *context)
Save error report and exit.
void handleCurveChange(CmdMediator *cmdMediator)
See DigitizeStateAbstractBase::handleCurveChange.
void setDirectoryExportSaveFromFilename(const QString &fileName)
Save the current Export/Save directory, after user has accepted the Export/Save dialog.
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:206
QDir getDirectoryExportSave() const
Get the current Export/Save directory.
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:290
void setModelGridDisplay(const DocumentModelGridDisplay &modelGridDisplay)
Set method for DocumentModelGridDisplay.
Definition: Document.cpp:1017
Provides list of file extensions for import.
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:359
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:684
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:996
QPixmap pixmap() const
See Document::pixmap.
void cmdFileOpen(const QString &fileName)
Open file. This is called from a file script command.
Definition: MainWindow.cpp:316
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:324
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
MainWindow(const QString &errorReportFile, const QString &fileCmdScriptFile, bool isRegressionTest, bool isGnuplot, bool isReset, bool isExportOnly, bool isExtractImageOnly, const QString &extractImageOnlyExtension, const QStringList &loadStartupFiles, const QStringList &commandLineWithoutLoadStartupFiles, QWidget *parent=0)
Single constructor.
Definition: MainWindow.cpp:134
void setModelCoords(const DocumentModelCoords &modelCoords)
Set method for DocumentModelCoords.
Definition: Document.cpp:972
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:308
BackgroundImage selectOriginal(BackgroundImage backgroundImage)
Make original background visible, for DigitizeStateColorPicker.
Priority::Value getPriority() const
Returns unused priority.
Definition: Category.cpp:19
void setDirectoryImportOpenFromFilename(const QString &fileName)
Save the current Import/Open directory, after user has accepted the Import/Open dialog.
void setPixmap(bool isGnuplot, 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.
Check Document state.
Definition: DocumentScrub.h:15
void updateAfterCommand(CmdMediator &cmdMediator, double highlightOpacity, GeometryWindow *geometryWindow, const Transformation &transformation)
Update the Points and their Curves after executing a command.
ZoomFactorInitial zoomFactorInitial() const
Get method for initial zoom factor.
QString filterCsv() const
QFileDialog filter for CSV files.
void setDelimiter(ExportDelimiter exportDelimiter)
Set method for delimiter.
void setLocale(QLocale::Language language, QLocale::Country country)
Set method for locale given attributes.
void handleKeyPress(CmdMediator *cmdMediator, Qt::Key key, bool atLeastOneSelectedItem)
See DigitizeStateAbstractBase::handleKeyPress.
void setPixmap(const QImage &image)
Set method for the background pixmap.
Definition: Document.cpp:1045
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.
static void bindToMainWindow(MainWindow *mainWindow)
Bind to MainWindow so this class can access the command stack.
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:914
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...
void cmdFileExport(const QString &fileName)
Export file. This is called from a file script command.
Definition: MainWindow.cpp:298
QDir getDirectoryImportOpen() const
Get the current Import/Open directory.
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.
void setModelExport(const DocumentModelExportFormat &modelExport)
Set method for DocumentModelExportFormat.
Definition: Document.cpp:1003
Model for DlgSettingsDigitizeCurve and CmdSettingsDigitizeCurve.
GraphicsView & view()
View for the QImage and QGraphicsItems, without const.
Affine transformation between screen and graph coordinates, based on digitized axis points...
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.
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.
ImportCropping importCropping() const
Get method for import cropping.
void setModelCurveStyles(const CurveStyles &modelCurveStyles)
Set method for CurveStyles.
Definition: Document.cpp:979
bool transformIsDefined() const
Return true if all three axis points have been defined.
Facade class that wraps around all of the create classes for MainWindow.
Definition: CreateFacade.h:16
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.
Definition: MainWindow.cpp:804
Model for DlgSettingsMainWindow.
void appendNewCmd(CmdMediator *cmdMediator, QUndoCommand *cmd)
Append just-created QUndoCommand to command stack. This is called from DigitizeStateAbstractBase subc...
void create(MainWindow &mw)
Create QAction facade.
CoordSystemIndex coordSystemIndex() const
Index of current active CoordSystem.
Definition: Document.cpp:310
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.
void setCurveSelected(bool isGnuplot, const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const DocumentModelColorFilter &modelColorFilter, const QString &curveSelected)
Update the selected curve.
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:726
QStringList unite(CmdMediator *cmdMediator, const QStringList &pointIdentifiersIn) const
Add.
void setModelColorFilter(const DocumentModelColorFilter &modelColorFilter)
Set method for DocumentModelColorFilter.
Definition: Document.cpp:954
void close()
Open Document is being closed so remove the background.
Model for DlgSettingsCoords and CmdSettingsCoords.
void setVisible(bool visible)
Make all grid lines visible or hidden.
Definition: GridLines.cpp:36
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.
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
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.
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:838
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.
void showTemporaryMessage(const QString &message)
Show temporary message in status bar. After a short interval the message will disappear.
Definition: StatusBar.cpp:235
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.
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.
unsigned int coordSystemCount() const
Number of CoordSystem.
Definition: Document.cpp:303
void updateSettingsExportFormat(const DocumentModelExportFormat &modelExport)
Update with new export properties.
Import of point data from clipboard.
virtual bool eventFilter(QObject *, QEvent *)
Catch secret keypresses.
Definition: MainWindow.cpp:345
void startLoadImage(const QUrl &url)
Start the asynchronous loading of an image from the specified url.
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.
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.
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:307
void setCurvesGraphs(const CurvesGraphs &curvesGraphs)
Let CmdAbstract classes overwrite CurvesGraphs.
Definition: Document.cpp:928
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 triggerStateTransition(bool isGnuplot, TransformationState transformationState, CmdMediator &cmdMediator, const Transformation &transformation, const QString &selectedGraphCurve)
Trigger a state transition to be performed immediately.
void check(MainWindow &mainWindow, const Document &document) const
Check document state.
void loadCommands(MainWindow &mainWindow, Document &document, QXmlStreamReader &reader)
Load commands from serialized xml.
DocumentModelExportFormat modelExport() const
Get method for DocumentModelExportFormat.
Definition: Document.cpp:712
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:880
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:36
CurveStyles modelCurveStyles() const
Get method for CurveStyles.
Definition: Document.cpp:698
QStringList fileExtensionsWithAsterisks() const
File extensions for use in file dialogs.
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
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);...
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.
Persist the directory between successive Import/Open operations, or successive Export/Save operations...
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:691
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:345
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:677
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
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.
void updateSettingsCurveList(const CurvesGraphs &curvesGraphs)
Update with new curves.