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