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