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