Engauge Digitizer  2
 All Classes Functions Variables Enumerations Friends Pages
MainWindow.cpp
1 
2 /******************************************************************************************************
3  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
4  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
5  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
6  ******************************************************************************************************/
7 
8 #include "BackgroundImage.h"
9 #include "BackgroundStateContext.h"
10 #include "img/bannerapp_16.xpm"
11 #include "img/bannerapp_32.xpm"
12 #include "img/bannerapp_64.xpm"
13 #include "img/bannerapp_128.xpm"
14 #include "img/bannerapp_256.xpm"
15 #include "ChecklistGuide.h"
16 #include "ChecklistGuideWizard.h"
17 #include "CmdAddPointsGraph.h"
18 #include "CmdCopy.h"
19 #include "CmdCut.h"
20 #include "CmdDelete.h"
21 #include "CmdMediator.h"
22 #include "CmdSelectCoordSystem.h"
23 #include "CmdStackShadow.h"
24 #include "ColorFilter.h"
25 #include "Curve.h"
26 #include "DataKey.h"
27 #include "DigitizeStateContext.h"
28 #include "DigitAxis.xpm"
29 #include "DigitColorPicker.xpm"
30 #include "DigitCurve.xpm"
31 #include "DigitPointMatch.xpm"
32 #include "DigitScale.xpm"
33 #include "DigitSegment.xpm"
34 #include "DigitSelect.xpm"
35 #include "DlgAbout.h"
36 #include "DlgErrorReportLocal.h"
37 #include "DlgErrorReportNetworking.h"
38 #include "DlgImportAdvanced.h"
39 #include "DlgRequiresTransform.h"
40 #include "DlgSettingsAxesChecker.h"
41 #include "DlgSettingsColorFilter.h"
42 #include "DlgSettingsCoords.h"
43 #include "DlgSettingsCurveAddRemove.h"
44 #include "DlgSettingsCurveProperties.h"
45 #include "DlgSettingsDigitizeCurve.h"
46 #include "DlgSettingsExportFormat.h"
47 #include "DlgSettingsGeneral.h"
48 #include "DlgSettingsGridDisplay.h"
49 #include "DlgSettingsGridRemoval.h"
50 #include "DlgSettingsMainWindow.h"
51 #include "DlgSettingsPointMatch.h"
52 #include "DlgSettingsSegments.h"
53 #include "DocumentSerialize.h"
54 #include "EngaugeAssert.h"
55 #include "EnumsToQt.h"
56 #include "ExportImageForRegression.h"
57 #include "ExportToFile.h"
58 #include "FileCmdScript.h"
59 #include "FittingCurve.h"
60 #include "FittingWindow.h"
61 #include "GeometryWindow.h"
62 #include "Ghosts.h"
63 #include "GraphicsItemsExtractor.h"
64 #include "GraphicsItemType.h"
65 #include "GraphicsScene.h"
66 #include "GraphicsView.h"
67 #include "GridLineFactory.h"
68 #include "GridLineLimiter.h"
69 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
70 #include "HelpWindow.h"
71 #endif
72 #ifdef ENGAUGE_JPEG2000
73 #include "Jpeg2000.h"
74 #endif // ENGAUGE_JPEG2000
75 #include "LoadFileInfo.h"
76 #ifdef NETWORKING
77 #include "LoadImageFromUrl.h"
78 #endif
79 #include "Logger.h"
80 #include "MainDirectoryPersist.h"
81 #include "MainTitleBarFormat.h"
82 #include "MainWindow.h"
83 #include "MimePointsImport.h"
84 #ifdef NETWORKING
85 #include "NetworkClient.h"
86 #endif
87 #include "NonPdf.h"
88 #ifdef ENGAUGE_PDF
89 #include "Pdf.h"
90 #endif // ENGAUGE_PDF
91 #include "PdfResolution.h"
92 #include <QAction>
93 #include <QApplication>
94 #include <QClipboard>
95 #include <QCloseEvent>
96 #include <QComboBox>
97 #include <QDebug>
98 #include <QDesktopServices>
99 #include <QDockWidget>
100 #include <QDomDocument>
101 #include <QFileDialog>
102 #include <QFileInfo>
103 #include <QGraphicsLineItem>
104 #include <QImageReader>
105 #include <QKeyEvent>
106 #include <QKeySequence>
107 #include <QLabel>
108 #include <qmath.h>
109 #include <QMenu>
110 #include <QMenuBar>
111 #include <QMessageBox>
112 #include <QMouseEvent>
113 #include <QPrintDialog>
114 #include <QPrinter>
115 #include <QProcess>
116 #include <QPushButton>
117 #include <QSettings>
118 #include <QSignalMapper>
119 #include <QTextStream>
120 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
121 #include <QtHelp>
122 #endif
123 #include <QTimer>
124 #include <QToolBar>
125 #include <QToolButton>
126 #include "QtToString.h"
127 #include <QVBoxLayout>
128 #include <QWhatsThis>
129 #include <QXmlStreamReader>
130 #include <QXmlStreamWriter>
131 #include "ScaleBarAxisPointsUnite.h"
132 #include "Settings.h"
133 #include "StatusBar.h"
134 #include "TransformationStateContext.h"
135 #include "TutorialDlg.h"
136 #include "Version.h"
137 #include "ViewPointStyle.h"
138 #include "ViewSegmentFilter.h"
139 #include "ZoomFactor.h"
140 #include "ZoomFactorInitial.h"
141 #include "ZoomTransition.h"
142 
143 const QString EMPTY_FILENAME ("");
144 const char *ENGAUGE_FILENAME_DESCRIPTION = "Engauge Document";
145 const QString ENGAUGE_FILENAME_EXTENSION ("dig");
146 const int REGRESSION_INTERVAL = 400; // Milliseconds
147 const unsigned int MAX_RECENT_FILE_LIST_SIZE = 8;
148 
149 MainWindow::MainWindow(const QString &errorReportFile,
150  const QString &fileCmdScriptFile,
151  bool isRegressionTest,
152  bool isGnuplot,
153  bool isReset,
154  QStringList loadStartupFiles,
155  QWidget *parent) :
156  QMainWindow(parent),
157  m_isDocumentExported (false),
158  m_engaugeFile (EMPTY_FILENAME),
159  m_currentFile (EMPTY_FILENAME),
160  m_layout (0),
161  m_scene (0),
162  m_view (0),
163  m_loadImageFromUrl (0),
164  m_cmdMediator (0),
165  m_digitizeStateContext (0),
166  m_transformationStateContext (0),
167  m_backgroundStateContext (0),
168  m_networkClient (0),
169  m_isGnuplot (isGnuplot),
170  m_ghosts (0),
171  m_timerRegressionErrorReport(0),
172  m_fileCmdScript (0),
173  m_isErrorReportRegressionTest (isRegressionTest),
174  m_timerRegressionFileCmdScript(0),
175  m_fittingCurve (0)
176 {
177  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::MainWindow"
178  << " curDir=" << QDir::currentPath().toLatin1().data();
179 
180 #if defined(OSX_DEBUG) || defined(OSX_RELEASE)
181  qApp->setApplicationName ("Engauge Digitizer");
182  qApp->setOrganizationDomain ("Mark Mitchell");
183 #endif
184 
186 
187  m_startupDirectory = QDir::currentPath();
188 
189  setCurrentFile ("");
190  createIcons();
191 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
192  setWindowFlags (Qt::WindowContextHelpButtonHint | windowFlags ()); // Add help to default buttons
193 #endif
194  setWindowTitle (engaugeWindowTitle ());
195 
196  createCentralWidget();
197  createActions ();
198  createStatusBar ();
199  createMenus ();
200  createToolBars ();
201  createDockableWidgets ();
202  createHelpWindow ();
203  createTutorial ();
204  createScene ();
205  createNetwork ();
206  createLoadImageFromUrl ();
207  createStateContextBackground ();
208  createStateContextDigitize ();
209  createStateContextTransformation ();
210  createSettingsDialogs ();
211  createCommandStackShadow ();
212  createZoomMaps ();
213  updateControls ();
214 
215  settingsRead (isReset); // This changes the current directory when not regression testing
216  setCurrentFile ("");
217  setUnifiedTitleAndToolBarOnMac(true);
218 
219  installEventFilter(this);
220 
221  // Start regression scripting if appropriate. Regression scripts assume current directory is the original
222  // current directory, so we temporarily reset the current directory
223  QString originalPath = QDir::currentPath();
224  QDir::setCurrent (m_startupDirectory);
225  if (!errorReportFile.isEmpty()) {
226  loadErrorReportFile(errorReportFile);
227  if (m_isErrorReportRegressionTest) {
228  startRegressionTestErrorReport(errorReportFile);
229  }
230  } else if (!fileCmdScriptFile.isEmpty()) {
231  m_fileCmdScript = new FileCmdScript (fileCmdScriptFile);
232  startRegressionTestFileCmdScript();
233  } else {
234 
235  // Save file names for later, after gui becomes available. The file names are dropped if error report file is specified
236  // since only one of the two modes is available at any time, for simplicity
237  m_loadStartupFiles = loadStartupFiles;
238  }
239  QDir::setCurrent (originalPath);
240 }
241 
242 MainWindow::~MainWindow()
243 {
244 }
245 
246 void MainWindow::addDockWindow (QDockWidget *dockWidget,
247  QSettings &settings,
248  const QString &settingsTokenArea,
249  const QString &settingsTokenGeometry,
250  Qt::DockWidgetArea dockWidgetArea)
251 {
252  // Checklist guide is docked or undocked. Default is docked so it does not get overlooked by the user (which
253  // can happen if it opens elsewhere). The user may not know it can be undocked, but at least can resize or
254  // hide it if he/she needs more room for the main window.
255  const bool DOCKED_EQUALS_NOT_FLOATING = false;
256  Qt::DockWidgetArea area = (Qt::DockWidgetArea) settings.value (settingsTokenArea,
257  Qt::NoDockWidgetArea).toInt();
258 
259  if (area == Qt::NoDockWidgetArea) {
260 
261  addDockWidget (dockWidgetArea,
262  dockWidget); // Add on the right to prevent error message, then immediately make undocked
263  dockWidget->setFloating(DOCKED_EQUALS_NOT_FLOATING);
264  if (settings.contains (settingsTokenGeometry)) {
265  dockWidget->restoreGeometry (settings.value (settingsTokenGeometry).toByteArray());
266  }
267 
268  } else {
269 
270  addDockWidget (area,
271  dockWidget);
272 
273  }
274 }
275 
276 void MainWindow::applyZoomFactorAfterLoad()
277 {
278  ZoomFactor zoomFactor;
279  ZoomFactorInitial zoomFactorInitial = m_modelMainWindow.zoomFactorInitial();
280 
281  if (m_zoomMapFromInitial.contains (zoomFactorInitial)) {
282  zoomFactor = m_zoomMapFromInitial [zoomFactorInitial];
283  } else if (zoomFactorInitial == ZOOM_INITIAL_PREVIOUS) {
284  zoomFactor = currentZoomFactor ();
285  } else {
286  ENGAUGE_ASSERT (false);
287  zoomFactor = currentZoomFactor();
288  }
289 
290  slotViewZoom (zoomFactor);
291 }
292 
293 void MainWindow::closeEvent(QCloseEvent *event)
294 {
295  if (maybeSave()) {
296  settingsWrite ();
297  event->accept ();
298  } else {
299  event->ignore ();
300  }
301 }
302 
304 {
305  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileClose";
306 
307  setWindowModified (false); // Prevent popup query asking if changes should be saved
308  slotFileClose();
309 }
310 
311 void MainWindow::cmdFileExport(const QString &fileName)
312 {
313  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileExport";
314 
315  ExportToFile exportStrategy;
316  fileExport(fileName,
317  exportStrategy);
318 }
319 
320 void MainWindow::cmdFileImport(const QString &fileName)
321 {
322  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileImport";
323 
324  m_regressionFile = exportFilenameFromInputFilename (fileName);
325  fileImport (fileName,
326  IMPORT_TYPE_SIMPLE);
327 }
328 
329 void MainWindow::cmdFileOpen(const QString &fileName)
330 {
331  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::cmdFileOpen";
332 
333  m_regressionFile = exportFilenameFromInputFilename (fileName);
334  loadDocumentFile(fileName);
335 }
336 
338 {
339  // We do not check m_cmdMediator with ENGAUGE_CHECK_PTR since calling code is expected to deal with null pointer at startup
340  return m_cmdMediator;
341 }
342 
343 void MainWindow::createActions()
344 {
345  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActions";
346 
347  createActionsFile ();
348  createActionsEdit ();
349  createActionsDigitize ();
350  createActionsView ();
351  createActionsSettings ();
352  createActionsHelp ();
353 }
354 
355 void MainWindow::createActionsDigitize ()
356 {
357  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsDigitize";
358 
359  QPixmap pixmapAxis (DigitAxis_xpm);
360  QPixmap pixmapCurve (DigitCurve_xpm);
361  QPixmap pixmapColorPicker (DigitColorPicker_xpm);
362  QPixmap pixmapPointMatch (DigitPointMatch_xpm);
363  QPixmap pixmapScale (DigitScale_xpm);
364  QPixmap pixmapSegment (DigitSegment_xpm);
365  QPixmap pixmapSelect (DigitSelect_xpm);
366 
367  QIcon iconAxis (pixmapAxis);
368  QIcon iconCurve (pixmapCurve);
369  QIcon iconColorPicker (pixmapColorPicker);
370  QIcon iconPointMatch (pixmapPointMatch);
371  QIcon iconScale (pixmapScale);
372  QIcon iconSegment (pixmapSegment);
373  QIcon iconSelect (pixmapSelect);
374 
375  m_actionDigitizeSelect = new QAction (iconSelect, tr ("Select Tool"), this);
376  m_actionDigitizeSelect->setShortcut (QKeySequence (tr ("Shift+F2")));
377  m_actionDigitizeSelect->setCheckable (true);
378  m_actionDigitizeSelect->setStatusTip (tr ("Select points on screen."));
379  m_actionDigitizeSelect->setWhatsThis (tr ("Select\n\n"
380  "Select points on the screen."));
381  connect (m_actionDigitizeSelect, SIGNAL (triggered ()), this, SLOT (slotDigitizeSelect ()));
382 
383  m_actionDigitizeAxis = new QAction (iconAxis, tr ("Axis Point Tool"), this);
384  m_actionDigitizeAxis->setShortcut (QKeySequence (tr ("Shift+F3")));
385  m_actionDigitizeAxis->setCheckable (true);
386  m_actionDigitizeAxis->setStatusTip (tr ("Digitize axis points for a graph."));
387  m_actionDigitizeAxis->setWhatsThis (tr ("Digitize Axis Point\n\n"
388  "Digitizes an axis point for a graph by placing a new point at the cursor "
389  "after a mouse click. The coordinates of the axis point are then "
390  "entered. In a graph, three axis points are required to define "
391  "the graph coordinates."));
392  connect (m_actionDigitizeAxis, SIGNAL (triggered ()), this, SLOT (slotDigitizeAxis ()));
393 
394  m_actionDigitizeScale = new QAction (iconScale, tr ("Scale Bar Tool"), this);
395  m_actionDigitizeScale->setShortcut (QKeySequence (tr ("Shift+F8")));
396  m_actionDigitizeScale->setCheckable (true);
397  m_actionDigitizeScale->setStatusTip (tr ("Digitize scale bar for a map."));
398  m_actionDigitizeScale->setWhatsThis (tr ("Digitize Scale Bar\n\n"
399  "Digitize a scale bar for a map by clicking and dragging. The length of the "
400  "scale bar is then entered. In a map, the two endpoints of the scale "
401  "bar define the distances in graph coordinates.\n\n"
402  "Maps must be imported using Import (Advanced)."));
403  connect (m_actionDigitizeScale, SIGNAL (triggered ()), this, SLOT (slotDigitizeScale ()));
404 
405  m_actionDigitizeCurve = new QAction (iconCurve, tr ("Curve Point Tool"), this);
406  m_actionDigitizeCurve->setShortcut (QKeySequence (tr ("Shift+F4")));
407  m_actionDigitizeCurve->setCheckable (true);
408  m_actionDigitizeCurve->setStatusTip (tr ("Digitize curve points."));
409  m_actionDigitizeCurve->setWhatsThis (tr ("Digitize Curve Point\n\n"
410  "Digitizes a curve point by placing a new point at the cursor "
411  "after a mouse click. Use this mode to digitize points along curves "
412  "one by one.\n\n"
413  "New points will be assigned to the currently selected curve."));
414  connect (m_actionDigitizeCurve, SIGNAL (triggered ()), this, SLOT (slotDigitizeCurve ()));
415 
416  m_actionDigitizePointMatch = new QAction (iconPointMatch, tr ("Point Match Tool"), this);
417  m_actionDigitizePointMatch->setShortcut (QKeySequence (tr ("Shift+F5")));
418  m_actionDigitizePointMatch->setCheckable (true);
419  m_actionDigitizePointMatch->setStatusTip (tr ("Digitize curve points in a point plot by matching a point."));
420  m_actionDigitizePointMatch->setWhatsThis (tr ("Digitize Curve Points by Point Matching\n\n"
421  "Digitizes curve points in a point plot by finding points that match a sample point. The process "
422  "starts by selecting a representative sample point.\n\n"
423  "New points will be assigned to the currently selected curve."));
424  connect (m_actionDigitizePointMatch, SIGNAL (triggered ()), this, SLOT (slotDigitizePointMatch ()));
425 
426  m_actionDigitizeColorPicker = new QAction (iconColorPicker, tr ("Color Picker Tool"), this);
427  m_actionDigitizeColorPicker->setShortcut (QKeySequence (tr ("Shift+F6")));
428  m_actionDigitizeColorPicker->setCheckable (true);
429  m_actionDigitizeColorPicker->setStatusTip (tr ("Select color settings for filtering in Segment Fill mode."));
430  m_actionDigitizeColorPicker->setWhatsThis (tr ("Select color settings for Segment Fill filtering\n\n"
431  "Select a pixel along the currently selected curve. That pixel and its neighbors will "
432  "define the filter settings (color, brightness, and so on) of the currently selected curve "
433  "while in Segment Fill mode."));
434  connect (m_actionDigitizeColorPicker, SIGNAL (triggered ()), this, SLOT (slotDigitizeColorPicker ()));
435 
436  m_actionDigitizeSegment = new QAction (iconSegment, tr ("Segment Fill Tool"), this);
437  m_actionDigitizeSegment->setShortcut (QKeySequence (tr ("Shift+F7")));
438  m_actionDigitizeSegment->setCheckable (true);
439  m_actionDigitizeSegment->setStatusTip (tr ("Digitize curve points along a segment of a curve."));
440  m_actionDigitizeSegment->setWhatsThis (tr ("Digitize Curve Points With Segment Fill\n\n"
441  "Digitizes curve points by placing new points along the highlighted "
442  "segment under the cursor. Use this mode to quickly digitize multiple points along a "
443  "curve with a single click.\n\n"
444  "New points will be assigned to the currently selected curve."));
445  connect (m_actionDigitizeSegment, SIGNAL (triggered ()), this, SLOT (slotDigitizeSegment ()));
446 
447  m_groupDigitize = new QActionGroup (this);
448  m_groupDigitize->addAction (m_actionDigitizeSelect);
449  m_groupDigitize->addAction (m_actionDigitizeAxis);
450  m_groupDigitize->addAction (m_actionDigitizeScale);
451  m_groupDigitize->addAction (m_actionDigitizeCurve);
452  m_groupDigitize->addAction (m_actionDigitizePointMatch);
453  m_groupDigitize->addAction (m_actionDigitizeColorPicker);
454  m_groupDigitize->addAction (m_actionDigitizeSegment);
455 }
456 
457 void MainWindow::createActionsEdit ()
458 {
459  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsEdit";
460 
461  m_actionEditUndo = new QAction(tr ("&Undo"), this);
462  m_actionEditUndo->setShortcut (QKeySequence::Undo);
463  m_actionEditUndo->setStatusTip (tr ("Undo the last operation."));
464  m_actionEditUndo->setWhatsThis (tr ("Undo\n\n"
465  "Undo the last operation."));
466  // connect is applied when CmdMediator appears
467 
468  m_actionEditRedo = new QAction(tr ("&Redo"), this);
469  m_actionEditRedo->setShortcut (QKeySequence::Redo);
470  m_actionEditRedo->setStatusTip (tr ("Redo the last operation."));
471  m_actionEditRedo->setWhatsThis (tr ("Redo\n\n"
472  "Redo the last operation."));
473  // connect is applied when CmdMediator appears
474 
475  m_actionEditCut = new QAction (tr ("Cut"), this);
476  m_actionEditCut->setShortcut (QKeySequence::Cut);
477  m_actionEditCut->setStatusTip (tr ("Cuts the selected points and copies them to the clipboard."));
478  m_actionEditCut->setWhatsThis (tr ("Cut\n\n"
479  "Cuts the selected points and copies them to the clipboard."));
480  connect (m_actionEditCut, SIGNAL (triggered ()), this, SLOT (slotEditCut ()));
481 
482  m_actionEditCopy = new QAction (tr ("Copy"), this);
483  m_actionEditCopy->setShortcut (QKeySequence::Copy);
484  m_actionEditCopy->setStatusTip (tr ("Copies the selected points to the clipboard."));
485  m_actionEditCopy->setWhatsThis (tr ("Copy\n\n"
486  "Copies the selected points to the clipboard."));
487  connect (m_actionEditCopy, SIGNAL (triggered ()), this, SLOT (slotEditCopy ()));
488 
489  m_actionEditPaste = new QAction (tr ("Paste"), this);
490  m_actionEditPaste->setShortcut (QKeySequence::Paste);
491  m_actionEditPaste->setStatusTip (tr ("Pastes the selected points from the clipboard."));
492  m_actionEditPaste->setWhatsThis (tr ("Paste\n\n"
493  "Pastes the selected points from the clipboard. They will be assigned to the current curve."));
494  connect (m_actionEditPaste, SIGNAL (triggered ()), this, SLOT (slotEditPaste ()));
495 
496  m_actionEditDelete = new QAction (tr ("Delete"), this);
497  m_actionEditDelete->setShortcut (QKeySequence::Delete);
498  m_actionEditDelete->setStatusTip (tr ("Deletes the selected points, after copying them to the clipboard."));
499  m_actionEditDelete->setWhatsThis (tr ("Delete\n\n"
500  "Deletes the selected points, after copying them to the clipboard."));
501  connect (m_actionEditDelete, SIGNAL (triggered ()), this, SLOT (slotEditDelete ()));
502 
503  m_actionEditPasteAsNew = new QAction (tr ("Paste As New"), this);
504  m_actionEditPasteAsNew->setStatusTip (tr ("Pastes an image from the clipboard."));
505  m_actionEditPasteAsNew->setWhatsThis (tr ("Paste as New\n\n"
506  "Creates a new document by pasting an image from the clipboard."));
507  connect (m_actionEditPasteAsNew, SIGNAL (triggered ()), this, SLOT (slotEditPasteAsNew ()));
508 
509  m_actionEditPasteAsNewAdvanced = new QAction (tr ("Paste As New (Advanced)..."), this);
510  m_actionEditPasteAsNewAdvanced->setStatusTip (tr ("Pastes an image from the clipboard, in advanced mode."));
511  m_actionEditPasteAsNewAdvanced->setWhatsThis (tr ("Paste as New (Advanced)\n\n"
512  "Creates a new document by pasting an image from the clipboard, in advanced mode."));
513  connect (m_actionEditPasteAsNewAdvanced, SIGNAL (triggered ()), this, SLOT (slotEditPasteAsNewAdvanced ()));
514 }
515 
516 void MainWindow::createActionsFile ()
517 {
518  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsFile";
519 
520  m_actionImport = new QAction(tr ("&Import..."), this);
521  m_actionImport->setShortcut (tr ("Ctrl+I"));
522  m_actionImport->setStatusTip (tr ("Creates a new document by importing an simple image."));
523  m_actionImport->setWhatsThis (tr ("Import Image\n\n"
524  "Creates a new document by importing an image with a single coordinate system, "
525  "and axes both coordinates known.\n\n"
526  "For more complicated images with multiple coordinate systems, "
527  "and/or floating axes, Import (Advanced) is used instead."));
528  connect (m_actionImport, SIGNAL (triggered ()), this, SLOT (slotFileImport ()));
529 
530  m_actionImportAdvanced = new QAction(tr ("Import (Advanced)..."), this);
531  m_actionImportAdvanced->setStatusTip (tr ("Creates a new document by importing an image with support for advanced feaures."));
532  m_actionImportAdvanced->setWhatsThis (tr ("Import (Advanced)\n\n"
533  "Creates a new document by importing an image with support for advanced feaures. In "
534  "advanced mode, there can be multiple coordinate systems and/or floating axes."));
535  connect (m_actionImportAdvanced, SIGNAL (triggered ()), this, SLOT (slotFileImportAdvanced ()));
536 
537  m_actionImportImageReplace = new QAction (tr ("Import (Image Replace)..."), this);
538  m_actionImportImageReplace->setStatusTip (tr ("Imports a new image into the current document, replacing the existing image."));
539  m_actionImportImageReplace->setWhatsThis (tr ("Import (Image Replace)\n\n"
540  "Imports a new image into the current document. The existing image is replaced, "
541  "and all curves in the document are preserved. This operation is useful for applying "
542  "the axis points and other settings from an existing document to a different image."));
543  connect (m_actionImportImageReplace, SIGNAL (triggered ()), this, SLOT (slotFileImportImageReplace ()));
544 
545  m_actionOpen = new QAction(tr ("&Open..."), this);
546  m_actionOpen->setShortcut (QKeySequence::Open);
547  m_actionOpen->setStatusTip (tr ("Opens an existing document."));
548  m_actionOpen->setWhatsThis (tr ("Open Document\n\n"
549  "Opens an existing document."));
550  connect (m_actionOpen, SIGNAL (triggered ()), this, SLOT (slotFileOpen ()));
551 
552 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
553  for (unsigned int i = 0; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
554  QAction *recentFileAction = new QAction (this);
555  recentFileAction->setVisible (true);
556  connect (recentFileAction, SIGNAL (triggered ()), this, SLOT (slotRecentFileAction ()));
557  m_actionRecentFiles.append (recentFileAction);
558  }
559 #endif
560 
561  m_actionClose = new QAction(tr ("&Close"), this);
562  m_actionClose->setShortcut (QKeySequence::Close);
563  m_actionClose->setStatusTip (tr ("Closes the open document."));
564  m_actionClose->setWhatsThis (tr ("Close Document\n\n"
565  "Closes the open document."));
566  connect (m_actionClose, SIGNAL (triggered ()), this, SLOT (slotFileClose ()));
567 
568  m_actionSave = new QAction(tr ("&Save"), this);
569  m_actionSave->setShortcut (QKeySequence::Save);
570  m_actionSave->setStatusTip (tr ("Saves the current document."));
571  m_actionSave->setWhatsThis (tr ("Save Document\n\n"
572  "Saves the current document."));
573  connect (m_actionSave, SIGNAL (triggered ()), this, SLOT (slotFileSave ()));
574 
575  m_actionSaveAs = new QAction(tr ("Save As..."), this);
576  m_actionSaveAs->setShortcut (QKeySequence::SaveAs);
577  m_actionSaveAs->setStatusTip (tr ("Saves the current document under a new filename."));
578  m_actionSaveAs->setWhatsThis (tr ("Save Document As\n\n"
579  "Saves the current document under a new filename."));
580  connect (m_actionSaveAs, SIGNAL (triggered ()), this, SLOT (slotFileSaveAs ()));
581 
582  m_actionExport = new QAction (tr ("Export..."), this);
583  m_actionExport->setShortcut (tr ("Ctrl+E"));
584  m_actionExport->setStatusTip (tr ("Exports the current document into a text file."));
585  m_actionExport->setWhatsThis (tr ("Export Document\n\n"
586  "Exports the current document into a text file."));
587  connect (m_actionExport, SIGNAL (triggered ()), this, SLOT (slotFileExport ()));
588 
589  m_actionPrint = new QAction (tr ("&Print..."), this);
590  m_actionPrint->setShortcut (QKeySequence::Print);
591  m_actionPrint->setStatusTip (tr ("Print the current document."));
592  m_actionPrint->setWhatsThis (tr ("Print Document\n\n"
593  "Print the current document to a printer or file."));
594  connect (m_actionPrint, SIGNAL (triggered ()), this, SLOT (slotFilePrint ()));
595 
596  m_actionExit = new QAction(tr ("&Exit"), this);
597  m_actionExit->setShortcut (QKeySequence::Quit);
598  m_actionExit->setStatusTip (tr ("Quits the application."));
599  m_actionExit->setWhatsThis (tr ("Exit\n\n"
600  "Quits the application."));
601  connect (m_actionExit, SIGNAL (triggered ()), this, SLOT (close ()));
602 }
603 
604 void MainWindow::createActionsHelp ()
605 {
606  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsHelp";
607 
608  m_actionHelpChecklistGuideWizard = new QAction (tr ("Checklist Guide Wizard"), this);
609  m_actionHelpChecklistGuideWizard->setCheckable (true);
610  m_actionHelpChecklistGuideWizard->setStatusTip (tr ("Open Checklist Guide Wizard during import to define digitizing steps"));
611  m_actionHelpChecklistGuideWizard->setWhatsThis (tr ("Checklist Guide Wizard\n\n"
612  "Use Checklist Guide Wizard during import to generate a checklist of steps "
613  "for the imported document"));
614 
615  m_actionHelpWhatsThis = QWhatsThis::createAction(this);
616  m_actionHelpWhatsThis->setShortcut (QKeySequence::WhatsThis);
617 
618  m_actionHelpTutorial = new QAction (tr ("Tutorial"), this);
619  m_actionHelpTutorial->setStatusTip (tr ("Play tutorial showing steps for digitizing curves"));
620  m_actionHelpTutorial->setWhatsThis (tr ("Tutorial\n\n"
621  "Play tutorial showing steps for digitizing points from curves drawn with lines "
622  "and/or point"));
623  connect (m_actionHelpTutorial, SIGNAL (triggered ()), this, SLOT (slotHelpTutorial()));
624 
625 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
626  m_actionHelpHelp = new QAction (tr ("Help"), this);
627  m_actionHelpHelp->setShortcut (QKeySequence::HelpContents);
628  m_actionHelpHelp->setStatusTip (tr ("Help documentation"));
629  m_actionHelpHelp->setWhatsThis (tr ("Help Documentation\n\n"
630  "Searchable help documentation"));
631  // This action gets connected directly to the QDockWidget when that is created
632 #endif
633 
634  m_actionHelpAbout = new QAction(tr ("About Engauge"), this);
635  m_actionHelpAbout->setStatusTip (tr ("About the application."));
636  m_actionHelpAbout->setWhatsThis (tr ("About Engauge\n\nAbout the application."));
637  connect (m_actionHelpAbout, SIGNAL (triggered ()), this, SLOT (slotHelpAbout ()));
638 }
639 
640 void MainWindow::createActionsSettings ()
641 {
642  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsSettings";
643 
644  m_actionSettingsCoords = new QAction (tr ("Coordinates..."), this);
645  m_actionSettingsCoords->setStatusTip (tr ("Edit Coordinate settings."));
646  m_actionSettingsCoords->setWhatsThis (tr ("Coordinate Settings\n\n"
647  "Coordinate settings determine how the graph coordinates are mapped to the pixels in the image"));
648  connect (m_actionSettingsCoords, SIGNAL (triggered ()), this, SLOT (slotSettingsCoords ()));
649 
650  m_actionSettingsCurveAddRemove = new QAction (tr ("Add/Remove Curve..."), this);
651  m_actionSettingsCurveAddRemove->setStatusTip (tr ("Add or Remove Curves."));
652  m_actionSettingsCurveAddRemove->setWhatsThis (tr ("Add/Remove Curve\n\n"
653  "Add/Remove Curve settings control which curves are included in the current document"));
654  connect (m_actionSettingsCurveAddRemove, SIGNAL (triggered ()), this, SLOT (slotSettingsCurveAddRemove ()));
655 
656  m_actionSettingsCurveProperties = new QAction (tr ("Curve Properties..."), this);
657  m_actionSettingsCurveProperties->setStatusTip (tr ("Edit Curve Properties settings."));
658  m_actionSettingsCurveProperties->setWhatsThis (tr ("Curve Properties Settings\n\n"
659  "Curves properties settings determine how each curve appears"));
660  connect (m_actionSettingsCurveProperties, SIGNAL (triggered ()), this, SLOT (slotSettingsCurveProperties ()));
661 
662  m_actionSettingsDigitizeCurve = new QAction (tr ("Digitize Curve..."), this);
663  m_actionSettingsDigitizeCurve->setStatusTip (tr ("Edit Digitize Axis and Graph Curve settings."));
664  m_actionSettingsDigitizeCurve->setWhatsThis (tr ("Digitize Axis and Graph Curve Settings\n\n"
665  "Digitize Curve settings determine how points are digitized in Digitize Axis Point and "
666  "Digitize Graph Point modes"));
667  connect (m_actionSettingsDigitizeCurve, SIGNAL (triggered ()), this, SLOT (slotSettingsDigitizeCurve ()));
668 
669  m_actionSettingsExport = new QAction (tr ("Export Format..."), this);
670  m_actionSettingsExport->setStatusTip (tr ("Edit Export Format settings."));
671  m_actionSettingsExport->setWhatsThis (tr ("Export Format Settings\n\n"
672  "Export format settings affect how exported files are formatted"));
673  connect (m_actionSettingsExport, SIGNAL (triggered ()), this, SLOT (slotSettingsExportFormat ()));
674 
675  m_actionSettingsColorFilter = new QAction (tr ("Color Filter..."), this);
676  m_actionSettingsColorFilter->setStatusTip (tr ("Edit Color Filter settings."));
677  m_actionSettingsColorFilter->setWhatsThis (tr ("Color Filter Settings\n\n"
678  "Color filtering simplifies the graphs for easier Point Matching and Segment Filling"));
679  connect (m_actionSettingsColorFilter, SIGNAL (triggered ()), this, SLOT (slotSettingsColorFilter ()));
680 
681  m_actionSettingsAxesChecker = new QAction (tr ("Axes Checker..."), this);
682  m_actionSettingsAxesChecker->setStatusTip (tr ("Edit Axes Checker settings."));
683  m_actionSettingsAxesChecker->setWhatsThis (tr ("Axes Checker Settings\n\n"
684  "Axes checker can reveal any axis point mistakes, which are otherwise hard to find."));
685  connect (m_actionSettingsAxesChecker, SIGNAL (triggered ()), this, SLOT (slotSettingsAxesChecker ()));
686 
687  m_actionSettingsGridDisplay = new QAction (tr ("Grid Line Display..."), this);
688  m_actionSettingsGridDisplay->setStatusTip (tr ("Edit Grid Line Display settings."));
689  m_actionSettingsGridDisplay->setWhatsThis (tr ("Grid Line Display Settings\n\n"
690  "Grid lines displayed on the graph can provide more accuracy than the Axis Checker, for distorted graphs. "
691  "In a distorted graph, the grid lines can be used to adjust the axis points for more accuracy in different regions."));
692  connect (m_actionSettingsGridDisplay, SIGNAL (triggered ()), this, SLOT (slotSettingsGridDisplay ()));
693 
694  m_actionSettingsGridRemoval = new QAction (tr ("Grid Line Removal..."), this);
695  m_actionSettingsGridRemoval->setStatusTip (tr ("Edit Grid Line Removal settings."));
696  m_actionSettingsGridRemoval->setWhatsThis (tr ("Grid Line Removal Settings\n\n"
697  "Grid line removal isolates curve lines for easier Point Matching and Segment Filling, when "
698  "Color Filtering is not able to separate grid lines from curve lines."));
699  connect (m_actionSettingsGridRemoval, SIGNAL (triggered ()), this, SLOT (slotSettingsGridRemoval ()));
700 
701  m_actionSettingsPointMatch = new QAction (tr ("Point Match..."), this);
702  m_actionSettingsPointMatch->setStatusTip (tr ("Edit Point Match settings."));
703  m_actionSettingsPointMatch->setWhatsThis (tr ("Point Match Settings\n\n"
704  "Point match settings determine how points are matched while in Point Match mode"));
705  connect (m_actionSettingsPointMatch, SIGNAL (triggered ()), this, SLOT (slotSettingsPointMatch ()));
706 
707  m_actionSettingsSegments = new QAction (tr ("Segment Fill..."), this);
708  m_actionSettingsSegments->setStatusTip (tr ("Edit Segment Fill settings."));
709  m_actionSettingsSegments->setWhatsThis (tr ("Segment Fill Settings\n\n"
710  "Segment fill settings determine how points are generated in the Segment Fill mode"));
711  connect (m_actionSettingsSegments, SIGNAL (triggered ()), this, SLOT (slotSettingsSegments ()));
712 
713  m_actionSettingsGeneral = new QAction (tr ("General..."), this);
714  m_actionSettingsGeneral->setStatusTip (tr ("Edit General settings."));
715  m_actionSettingsGeneral->setWhatsThis (tr ("General Settings\n\n"
716  "General settings are document-specific settings that affect multiple modes. For example, the cursor size setting affects "
717  "both Color Picker and Point Match modes"));
718  connect (m_actionSettingsGeneral, SIGNAL (triggered ()), this, SLOT (slotSettingsGeneral ()));
719 
720  m_actionSettingsMainWindow = new QAction (tr ("Main Window..."), this);
721  m_actionSettingsMainWindow->setEnabled (true);
722  m_actionSettingsMainWindow->setStatusTip (tr ("Edit Main Window settings."));
723  m_actionSettingsMainWindow->setWhatsThis (tr ("Main Window Settings\n\n"
724  "Main window settings affect the user interface and are not specific to any document"));
725  connect (m_actionSettingsMainWindow, SIGNAL (triggered ()), this, SLOT (slotSettingsMainWindow ()));
726 }
727 
728 void MainWindow::createActionsView ()
729 {
730  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createActionsView";
731 
732  m_actionViewBackground = new QAction (tr ("Background Toolbar"), this);
733  m_actionViewBackground->setCheckable (true);
734  m_actionViewBackground->setChecked (true);
735  m_actionViewBackground->setStatusTip (tr ("Show or hide the background toolbar."));
736  m_actionViewBackground->setWhatsThis (tr ("View Background ToolBar\n\n"
737  "Show or hide the background toolbar"));
738  connect (m_actionViewBackground, SIGNAL (triggered ()), this, SLOT (slotViewToolBarBackground ()));
739 
740  m_actionViewChecklistGuide = new QAction (tr ("Checklist Guide Toolbar"), this);
741  m_actionViewChecklistGuide->setCheckable (true);
742  m_actionViewChecklistGuide->setChecked (false);
743  m_actionViewChecklistGuide->setStatusTip (tr ("Show or hide the checklist guide."));
744  m_actionViewChecklistGuide->setWhatsThis (tr ("View Checklist Guide\n\n"
745  "Show or hide the checklist guide"));
746  connect (m_actionViewChecklistGuide, SIGNAL (changed ()), this, SLOT (slotViewToolBarChecklistGuide()));
747 
748  m_actionViewFittingWindow = new QAction (tr ("Curve Fitting Window"), this);
749  m_actionViewFittingWindow->setCheckable (true);
750  m_actionViewFittingWindow->setChecked (false);
751  m_actionViewFittingWindow->setStatusTip (tr ("Show or hide the curve fitting window."));
752  m_actionViewFittingWindow->setWhatsThis (tr ("View Curve Fitting Window\n\n"
753  "Show or hide the curve fitting window"));
754  connect (m_actionViewFittingWindow, SIGNAL (changed ()), this, SLOT (slotViewToolBarFittingWindow()));
755 
756  m_actionViewGeometryWindow = new QAction (tr ("Geometry Window"), this);
757  m_actionViewGeometryWindow->setCheckable (true);
758  m_actionViewGeometryWindow->setChecked (false);
759  m_actionViewGeometryWindow->setStatusTip (tr ("Show or hide the geometry window."));
760  m_actionViewGeometryWindow->setWhatsThis (tr ("View Geometry Window\n\n"
761  "Show or hide the geometry window"));
762  connect (m_actionViewGeometryWindow, SIGNAL (changed ()), this, SLOT (slotViewToolBarGeometryWindow()));
763 
764  m_actionViewDigitize = new QAction (tr ("Digitizing Tools Toolbar"), this);
765  m_actionViewDigitize->setCheckable (true);
766  m_actionViewDigitize->setChecked (true);
767  m_actionViewDigitize->setStatusTip (tr ("Show or hide the digitizing tools toolbar."));
768  m_actionViewDigitize->setWhatsThis (tr ("View Digitizing Tools ToolBar\n\n"
769  "Show or hide the digitizing tools toolbar"));
770  connect (m_actionViewDigitize, SIGNAL (triggered ()), this, SLOT (slotViewToolBarDigitize()));
771 
772  m_actionViewSettingsViews = new QAction (tr ("Settings Views Toolbar"), this);
773  m_actionViewSettingsViews->setCheckable (true);
774  m_actionViewSettingsViews->setChecked (true);
775  m_actionViewSettingsViews->setStatusTip (tr ("Show or hide the settings views toolbar."));
776  m_actionViewSettingsViews->setWhatsThis (tr ("View Settings Views ToolBar\n\n"
777  "Show or hide the settings views toolbar. These views graphically show the "
778  "most important settings."));
779  connect (m_actionViewSettingsViews, SIGNAL (triggered ()), this, SLOT (slotViewToolBarSettingsViews()));
780 
781  m_actionViewCoordSystem = new QAction (tr ("Coordinate System Toolbar"), this);
782  m_actionViewCoordSystem->setCheckable (true);
783  m_actionViewCoordSystem->setChecked (false);
784  m_actionViewCoordSystem->setStatusTip (tr ("Show or hide the coordinate system toolbar."));
785  m_actionViewCoordSystem->setWhatsThis (tr ("View Coordinate Systems ToolBar\n\n"
786  "Show or hide the coordinate system selection toolbar. This toolbar is used "
787  "to select the current coordinate system when the document has multiple "
788  "coordinate systems. This toolbar is also used to view and print all coordinate "
789  "systems.\n\n"
790  "This toolbar is disabled when there is only one coordinate system."));
791  connect (m_actionViewCoordSystem, SIGNAL (triggered ()), this, SLOT (slotViewToolBarCoordSystem()));
792 
793  m_actionViewToolTips = new QAction (tr ("Tool Tips"), this);
794  m_actionViewToolTips->setCheckable (true);
795  m_actionViewToolTips->setChecked (true);
796  m_actionViewToolTips->setStatusTip (tr ("Show or hide the tool tips."));
797  m_actionViewToolTips->setWhatsThis (tr ("View Tool Tips\n\n"
798  "Show or hide the tool tips"));
799  connect (m_actionViewToolTips, SIGNAL (triggered ()), this, SLOT (slotViewToolTips()));
800 
801  m_actionViewGridLines = new QAction (tr ("Grid Lines"), this);
802  m_actionViewGridLines->setCheckable (true);
803  m_actionViewGridLines->setChecked (false);
804  m_actionViewGridLines->setStatusTip (tr ("Show or hide grid lines."));
805  m_actionViewGridLines->setWhatsThis (tr ("View Grid Lines\n\n"
806  "Show or hide grid lines that are added for accurate adjustments of the axes points, "
807  "which can improve accuracy in distorted graphs"));
808  connect (m_actionViewGridLines, SIGNAL (triggered ()), this, SLOT (slotViewGridLines()));
809 
810  m_actionViewBackgroundNone = new QAction (tr ("No Background"), this);
811  m_actionViewBackgroundNone->setCheckable (true);
812  m_actionViewBackgroundNone->setStatusTip (tr ("Do not show the image underneath the points."));
813  m_actionViewBackgroundNone->setWhatsThis (tr ("No Background\n\n"
814  "No image is shown so points are easier to see"));
815 
816  m_actionViewBackgroundOriginal = new QAction (tr ("Show Original Image"), this);
817  m_actionViewBackgroundOriginal->setCheckable (true);
818  m_actionViewBackgroundOriginal->setStatusTip (tr ("Show the original image underneath the points."));
819  m_actionViewBackgroundOriginal->setWhatsThis (tr ("Show Original Image\n\n"
820  "Show the original image underneath the points"));
821 
822  m_actionViewBackgroundFiltered = new QAction (tr ("Show Filtered Image"), this);
823  m_actionViewBackgroundFiltered->setCheckable (true);
824  m_actionViewBackgroundFiltered->setChecked (true);
825  m_actionViewBackgroundFiltered->setStatusTip (tr ("Show the filtered image underneath the points."));
826  m_actionViewBackgroundFiltered->setWhatsThis (tr ("Show Filtered Image\n\n"
827  "Show the filtered image underneath the points.\n\n"
828  "The filtered image is created from the original image according to the "
829  "Filter preferences so unimportant information is hidden and important "
830  "information is emphasized"));
831 
832  m_actionViewCurvesNone = new QAction (tr ("Hide All Curves"), this);
833  m_actionViewCurvesNone->setCheckable (true);
834  m_actionViewCurvesNone->setStatusTip (tr ("Hide all digitized curves."));
835  m_actionViewCurvesNone->setWhatsThis (tr ("Hide All Curves\n\n"
836  "No axis points or digitized graph curves are shown so the image is easier to see."));
837 
838  m_actionViewCurvesSelected = new QAction (tr ("Show Selected Curve"), this);
839  m_actionViewCurvesSelected->setCheckable (true);
840  m_actionViewCurvesSelected->setStatusTip (tr ("Show only the currently selected curve."));
841  m_actionViewCurvesSelected->setWhatsThis (tr ("Show Selected Curve\n\n"
842  "Show only the digitized points and line that belong to the currently selected curve."));
843 
844  m_actionViewCurvesAll = new QAction (tr ("Show All Curves"), this);
845  m_actionViewCurvesAll->setCheckable (true);
846  m_actionViewCurvesAll->setChecked (true);
847  m_actionViewCurvesAll->setStatusTip (tr ("Show all curves."));
848  m_actionViewCurvesAll->setWhatsThis (tr ("Show All Curves\n\n"
849  "Show all digitized axis points and graph curves"));
850 
851  m_groupBackground = new QActionGroup(this);
852  m_groupBackground->addAction (m_actionViewBackgroundNone);
853  m_groupBackground->addAction (m_actionViewBackgroundOriginal);
854  m_groupBackground->addAction (m_actionViewBackgroundFiltered);
855  connect (m_groupBackground, SIGNAL(triggered (QAction*)), this, SLOT (slotViewGroupBackground(QAction*)));
856 
857  m_groupCurves = new QActionGroup(this);
858  m_groupCurves->addAction (m_actionViewCurvesNone);
859  m_groupCurves->addAction (m_actionViewCurvesSelected);
860  m_groupCurves->addAction (m_actionViewCurvesAll);
861  connect (m_groupCurves, SIGNAL(triggered (QAction*)), this, SLOT (slotViewGroupCurves(QAction*)));
862 
863  m_actionStatusNever = new QAction (tr ("Hide Always"), this);
864  m_actionStatusNever->setCheckable(true);
865  m_actionStatusNever->setStatusTip (tr ("Always hide the status bar."));
866  m_actionStatusNever->setWhatsThis (tr ("Hide the status bar. No temporary status or feedback messages will appear."));
867 
868  m_actionStatusTemporary = new QAction (tr ("Show Temporary Messages"), this);
869  m_actionStatusTemporary->setCheckable(true);
870  m_actionStatusTemporary->setStatusTip (tr ("Hide the status bar except when display temporary messages."));
871  m_actionStatusTemporary->setWhatsThis (tr ("Hide the status bar, except when displaying temporary status and feedback messages."));
872 
873  m_actionStatusAlways = new QAction (tr ("Show Always"), this);
874  m_actionStatusAlways->setCheckable(true);
875  m_actionStatusAlways->setStatusTip (tr ("Always show the status bar."));
876  m_actionStatusAlways->setWhatsThis (tr ("Show the status bar. Besides displaying temporary status and feedback messages, "
877  "the status bar also displays information about the cursor position."));
878 
879  m_groupStatus = new QActionGroup(this);
880  m_groupStatus->addAction (m_actionStatusNever);
881  m_groupStatus->addAction (m_actionStatusTemporary);
882  m_groupStatus->addAction (m_actionStatusAlways);
883  connect (m_groupStatus, SIGNAL (triggered (QAction*)), this, SLOT (slotViewGroupStatus(QAction*)));
884 
885  m_actionZoomOut = new QAction (tr ("Zoom Out"), this);
886  m_actionZoomOut->setStatusTip (tr ("Zoom out"));
887  // setShortCut is called by updateSettingsMainWindow
888  connect (m_actionZoomOut, SIGNAL (triggered ()), this, SLOT (slotViewZoomOut ()));
889 
890  m_actionZoomIn = new QAction (tr ("Zoom In"), this);
891  m_actionZoomIn->setStatusTip (tr ("Zoom in"));
892  // setShortCut is called by updateSettingsMainWindow
893  connect (m_actionZoomIn, SIGNAL (triggered ()), this, SLOT (slotViewZoomIn ()));
894 
895  m_mapperZoomFactor = new QSignalMapper (this);
896  connect (m_mapperZoomFactor, SIGNAL (mapped (int)), this, SLOT (slotViewZoomFactorInt (int)));
897 
898  m_actionZoom16To1 = new QAction (tr ("16:1 (1600%)"), this);
899  m_actionZoom16To1->setCheckable (true);
900  m_actionZoom16To1->setStatusTip (tr ("Zoom 16:1"));
901  connect (m_actionZoom16To1, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
902  m_mapperZoomFactor->setMapping (m_actionZoom16To1, ZOOM_16_TO_1);
903 
904  m_actionZoom16To1Farther = new QAction (tr ("16:1 farther (1270%)"), this);
905  m_actionZoom16To1Farther->setCheckable (true);
906  m_actionZoom16To1Farther->setStatusTip (tr ("Zoom 12.7:1"));
907  connect (m_actionZoom16To1Farther, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
908  m_mapperZoomFactor->setMapping (m_actionZoom16To1Farther, ZOOM_16_TO_1_FARTHER);
909 
910  m_actionZoom8To1Closer = new QAction (tr ("8:1 closer (1008%)"), this);
911  m_actionZoom8To1Closer->setCheckable (true);
912  m_actionZoom8To1Closer->setStatusTip (tr ("Zoom 10.08:1"));
913  connect (m_actionZoom8To1Closer, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
914  m_mapperZoomFactor->setMapping (m_actionZoom8To1Closer, ZOOM_8_TO_1_CLOSER);
915 
916  m_actionZoom8To1 = new QAction (tr ("8:1 (800%)"), this);
917  m_actionZoom8To1->setCheckable (true);
918  m_actionZoom8To1->setStatusTip (tr ("Zoom 8:1"));
919  connect (m_actionZoom8To1, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
920  m_mapperZoomFactor->setMapping (m_actionZoom8To1, ZOOM_8_TO_1);
921 
922  m_actionZoom8To1Farther = new QAction (tr ("8:1 farther (635%)"), this);
923  m_actionZoom8To1Farther->setCheckable (true);
924  m_actionZoom8To1Farther->setStatusTip (tr ("Zoom 6.35:1"));
925  connect (m_actionZoom8To1Farther, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
926  m_mapperZoomFactor->setMapping (m_actionZoom8To1Farther, ZOOM_8_TO_1_FARTHER);
927 
928  m_actionZoom4To1Closer = new QAction (tr ("4:1 closer (504%)"), this);
929  m_actionZoom4To1Closer->setCheckable (true);
930  m_actionZoom4To1Closer->setStatusTip (tr ("Zoom 5.04:1"));
931  connect (m_actionZoom4To1Closer, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
932  m_mapperZoomFactor->setMapping (m_actionZoom4To1Closer, ZOOM_4_TO_1_CLOSER);
933 
934  m_actionZoom4To1 = new QAction (tr ("4:1 (400%)"), this);
935  m_actionZoom4To1->setCheckable (true);
936  m_actionZoom4To1->setStatusTip (tr ("Zoom 4:1"));
937  connect (m_actionZoom4To1, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
938  m_mapperZoomFactor->setMapping (m_actionZoom4To1, ZOOM_4_TO_1);
939 
940  m_actionZoom4To1Farther = new QAction (tr ("4:1 farther (317%)"), this);
941  m_actionZoom4To1Farther->setCheckable (true);
942  m_actionZoom4To1Farther->setStatusTip (tr ("Zoom 3.17:1"));
943  connect (m_actionZoom4To1Farther, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
944  m_mapperZoomFactor->setMapping (m_actionZoom4To1Farther, ZOOM_4_TO_1_FARTHER);
945 
946  m_actionZoom2To1Closer = new QAction (tr ("2:1 closer (252%)"), this);
947  m_actionZoom2To1Closer->setCheckable (true);
948  m_actionZoom2To1Closer->setStatusTip (tr ("Zoom 2.52:1"));
949  connect (m_actionZoom2To1Closer, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
950  m_mapperZoomFactor->setMapping (m_actionZoom2To1Closer, ZOOM_2_TO_1_CLOSER);
951 
952  m_actionZoom2To1 = new QAction (tr ("2:1 (200%)"), this);
953  m_actionZoom2To1->setCheckable (true);
954  m_actionZoom2To1->setStatusTip (tr ("Zoom 2:1"));
955  connect (m_actionZoom2To1, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
956  m_mapperZoomFactor->setMapping (m_actionZoom2To1, ZOOM_2_TO_1);
957 
958  m_actionZoom2To1Farther = new QAction (tr ("2:1 farther (159%)"), this);
959  m_actionZoom2To1Farther->setCheckable (true);
960  m_actionZoom2To1Farther->setStatusTip (tr ("Zoom 1.59:1"));
961  connect (m_actionZoom2To1Farther, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
962  m_mapperZoomFactor->setMapping (m_actionZoom2To1Farther, ZOOM_2_TO_1_FARTHER);
963 
964  m_actionZoom1To1Closer = new QAction (tr ("1:1 closer (126%)"), this);
965  m_actionZoom1To1Closer->setCheckable (true);
966  m_actionZoom1To1Closer->setChecked (true);
967  m_actionZoom1To1Closer->setStatusTip (tr ("Zoom 1.3:1"));
968  connect (m_actionZoom1To1Closer, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
969  m_mapperZoomFactor->setMapping (m_actionZoom1To1Closer, ZOOM_1_TO_1_CLOSER);
970 
971  m_actionZoom1To1 = new QAction (tr ("1:1 (100%)"), this);
972  m_actionZoom1To1->setCheckable (true);
973  m_actionZoom1To1->setChecked (true);
974  m_actionZoom1To1->setStatusTip (tr ("Zoom 1:1"));
975  connect (m_actionZoom1To1, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
976  m_mapperZoomFactor->setMapping (m_actionZoom1To1, ZOOM_1_TO_1);
977 
978  m_actionZoom1To1Farther = new QAction (tr ("1:1 farther (79%)"), this);
979  m_actionZoom1To1Farther->setCheckable (true);
980  m_actionZoom1To1Farther->setChecked (true);
981  m_actionZoom1To1Farther->setStatusTip (tr ("Zoom 0.8:1"));
982  connect (m_actionZoom1To1Farther, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
983  m_mapperZoomFactor->setMapping (m_actionZoom1To1Farther, ZOOM_1_TO_1_FARTHER);
984 
985  m_actionZoom1To2Closer = new QAction (tr ("1:2 closer (63%)"), this);
986  m_actionZoom1To2Closer->setCheckable (true);
987  m_actionZoom1To2Closer->setStatusTip (tr ("Zoom 1.3:2"));
988  connect (m_actionZoom1To2Closer, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
989  m_mapperZoomFactor->setMapping (m_actionZoom1To2Closer, ZOOM_1_TO_2_CLOSER);
990 
991  m_actionZoom1To2 = new QAction (tr ("1:2 (50%)"), this);
992  m_actionZoom1To2->setCheckable (true);
993  m_actionZoom1To2->setStatusTip (tr ("Zoom 1:2"));
994  connect (m_actionZoom1To2, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
995  m_mapperZoomFactor->setMapping (m_actionZoom1To2, ZOOM_1_TO_2);
996 
997  m_actionZoom1To2Farther = new QAction (tr ("1:2 farther (40%)"), this);
998  m_actionZoom1To2Farther->setCheckable (true);
999  m_actionZoom1To2Farther->setStatusTip (tr ("Zoom 0.8:2"));
1000  connect (m_actionZoom1To2Farther, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1001  m_mapperZoomFactor->setMapping (m_actionZoom1To2Farther, ZOOM_1_TO_2_FARTHER);
1002 
1003  m_actionZoom1To4Closer = new QAction (tr ("1:4 closer (31%)"), this);
1004  m_actionZoom1To4Closer->setCheckable (true);
1005  m_actionZoom1To4Closer->setStatusTip (tr ("Zoom 1.3:4"));
1006  connect (m_actionZoom1To4Closer, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1007  m_mapperZoomFactor->setMapping (m_actionZoom1To4Closer, ZOOM_1_TO_4_CLOSER);
1008 
1009  m_actionZoom1To4 = new QAction (tr ("1:4 (25%)"), this);
1010  m_actionZoom1To4->setCheckable (true);
1011  m_actionZoom1To4->setStatusTip (tr ("Zoom 1:4"));
1012  connect (m_actionZoom1To4, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1013  m_mapperZoomFactor->setMapping (m_actionZoom1To4, ZOOM_1_TO_4);
1014 
1015  m_actionZoom1To4Farther = new QAction (tr ("1:4 farther (20%)"), this);
1016  m_actionZoom1To4Farther->setCheckable (true);
1017  m_actionZoom1To4Farther->setStatusTip (tr ("Zoom 0.8:4"));
1018  connect (m_actionZoom1To4Farther, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1019  m_mapperZoomFactor->setMapping (m_actionZoom1To4Farther, ZOOM_1_TO_4_FARTHER);
1020 
1021  m_actionZoom1To8Closer = new QAction (tr ("1:8 closer (12.5%)"), this);
1022  m_actionZoom1To8Closer->setCheckable (true);
1023  m_actionZoom1To8Closer->setStatusTip (tr ("Zoom 1:8"));
1024  connect (m_actionZoom1To8Closer, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1025  m_mapperZoomFactor->setMapping (m_actionZoom1To8Closer, ZOOM_1_TO_8_CLOSER);
1026 
1027  m_actionZoom1To8 = new QAction (tr ("1:8 (12.5%)"), this);
1028  m_actionZoom1To8->setCheckable (true);
1029  m_actionZoom1To8->setStatusTip (tr ("Zoom 1:8"));
1030  connect (m_actionZoom1To8, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1031  m_mapperZoomFactor->setMapping (m_actionZoom1To8, ZOOM_1_TO_8);
1032 
1033  m_actionZoom1To8Farther = new QAction (tr ("1:8 farther (10%)"), this);
1034  m_actionZoom1To8Farther->setCheckable (true);
1035  m_actionZoom1To8Farther->setStatusTip (tr ("Zoom 0.8:8"));
1036  connect (m_actionZoom1To8Farther, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1037  m_mapperZoomFactor->setMapping (m_actionZoom1To8Farther, ZOOM_1_TO_8_FARTHER);
1038 
1039  m_actionZoom1To16Closer = new QAction (tr ("1:16 closer (8%)"), this);
1040  m_actionZoom1To16Closer->setCheckable (true);
1041  m_actionZoom1To16Closer->setStatusTip (tr ("Zoom 1.3:16"));
1042  connect (m_actionZoom1To16Closer, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1043  m_mapperZoomFactor->setMapping (m_actionZoom1To16Closer, ZOOM_1_TO_16_CLOSER);
1044 
1045  m_actionZoom1To16 = new QAction (tr ("1:16 (6.25%)"), this);
1046  m_actionZoom1To16->setCheckable (true);
1047  m_actionZoom1To16->setStatusTip (tr ("Zoom 1:16"));
1048  connect (m_actionZoom1To16, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1049  m_mapperZoomFactor->setMapping (m_actionZoom1To16, ZOOM_1_TO_16);
1050 
1051  m_actionZoomFill = new QAction (tr ("Fill"), this);
1052  m_actionZoomFill->setCheckable (true);
1053  m_actionZoomFill->setStatusTip (tr ("Zoom with stretching to fill window"));
1054  connect (m_actionZoomFill, SIGNAL (triggered ()), m_mapperZoomFactor, SLOT (map ()));
1055  m_mapperZoomFactor->setMapping (m_actionZoomFill, ZOOM_FILL);
1056 
1057  m_groupZoom = new QActionGroup (this);
1058  m_groupZoom->addAction (m_actionZoom16To1);
1059  m_groupZoom->addAction (m_actionZoom16To1Farther);
1060  m_groupZoom->addAction (m_actionZoom8To1Closer);
1061  m_groupZoom->addAction (m_actionZoom8To1);
1062  m_groupZoom->addAction (m_actionZoom8To1Farther);
1063  m_groupZoom->addAction (m_actionZoom4To1Closer);
1064  m_groupZoom->addAction (m_actionZoom4To1);
1065  m_groupZoom->addAction (m_actionZoom4To1Farther);
1066  m_groupZoom->addAction (m_actionZoom2To1Closer);
1067  m_groupZoom->addAction (m_actionZoom2To1);
1068  m_groupZoom->addAction (m_actionZoom2To1Farther);
1069  m_groupZoom->addAction (m_actionZoom1To1Closer);
1070  m_groupZoom->addAction (m_actionZoom1To1);
1071  m_groupZoom->addAction (m_actionZoom1To1Farther);
1072  m_groupZoom->addAction (m_actionZoom1To2Closer);
1073  m_groupZoom->addAction (m_actionZoom1To2);
1074  m_groupZoom->addAction (m_actionZoom1To2Farther);
1075  m_groupZoom->addAction (m_actionZoom1To4Closer);
1076  m_groupZoom->addAction (m_actionZoom1To4);
1077  m_groupZoom->addAction (m_actionZoom1To4Farther);
1078  m_groupZoom->addAction (m_actionZoom1To8Closer);
1079  m_groupZoom->addAction (m_actionZoom1To8);
1080  m_groupZoom->addAction (m_actionZoom1To8Farther);
1081  m_groupZoom->addAction (m_actionZoom1To16Closer);
1082  m_groupZoom->addAction (m_actionZoom1To16);
1083  m_groupZoom->addAction (m_actionZoomFill);
1084 }
1085 
1086 void MainWindow::createCentralWidget ()
1087 {
1088  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createCentralWidget";
1089 
1090  QWidget *widget = new QWidget;
1091  setCentralWidget (widget);
1092  m_layout = new QVBoxLayout;
1093  widget->setLayout (m_layout);
1094 }
1095 
1096 void MainWindow::createCommandStackShadow ()
1097 {
1098  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createCommandStackShadow";
1099 
1100  m_cmdStackShadow = new CmdStackShadow;
1101 }
1102 
1103 void MainWindow::createDockableWidgets ()
1104 {
1105  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createDockableWidgets";
1106 
1107  // Checklist guide starts out hidden. It will be positioned in settingsRead
1108  m_dockChecklistGuide = new ChecklistGuide (this);
1109  connect (m_dockChecklistGuide, SIGNAL (signalChecklistClosed()), this, SLOT (slotChecklistClosed()));
1110 
1111  // Fitting window starts out hidden since there is nothing to show initially. It will be positioned in settingsRead
1112  m_dockFittingWindow = new FittingWindow (this);
1113  connect (m_dockFittingWindow, SIGNAL (signalFittingWindowClosed()),
1114  this, SLOT (slotFittingWindowClosed()));
1115  connect (m_dockFittingWindow, SIGNAL (signalCurveFit(FittingCurveCoefficients, double, double, bool, bool)),
1116  this, SLOT (slotFittingWindowCurveFit(FittingCurveCoefficients, double, double, bool, bool)));
1117 
1118  // Geometry window starts out hidden since there is nothing to show initially. It will be positioned in settingsRead
1119  m_dockGeometryWindow = new GeometryWindow (this);
1120  connect (m_dockGeometryWindow, SIGNAL (signalGeometryWindowClosed()),
1121  this, SLOT (slotGeometryWindowClosed()));
1122 
1123 }
1124 
1125 void MainWindow::createHelpWindow ()
1126 {
1127  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createHelpWindow";
1128 
1129 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
1130  m_helpWindow = new HelpWindow (this);
1131  m_helpWindow->hide ();
1132  addDockWidget (Qt::RightDockWidgetArea,
1133  m_helpWindow); // Dock area is required by addDockWidget but immediately overridden in next line
1134  m_helpWindow->setFloating (true);
1135 
1136  connect (m_actionHelpHelp, SIGNAL (triggered ()), m_helpWindow, SLOT (show ()));
1137 #endif
1138 }
1139 
1140 void MainWindow::createIcons()
1141 {
1142  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createIcons";
1143 
1144  QIcon icon;
1145  QPixmap icon16 (bannerapp_16);
1146  QPixmap icon32 (bannerapp_32);
1147  QPixmap icon64 (bannerapp_64);
1148  QPixmap icon128 (bannerapp_128);
1149  QPixmap icon256 (bannerapp_256);
1150 
1151  icon.addPixmap (icon16);
1152  icon.addPixmap (icon32);
1153  icon.addPixmap (icon64);
1154  icon.addPixmap (icon128);
1155  icon.addPixmap (icon256);
1156 
1157  setWindowIcon (icon);
1158 }
1159 
1160 void MainWindow::createLoadImageFromUrl ()
1161 {
1162 #ifdef NETWORKING
1163  m_loadImageFromUrl = new LoadImageFromUrl (*this);
1164 #endif
1165 }
1166 
1167 void MainWindow::createMenus()
1168 {
1169  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createMenus";
1170 
1171  m_menuFile = menuBar()->addMenu(tr("&File"));
1172  m_menuFile->addAction (m_actionImport);
1173  m_menuFile->addAction (m_actionImportAdvanced);
1174  m_menuFile->addAction (m_actionImportImageReplace);
1175  m_menuFile->addAction (m_actionOpen);
1176 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
1177  m_menuFileOpenRecent = new QMenu (tr ("Open &Recent"));
1178  for (unsigned int i = 0; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
1179  m_menuFileOpenRecent->addAction (m_actionRecentFiles.at (i));
1180  }
1181  m_menuFile->addMenu (m_menuFileOpenRecent);
1182 #endif
1183  m_menuFile->addAction (m_actionClose);
1184  m_menuFile->insertSeparator (m_actionSave);
1185  m_menuFile->addAction (m_actionSave);
1186  m_menuFile->addAction (m_actionSaveAs);
1187  m_menuFile->addAction (m_actionExport);
1188  m_menuFile->insertSeparator (m_actionPrint);
1189  m_menuFile->addAction (m_actionPrint);
1190  m_menuFile->insertSeparator (m_actionExit);
1191  m_menuFile->addAction (m_actionExit);
1192 
1193  m_menuEdit = menuBar()->addMenu(tr("&Edit"));
1194  connect (m_menuEdit, SIGNAL (aboutToShow ()), this, SLOT (slotEditMenu ()));
1195  m_menuEdit->addAction (m_actionEditUndo);
1196  m_menuEdit->addAction (m_actionEditRedo);
1197  m_menuEdit->insertSeparator (m_actionEditCut);
1198  m_menuEdit->addAction (m_actionEditCut);
1199  m_menuEdit->addAction (m_actionEditCopy);
1200  m_menuEdit->addAction (m_actionEditPaste);
1201  m_menuEdit->addAction (m_actionEditDelete);
1202  m_menuEdit->insertSeparator (m_actionEditPasteAsNew);
1203  m_menuEdit->addAction (m_actionEditPasteAsNew);
1204  m_menuEdit->addAction (m_actionEditPasteAsNewAdvanced);
1205 
1206  m_menuDigitize = menuBar()->addMenu(tr("Digitize"));
1207  m_menuDigitize->addAction (m_actionDigitizeSelect);
1208  m_menuDigitize->addAction (m_actionDigitizeAxis);
1209  m_menuDigitize->addAction (m_actionDigitizeScale);
1210  m_menuDigitize->addAction (m_actionDigitizeCurve);
1211  m_menuDigitize->addAction (m_actionDigitizePointMatch);
1212  m_menuDigitize->addAction (m_actionDigitizeColorPicker);
1213  m_menuDigitize->addAction (m_actionDigitizeSegment);
1214 
1215  m_menuView = menuBar()->addMenu(tr("View"));
1216  m_menuView->addAction (m_actionViewBackground);
1217  m_menuView->addAction (m_actionViewDigitize);
1218  m_menuView->addAction (m_actionViewChecklistGuide);
1219  m_menuView->addAction (m_actionViewFittingWindow);
1220  m_menuView->addAction (m_actionViewGeometryWindow);
1221  m_menuView->addAction (m_actionViewSettingsViews);
1222  m_menuView->addAction (m_actionViewCoordSystem);
1223  m_menuView->insertSeparator (m_actionViewToolTips);
1224  m_menuView->addAction (m_actionViewToolTips);
1225  m_menuView->addAction (m_actionViewGridLines);
1226  m_menuView->insertSeparator (m_actionViewBackgroundNone);
1227  m_menuViewBackground = new QMenu (tr ("Background"));
1228  m_menuViewBackground->addAction (m_actionViewBackgroundNone);
1229  m_menuViewBackground->addAction (m_actionViewBackgroundOriginal);
1230  m_menuViewBackground->addAction (m_actionViewBackgroundFiltered);
1231  m_menuView->addMenu (m_menuViewBackground);
1232  m_menuViewCurves = new QMenu (tr ("Curves"));
1233  m_menuViewCurves->addAction (m_actionViewCurvesNone);
1234  m_menuViewCurves->addAction (m_actionViewCurvesSelected);
1235  m_menuViewCurves->addAction (m_actionViewCurvesAll);
1236  m_menuView->addMenu (m_menuViewCurves);
1237  m_menuViewStatus = new QMenu (tr ("Status Bar"));
1238  m_menuViewStatus->addAction (m_actionStatusNever);
1239  m_menuViewStatus->addAction (m_actionStatusTemporary);
1240  m_menuViewStatus->addAction (m_actionStatusAlways);
1241  m_menuView->addMenu (m_menuViewStatus);
1242  m_menuViewZoom = new QMenu (tr ("Zoom"));
1243  m_menuViewZoom->addAction (m_actionZoomOut);
1244  m_menuViewZoom->addAction (m_actionZoomIn);
1245  m_menuViewZoom->insertSeparator (m_actionZoom16To1);
1246  m_menuViewZoom->addAction (m_actionZoom16To1);
1247  m_menuViewZoom->addAction (m_actionZoom16To1Farther);
1248  m_menuViewZoom->addAction (m_actionZoom8To1Closer);
1249  m_menuViewZoom->addAction (m_actionZoom8To1);
1250  m_menuViewZoom->addAction (m_actionZoom8To1Farther);
1251  m_menuViewZoom->addAction (m_actionZoom4To1Closer);
1252  m_menuViewZoom->addAction (m_actionZoom4To1);
1253  m_menuViewZoom->addAction (m_actionZoom4To1Farther);
1254  m_menuViewZoom->addAction (m_actionZoom2To1Closer);
1255  m_menuViewZoom->addAction (m_actionZoom2To1);
1256  m_menuViewZoom->addAction (m_actionZoom2To1Farther);
1257  m_menuViewZoom->addAction (m_actionZoom1To1Closer);
1258  m_menuViewZoom->addAction (m_actionZoom1To1);
1259  m_menuViewZoom->addAction (m_actionZoom1To1Farther);
1260  m_menuViewZoom->addAction (m_actionZoom1To2Closer);
1261  m_menuViewZoom->addAction (m_actionZoom1To2);
1262  m_menuViewZoom->addAction (m_actionZoom1To2Farther);
1263  m_menuViewZoom->addAction (m_actionZoom1To4Closer);
1264  m_menuViewZoom->addAction (m_actionZoom1To4);
1265  m_menuViewZoom->addAction (m_actionZoom1To4Farther);
1266  m_menuViewZoom->addAction (m_actionZoom1To8Closer);
1267  m_menuViewZoom->addAction (m_actionZoom1To8);
1268  m_menuViewZoom->addAction (m_actionZoom1To8Farther);
1269  m_menuViewZoom->addAction (m_actionZoom1To16Closer);
1270  m_menuViewZoom->addAction (m_actionZoom1To16);
1271  m_menuViewZoom->addAction (m_actionZoomFill);
1272  m_menuView->addMenu (m_menuViewZoom);
1273 
1274  m_menuSettings = menuBar()->addMenu(tr ("Settings"));
1275  m_menuSettings->addAction (m_actionSettingsCoords);
1276  m_menuSettings->addAction (m_actionSettingsCurveAddRemove);
1277  m_menuSettings->addAction (m_actionSettingsCurveProperties);
1278  m_menuSettings->addAction (m_actionSettingsDigitizeCurve);
1279  m_menuSettings->addAction (m_actionSettingsExport);
1280  m_menuSettings->addAction (m_actionSettingsColorFilter);
1281  m_menuSettings->addAction (m_actionSettingsAxesChecker);
1282  m_menuSettings->addAction (m_actionSettingsGridDisplay);
1283  m_menuSettings->addAction (m_actionSettingsGridRemoval);
1284  m_menuSettings->addAction (m_actionSettingsPointMatch);
1285  m_menuSettings->addAction (m_actionSettingsSegments);
1286  m_menuSettings->insertSeparator (m_actionSettingsGeneral);
1287  m_menuSettings->addAction (m_actionSettingsGeneral);
1288  m_menuSettings->addAction (m_actionSettingsMainWindow);
1289 
1290  m_menuHelp = menuBar()->addMenu(tr("&Help"));
1291  m_menuHelp->addAction (m_actionHelpChecklistGuideWizard);
1292  m_menuHelp->insertSeparator(m_actionHelpWhatsThis);
1293  m_menuHelp->addAction (m_actionHelpWhatsThis);
1294  m_menuHelp->addAction (m_actionHelpTutorial);
1295 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
1296  m_menuHelp->addAction (m_actionHelpHelp);
1297 #endif
1298  m_menuHelp->addAction (m_actionHelpAbout);
1299 
1300  updateRecentFileList();
1301 }
1302 
1303 void MainWindow::createNetwork ()
1304 {
1305  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createNetwork";
1306 
1307 #ifdef NETWORKING
1308  m_networkClient = new NetworkClient (this);
1309 #endif
1310 }
1311 
1312 void MainWindow::createSettingsDialogs ()
1313 {
1314  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createSettingsDialogs";
1315 
1316  m_dlgSettingsCoords = new DlgSettingsCoords (*this);
1317  m_dlgSettingsCurveAddRemove = new DlgSettingsCurveAddRemove (*this);
1318  m_dlgSettingsCurveProperties = new DlgSettingsCurveProperties (*this);
1319  m_dlgSettingsDigitizeCurve = new DlgSettingsDigitizeCurve (*this);
1320  m_dlgSettingsExportFormat = new DlgSettingsExportFormat (*this);
1321  m_dlgSettingsColorFilter = new DlgSettingsColorFilter (*this);
1322  m_dlgSettingsAxesChecker = new DlgSettingsAxesChecker (*this);
1323  m_dlgSettingsGridDisplay = new DlgSettingsGridDisplay (*this);
1324  m_dlgSettingsGridRemoval = new DlgSettingsGridRemoval (*this);
1325  m_dlgSettingsPointMatch = new DlgSettingsPointMatch (*this);
1326  m_dlgSettingsSegments = new DlgSettingsSegments (*this);
1327  m_dlgSettingsGeneral = new DlgSettingsGeneral (*this);
1328  m_dlgSettingsMainWindow = new DlgSettingsMainWindow (*this);
1329 
1330  m_dlgSettingsCoords->setVisible (false);
1331  m_dlgSettingsCurveAddRemove->setVisible (false);
1332  m_dlgSettingsCurveProperties->setVisible (false);
1333  m_dlgSettingsDigitizeCurve->setVisible (false);
1334  m_dlgSettingsExportFormat->setVisible (false);
1335  m_dlgSettingsColorFilter->setVisible (false);
1336  m_dlgSettingsAxesChecker->setVisible (false);
1337  m_dlgSettingsGridDisplay->setVisible (false);
1338  m_dlgSettingsGridRemoval->setVisible (false);
1339  m_dlgSettingsPointMatch->setVisible (false);
1340  m_dlgSettingsSegments->setVisible (false);
1341  m_dlgSettingsGeneral->setVisible (false);
1342  m_dlgSettingsMainWindow->setVisible (false);
1343 }
1344 
1345 void MainWindow::createScene ()
1346 {
1347  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createScene";
1348 
1349  m_scene = new GraphicsScene (this);
1350  m_view = new GraphicsView (m_scene, *this);
1351  m_layout->addWidget (m_view);
1352 }
1353 
1354 void MainWindow::createStateContextBackground ()
1355 {
1356  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createStateContextBackground";
1357 
1358  m_backgroundStateContext = new BackgroundStateContext (*this);
1359 }
1360 
1361 void MainWindow::createStateContextDigitize ()
1362 {
1363  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createStateContextDigitize";
1364 
1365  m_digitizeStateContext = new DigitizeStateContext (*this,
1366  *m_view,
1367  m_isGnuplot);
1368 }
1369 
1370 void MainWindow::createStateContextTransformation ()
1371 {
1372  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createStateContextTransformation";
1373 
1374  ENGAUGE_CHECK_PTR (m_scene);
1375 
1376  m_transformationStateContext = new TransformationStateContext (*m_scene,
1377  m_isGnuplot);
1378 }
1379 
1380 void MainWindow::createStatusBar ()
1381 {
1382  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createStatusBar";
1383 
1384  m_statusBar = new StatusBar (*statusBar ());
1385  connect (this, SIGNAL (signalZoom(int)), m_statusBar, SLOT (slotZoom(int)));
1386  connect (m_statusBar, SIGNAL (signalZoom (int)), this, SLOT (slotViewZoom (int)));
1387 }
1388 
1389 void MainWindow::createToolBars ()
1390 {
1391  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createToolBars";
1392 
1393  const int VIEW_SIZE = 22;
1394 
1395  // Background toolbar widgets
1396  m_cmbBackground = new QComboBox ();
1397  m_cmbBackground->setEnabled (false);
1398  m_cmbBackground->setStatusTip (tr ("Select background image"));
1399  m_cmbBackground->setWhatsThis (tr ("Selected Background\n\n"
1400  "Select background image:\n"
1401  "1) No background which highlights points\n"
1402  "2) Original image which shows everything\n"
1403  "3) Filtered image which highlights important details"));
1404  m_cmbBackground->addItem (tr ("No background"), QVariant (BACKGROUND_IMAGE_NONE));
1405  m_cmbBackground->addItem (tr ("Original image"), QVariant (BACKGROUND_IMAGE_ORIGINAL));
1406  m_cmbBackground->addItem (tr ("Filtered image"), QVariant (BACKGROUND_IMAGE_FILTERED));
1407  // selectBackgroundOriginal needs currentIndexChanged
1408  connect (m_cmbBackground, SIGNAL (currentIndexChanged (int)), this, SLOT (slotCmbBackground (int)));
1409 
1410  // Background toolbar
1411  m_toolBackground = new QToolBar (tr ("Background"), this);
1412  m_toolBackground->addWidget (m_cmbBackground);
1413  addToolBar (m_toolBackground);
1414 
1415  // Digitize toolbar widgets that are not created elsewhere
1416  m_cmbCurve = new QComboBox ();
1417  m_cmbCurve->setEnabled (false);
1418  m_cmbCurve->setMinimumWidth (180);
1419  m_cmbCurve->setStatusTip (tr ("Select curve for new points."));
1420  m_cmbCurve->setWhatsThis (tr ("Selected Curve Name\n\n"
1421  "Select curve for any new points. Every point belongs to one curve.\n\n"
1422  "This can be changed while in Curve Point, Point Match, Color Picker or Segment Fill mode."));
1423  connect (m_cmbCurve, SIGNAL (activated (int)), this, SLOT (slotCmbCurve (int))); // activated() ignores code changes
1424 
1425  // Digitize toolbar
1426  m_toolDigitize = new QToolBar (tr ("Drawing"), this);
1427  m_toolDigitize->addAction (m_actionDigitizeSelect);
1428  m_toolDigitize->insertSeparator (m_actionDigitizeAxis);
1429  m_toolDigitize->addAction (m_actionDigitizeAxis);
1430  m_toolDigitize->addAction (m_actionDigitizeScale);
1431  m_toolDigitize->insertSeparator (m_actionDigitizeCurve);
1432  m_toolDigitize->addAction (m_actionDigitizeCurve);
1433  m_toolDigitize->addAction (m_actionDigitizePointMatch);
1434  m_toolDigitize->addAction (m_actionDigitizeColorPicker);
1435  m_toolDigitize->addAction (m_actionDigitizeSegment);
1436  m_toolDigitize->addWidget (m_cmbCurve);
1437  addToolBar (m_toolDigitize);
1438 
1439  // Views toolbar widgets
1440  m_viewPointStyle = new ViewPointStyle();
1441  m_viewPointStyle->setMinimumSize(VIEW_SIZE, VIEW_SIZE);
1442  m_viewPointStyle->setMaximumSize(VIEW_SIZE, VIEW_SIZE);
1443  m_viewPointStyle->setStatusTip (tr ("Points style for the currently selected curve"));
1444  m_viewPointStyle->setWhatsThis (tr ("Points Style\n\n"
1445  "Points style for the currently selected curve. The points style is only "
1446  "displayed in this toolbar. To change the points style, "
1447  "use the Curve Properties dialog."));
1448 
1449  m_viewSegmentFilter = new ViewSegmentFilter();
1450  m_viewSegmentFilter->setMinimumSize(VIEW_SIZE, VIEW_SIZE);
1451  m_viewSegmentFilter->setMaximumSize(VIEW_SIZE, VIEW_SIZE);
1452  m_viewSegmentFilter->setStatusTip (tr ("View of filter for current curve in Segment Fill mode"));
1453  m_viewSegmentFilter->setWhatsThis (tr ("Segment Fill Filter\n\n"
1454  "View of filter for the current curve in Segment Fill mode. The filter settings are only "
1455  "displayed in this toolbar. To changed the filter settings, "
1456  "use the Color Picker mode or the Filter Settings dialog."));
1457 
1458  // Settings views toolbar
1459  m_toolSettingsViews = new QToolBar (tr ("Views"), this);
1460  m_toolSettingsViews->addWidget (m_viewPointStyle);
1461  m_toolSettingsViews->addWidget (new QLabel (" ")); // A hack, but this works to put some space between the adjacent widgets
1462  m_toolSettingsViews->addWidget (m_viewSegmentFilter);
1463  addToolBar (m_toolSettingsViews);
1464 
1465  // Coordinate system toolbar
1466  m_cmbCoordSystem = new QComboBox;
1467  m_cmbCoordSystem->setEnabled (false);
1468  m_cmbCoordSystem->setStatusTip (tr ("Currently selected coordinate system"));
1469  m_cmbCoordSystem->setWhatsThis (tr ("Selected Coordinate System\n\n"
1470  "Currently selected coordinate system. This is used to switch between coordinate systems "
1471  "in documents with multiple coordinate systems"));
1472  connect (m_cmbCoordSystem, SIGNAL (activated (int)), this, SLOT (slotCmbCoordSystem (int)));
1473 
1474  m_btnShowAll = new QPushButton(QIcon(":/engauge/img/icon_show_all.png"), "");
1475  m_btnShowAll->setEnabled (false);
1476  m_btnShowAll->setAcceptDrops(false);
1477  m_btnShowAll->setStatusTip (tr ("Show all coordinate systems"));
1478  m_btnShowAll->setWhatsThis (tr ("Show All Coordinate Systems\n\n"
1479  "When pressed and held, this button shows all digitized points and lines for all coordinate systems."));
1480  connect (m_btnShowAll, SIGNAL (pressed ()), this, SLOT (slotBtnShowAllPressed ()));
1481  connect (m_btnShowAll, SIGNAL (released ()), this, SLOT (slotBtnShowAllReleased ()));
1482 
1483  m_btnPrintAll = new QPushButton(QIcon(":/engauge/img/icon_print_all.png"), "");
1484  m_btnPrintAll->setEnabled (false);
1485  m_btnPrintAll->setAcceptDrops(false);
1486  m_btnPrintAll->setStatusTip (tr ("Print all coordinate systems"));
1487  m_btnPrintAll->setWhatsThis (tr ("Print All Coordinate Systems\n\n"
1488  "When pressed, this button Prints all digitized points and lines for all coordinate systems."));
1489  connect (m_btnPrintAll, SIGNAL (pressed ()), this, SLOT (slotBtnPrintAll ()));
1490 
1491  m_toolCoordSystem = new QToolBar (tr ("Coordinate System"), this);
1492  m_toolCoordSystem->addWidget (m_cmbCoordSystem);
1493  m_toolCoordSystem->addWidget (m_btnShowAll);
1494  m_toolCoordSystem->addWidget (m_btnPrintAll);
1495  addToolBar (m_toolCoordSystem);
1496 }
1497 
1498 void MainWindow::createTutorial ()
1499 {
1500  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createTutorial";
1501 
1502  m_tutorialDlg = new TutorialDlg (this);
1503  m_tutorialDlg->setModal (true);
1504  m_tutorialDlg->setMinimumSize (500, 400);
1505  m_tutorialDlg->hide();
1506 }
1507 
1508 void MainWindow::createZoomMaps ()
1509 {
1510  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::createZoomMaps";
1511 
1512  m_zoomMapFromInitial [ZOOM_INITIAL_16_TO_1] = ZOOM_16_TO_1;
1513  m_zoomMapFromInitial [ZOOM_INITIAL_8_TO_1] = ZOOM_8_TO_1;
1514  m_zoomMapFromInitial [ZOOM_INITIAL_4_TO_1] = ZOOM_4_TO_1;
1515  m_zoomMapFromInitial [ZOOM_INITIAL_2_TO_1] = ZOOM_2_TO_1;
1516  m_zoomMapFromInitial [ZOOM_INITIAL_1_TO_1] = ZOOM_1_TO_1;
1517  m_zoomMapFromInitial [ZOOM_INITIAL_1_TO_2] = ZOOM_1_TO_2;
1518  m_zoomMapFromInitial [ZOOM_INITIAL_1_TO_4] = ZOOM_1_TO_4;
1519  m_zoomMapFromInitial [ZOOM_INITIAL_1_TO_8] = ZOOM_1_TO_8;
1520  m_zoomMapFromInitial [ZOOM_INITIAL_1_TO_16] = ZOOM_1_TO_16;
1521  m_zoomMapFromInitial [ZOOM_INITIAL_FILL] = ZOOM_FILL;
1522 
1523  m_zoomMapToAction [ZOOM_16_TO_1] = m_actionZoom16To1;
1524  m_zoomMapToAction [ZOOM_16_TO_1_FARTHER] = m_actionZoom16To1Farther;
1525  m_zoomMapToAction [ZOOM_8_TO_1_CLOSER] = m_actionZoom8To1Closer;
1526  m_zoomMapToAction [ZOOM_8_TO_1] = m_actionZoom8To1;
1527  m_zoomMapToAction [ZOOM_8_TO_1_FARTHER] = m_actionZoom8To1Farther;
1528  m_zoomMapToAction [ZOOM_4_TO_1_CLOSER] = m_actionZoom4To1Closer;
1529  m_zoomMapToAction [ZOOM_4_TO_1] = m_actionZoom4To1;
1530  m_zoomMapToAction [ZOOM_4_TO_1_FARTHER] = m_actionZoom4To1Farther;
1531  m_zoomMapToAction [ZOOM_2_TO_1_CLOSER] = m_actionZoom2To1Closer;
1532  m_zoomMapToAction [ZOOM_2_TO_1] = m_actionZoom2To1;
1533  m_zoomMapToAction [ZOOM_2_TO_1_FARTHER] = m_actionZoom2To1Farther;
1534  m_zoomMapToAction [ZOOM_1_TO_1_CLOSER] = m_actionZoom1To1Closer;
1535  m_zoomMapToAction [ZOOM_1_TO_1] = m_actionZoom1To1;
1536  m_zoomMapToAction [ZOOM_1_TO_1_FARTHER] = m_actionZoom1To1Farther;
1537  m_zoomMapToAction [ZOOM_1_TO_2_CLOSER] = m_actionZoom1To2Closer;
1538  m_zoomMapToAction [ZOOM_1_TO_2] = m_actionZoom1To2;
1539  m_zoomMapToAction [ZOOM_1_TO_2_FARTHER] = m_actionZoom1To2Farther;
1540  m_zoomMapToAction [ZOOM_1_TO_4_CLOSER] = m_actionZoom1To4Closer;
1541  m_zoomMapToAction [ZOOM_1_TO_4] = m_actionZoom1To4;
1542  m_zoomMapToAction [ZOOM_1_TO_4_FARTHER] = m_actionZoom1To4Farther;
1543  m_zoomMapToAction [ZOOM_1_TO_8_CLOSER] = m_actionZoom1To8Closer;
1544  m_zoomMapToAction [ZOOM_1_TO_8] = m_actionZoom1To8;
1545  m_zoomMapToAction [ZOOM_1_TO_8_FARTHER] = m_actionZoom1To8Farther;
1546  m_zoomMapToAction [ZOOM_1_TO_16_CLOSER] = m_actionZoom1To16Closer;
1547  m_zoomMapToAction [ZOOM_1_TO_16] = m_actionZoom1To16;
1548  m_zoomMapToAction [ZOOM_FILL] = m_actionZoomFill;
1549 }
1550 
1551 ZoomFactor MainWindow::currentZoomFactor () const
1552 {
1553  // Find the zoom control that is checked
1554  for (int z = 0; z < NUMBER_ZOOM_FACTORS; z++) {
1555  ZoomFactor zoomFactor = (ZoomFactor) z;
1556  if (m_zoomMapToAction [zoomFactor]->isChecked ()) {
1557  // This zoom control is checked
1558  return zoomFactor;
1559  }
1560  }
1561 
1562  ENGAUGE_ASSERT (false);
1563  return ZOOM_1_TO_1;
1564 }
1565 
1566 bool MainWindow::eventFilter(QObject *target, QEvent *event)
1567 {
1568  if (event->type () == QEvent::KeyPress) {
1569 
1570  QKeyEvent *eventKeyPress = (QKeyEvent *) event;
1571 
1572  // Special shortcuts. All of these are probably only useful for debugging and/or regression testing
1573  if ((eventKeyPress->key() == Qt::Key_E) &&
1574  ((eventKeyPress->modifiers() & Qt::ShiftModifier) != 0) &&
1575  ((eventKeyPress->modifiers() & Qt::ControlModifier) != 0)) {
1576 
1577  saveErrorReportFileAndExit ("Shift+Control+E",
1578  __FILE__,
1579  __LINE__,
1580  "userTriggered");
1581 
1582  }
1583  }
1584 
1585  return QObject::eventFilter (target, event);
1586 }
1587 
1588 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
1589 void MainWindow::exportAllCoordinateSystemsAfterRegressionTests()
1590 {
1591  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::exportAllCoordinateSystemsAfterRegressionTests curDir=" << QDir::currentPath().toLatin1().data();
1592 
1593  // Output the regression test results. One file is output for every coordinate system
1594  for (CoordSystemIndex index = 0; index < m_cmdMediator->document().coordSystemCount(); index++) {
1595 
1596  updateCoordSystem (index); // Switch to the specified coordinate system
1597 
1598  QString regressionFile = QString ("%1_%2")
1599  .arg (m_regressionFile)
1600  .arg (index + 1); // Append the coordinate system index
1601 
1602  // Normally we just export to a file, but when regression testing the export will fail since coordinates are not defined. To
1603  // get an export file when regression testing, we just output the image size
1604  if (m_isErrorReportRegressionTest && !m_transformation.transformIsDefined()) {
1605 
1606  ExportImageForRegression exportStrategy (m_cmdMediator->pixmap ());
1607  exportStrategy.fileExport (regressionFile);
1608 
1609  } else {
1610 
1611  ExportToFile exportStrategy;
1612 
1613  fileExport (regressionFile,
1614  exportStrategy);
1615  }
1616  }
1617 }
1618 #endif
1619 
1620 QString MainWindow::exportFilenameFromInputFilename (const QString &fileName) const
1621 {
1622  QString outFileName = fileName;
1623 
1624  outFileName = outFileName.replace (".xml", ".csv_actual"); // Applies when extension is xml
1625  outFileName = outFileName.replace (".dig", ".csv_actual"); // Applies when extension is dig
1626  outFileName = outFileName.replace (".pdf", ".csv_actual"); // Applies when extension is pdf
1627 
1628  return outFileName;
1629 }
1630 
1631 void MainWindow::fileExport(const QString &fileName,
1632  ExportToFile exportStrategy)
1633 {
1634  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileExport"
1635  << " curDir=" << QDir::currentPath().toLatin1().data()
1636  << " fileName=" << fileName.toLatin1().data();
1637 
1638  QFile file (fileName);
1639  if (file.open(QIODevice::WriteOnly)) {
1640 
1641  QTextStream str (&file);
1642 
1643  DocumentModelExportFormat modelExportFormat = modelExportOverride (m_cmdMediator->document().modelExport(),
1644  exportStrategy,
1645  fileName);
1646  exportStrategy.exportToFile (modelExportFormat,
1647  m_cmdMediator->document(),
1648  m_modelMainWindow,
1649  transformation (),
1650  str);
1651 
1652  updateChecklistGuide ();
1653  m_statusBar->showTemporaryMessage("File saved");
1654 
1655  } else {
1656 
1657  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::fileExport"
1658  << " file=" << fileName.toLatin1().data()
1659  << " curDir=" << QDir::currentPath().toLatin1().data();
1660  QMessageBox::critical (0,
1661  engaugeWindowTitle(),
1662  tr ("Unable to export to file ") + fileName);
1663  }
1664 }
1665 
1666 void MainWindow::fileImport (const QString &fileName,
1667  ImportType importType)
1668 {
1669  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileImport"
1670  << " fileName=" << fileName.toLatin1 ().data ()
1671  << " curDir=" << QDir::currentPath().toLatin1().data()
1672  << " importType=" << importType;
1673 
1674  QString originalFileOld = m_originalFile;
1675  bool originalFileWasImported = m_originalFileWasImported;
1676 
1677  m_originalFile = fileName; // Make this available for logging in case an error occurs during the load
1678  m_originalFileWasImported = true;
1679 
1680  if (importType == IMPORT_TYPE_ADVANCED) {
1681 
1682  // Remove any existing points, axes checker(s) and such from the previous Document so they do not appear in setupAfterLoadNewDocument
1683  // when previewing for IMAGE_TYPE_ADVANCED
1684  slotFileClose();
1685 
1686  // Restore the background just closed by slotFileClose. This is required so when the image is loaded for preview, it will appear
1687  m_backgroundStateContext->setBackgroundImage(BACKGROUND_IMAGE_ORIGINAL);
1688  }
1689 
1690  QImage image;
1691  bool loaded = false;
1692 
1693 #ifdef ENGAUGE_JPEG2000
1694  Jpeg2000 jpeg2000;
1695  loaded = jpeg2000.load (fileName,
1696  image);
1697 #endif // ENGAUGE_JPEG2000
1698 
1699 #ifdef ENGAUGE_PDF
1700  if (!loaded) {
1701 
1702  Pdf pdf;
1703  PdfReturn pdfReturn = pdf.load (fileName,
1704  image,
1705  m_modelMainWindow.pdfResolution(),
1706  m_modelMainWindow.importCropping(),
1707  m_isErrorReportRegressionTest);
1708  if (pdfReturn == PDF_RETURN_CANCELED) {
1709 
1710  // User canceled so exit immediately
1711  return;
1712 
1713  }
1714 
1715  loaded = (pdfReturn == PDF_RETURN_SUCCESS);
1716  }
1717 #endif // ENGAUGE_PDF
1718 
1719  if (!loaded) {
1720  NonPdf nonPdf;
1721  NonPdfReturn nonPdfReturn = nonPdf.load (fileName,
1722  image,
1723  m_modelMainWindow.importCropping(),
1724  m_isErrorReportRegressionTest);
1725  if (nonPdfReturn == NON_PDF_RETURN_CANCELED) {
1726 
1727  // User canceled so exit immediately
1728  return;
1729 
1730  }
1731 
1732  loaded = (nonPdfReturn == NON_PDF_RETURN_SUCCESS);
1733  }
1734 
1735  if (!loaded) {
1736  QString msg = QString("%1 %2 %3 %4.")
1737  .arg (tr ("Cannot read file"))
1738  .arg (fileName)
1739  .arg (tr ("from directory"))
1740  .arg (QDir::currentPath());
1741  QMessageBox::warning (this,
1742  engaugeWindowTitle(),
1743  msg);
1744 
1745  // Reset
1746  m_originalFile = originalFileOld;
1747  m_originalFileWasImported = originalFileWasImported;
1748 
1749  } else {
1750 
1751  loaded = loadImage (fileName,
1752  image,
1753  importType);
1754 
1755  if (!loaded) {
1756 
1757  // Failed
1758  if (importType == IMPORT_TYPE_ADVANCED) {
1759 
1760  // User cancelled after another file was imported so it could be previewed. In anticipation of the loading-for-preview,
1761  // we closed the current Document at the top of this method so we cannot reload. So, the only option is to close again
1762  // so the half-imported current Document is removed
1763  slotFileClose();
1764 
1765  } else {
1766 
1767  // Reset
1768  m_originalFile = originalFileOld;
1769  m_originalFileWasImported = originalFileWasImported;
1770  }
1771  }
1772  }
1773 }
1774 
1775 void MainWindow::fileImportWithPrompts (ImportType importType)
1776 {
1777  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::fileImportWithPrompts"
1778  << " importType=" << importType;
1779 
1780  // Skip maybeSave method for IMPORT_TYPE_REPLACE_IMAGE since open file dialog is enough to allow user to cancel the operation, and
1781  // since no information is lost in that case
1782  bool okToContinue = true;
1783  if (importType != IMPORT_TYPE_IMAGE_REPLACE) {
1784  okToContinue = maybeSave ();
1785  }
1786 
1787  if (okToContinue) {
1788 
1789  QString filter;
1790  QTextStream str (&filter);
1791 
1792  // Compile a list of supported formats into a filter
1793  QList<QByteArray>::const_iterator itr;
1794  QList<QByteArray> supportedImageFormats = QImageReader::supportedImageFormats();
1795  QStringList supportedImageFormatStrings;
1796  for (itr = supportedImageFormats.begin (); itr != supportedImageFormats.end (); itr++) {
1797  QByteArray arr = *itr;
1798  QString extensionAsWildcard = QString ("*.%1").arg (QString (arr));
1799  supportedImageFormatStrings << extensionAsWildcard;
1800  }
1801 #ifdef ENGAUGE_JPEG2000
1802  Jpeg2000 jpeg2000;
1803  supportedImageFormatStrings << jpeg2000.supportedImageWildcards();
1804 #endif // ENGAUGE_JPEG2000
1805 
1806 #ifdef ENGAUGE_PDF
1807  supportedImageFormatStrings << "*.pdf";
1808 #endif // ENGAUGE_PDF
1809 
1810  supportedImageFormatStrings.sort();
1811 
1812  str << "Image Files (" << supportedImageFormatStrings.join (" ") << ")";
1813 
1814  // Allow selection of files with strange suffixes in case the file extension was changed. Since
1815  // the default is the first filter, we add this afterwards (it is the off-nominal case)
1816  str << ";; All Files (*.*)";
1817 
1818  MainDirectoryPersist directoryPersist;
1819  QString fileName = QFileDialog::getOpenFileName (this,
1820  tr("Import Image"),
1821  directoryPersist.getDirectoryImportOpen ().path (),
1822  filter);
1823  if (!fileName.isEmpty ()) {
1824 
1825  directoryPersist.setDirectoryImportOpenFromFilename (fileName);
1826 
1827  // We import the file BEFORE asking the number of coordinate systems, so user can see how many there are
1828  fileImport (fileName,
1829  importType);
1830  }
1831  }
1832 }
1833 
1834 void MainWindow::filePaste (ImportType importType)
1835 {
1836  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::filePaste"
1837  << " importType=" << importType;
1838 
1839  QString originalFileOld = m_originalFile;
1840  bool originalFileWasImported = m_originalFileWasImported;
1841 
1842  QString fileName ("clipboard");
1843  m_originalFile = fileName; // Make this available for logging in case an error occurs during the load
1844  m_originalFileWasImported = true;
1845 
1846  if (importType == IMPORT_TYPE_ADVANCED) {
1847 
1848  // Remove any existing points, axes checker(s) and such from the previous Document so they do not appear in setupAfterLoadNewDocument
1849  // when previewing for IMAGE_TYPE_ADVANCED
1850  slotFileClose();
1851 
1852  // Restore the background just closed by slotFileClose. This is required so when the image is loaded for preview, it will appear
1853  m_backgroundStateContext->setBackgroundImage(BACKGROUND_IMAGE_ORIGINAL);
1854  }
1855 
1856  // An image was in the clipboard when this method was called but it may have disappeared
1857  QImage image = QApplication::clipboard()->image();
1858 
1859  bool loaded = false;
1860  if (!loaded) {
1861  loaded = !image.isNull();
1862  }
1863 
1864  if (!loaded) {
1865  QMessageBox::warning (this,
1866  engaugeWindowTitle(),
1867  QString("%1 %2 %3 %4.")
1868  .arg (tr ("Cannot read file"))
1869  .arg (fileName)
1870  .arg (tr ("from directory"))
1871  .arg (QDir::currentPath ()));
1872 
1873  // Reset
1874  m_originalFile = originalFileOld;
1875  m_originalFileWasImported = originalFileWasImported;
1876 
1877  } else {
1878 
1879  loaded = loadImage (fileName,
1880  image,
1881  importType);
1882 
1883  if (!loaded) {
1884 
1885  // Failed
1886  if (importType == IMPORT_TYPE_ADVANCED) {
1887 
1888  // User cancelled after another file was imported so it could be previewed. In anticipation of the loading-for-preview,
1889  // we closed the current Document at the top of this method so we cannot reload. So, the only option is to close again
1890  // so the half-imported current Document is removed
1891  slotFileClose();
1892 
1893  } else {
1894 
1895  // Reset
1896  m_originalFile = originalFileOld;
1897  m_originalFileWasImported = originalFileWasImported;
1898  }
1899  }
1900  }
1901 }
1902 
1903 void MainWindow::ghostsCreate ()
1904 {
1905  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::ghostsCreate";
1906 
1907  ENGAUGE_ASSERT (m_ghosts == 0);
1908  m_ghosts = new Ghosts (m_cmdMediator->document().coordSystemIndex());
1909 
1910  for (unsigned int index = 0; index < m_cmdMediator->document().coordSystemCount(); index++) {
1911 
1912  // Skip this coordinate system if it is the selected coordinate system since it will be displayed anyway, so no ghosts are required
1913  if (index != m_ghosts->coordSystemIndexToBeRestored ()) {
1914 
1915  updateCoordSystem (index);
1916 
1917  // Take a snapshot of the graphics items
1918  m_ghosts->captureGraphicsItems (*m_scene);
1919  }
1920  }
1921 
1922  // Restore the coordinate system that was originally selected, so its points/lines are visible
1924 
1925  // Make visible ghosts
1926  m_ghosts->createGhosts (*m_scene);
1927 }
1928 
1929 void MainWindow::ghostsDestroy ()
1930 {
1931  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::ghostsDestroy";
1932 
1933  ENGAUGE_CHECK_PTR (m_ghosts);
1934 
1935  m_ghosts->destroyGhosts(*m_scene);
1936 
1937  delete m_ghosts;
1938  m_ghosts = 0;
1939 }
1940 
1942 {
1943  return m_backgroundStateContext->imageForCurveState();
1944 }
1945 
1947 {
1948  return m_isGnuplot;
1949 }
1950 
1951 void MainWindow::loadCoordSystemListFromCmdMediator ()
1952 {
1953  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadCoordSystemListFromCmdMediator";
1954 
1955  m_cmbCoordSystem->clear();
1956 
1957  unsigned int numberCoordSystem = m_cmdMediator->document().coordSystemCount();
1958 
1959  for (unsigned int i = 0; i < numberCoordSystem; i++) {
1960  int index1Based = i + 1;
1961  m_cmbCoordSystem->addItem (QString::number (index1Based),
1962  QVariant (i));
1963  }
1964 
1965  // Always start with the first entry selected
1966  m_cmbCoordSystem->setCurrentIndex (0);
1967 
1968  // Disable the controls if there is only one entry. Hopefully the user will not even notice it, thus simplifying the interface
1969  bool enable = (m_cmbCoordSystem->count() > 1);
1970  m_cmbCoordSystem->setEnabled (enable);
1971  m_btnShowAll->setEnabled (enable);
1972  m_btnPrintAll->setEnabled (enable);
1973 }
1974 
1975 void MainWindow::loadCurveListFromCmdMediator ()
1976 {
1977  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadCurveListFromCmdMediator";
1978 
1979  m_cmbCurve->clear ();
1980  QStringList curvesGraphsNames = m_cmdMediator->curvesGraphsNames ();
1981  QStringList::iterator itr;
1982  for (itr = curvesGraphsNames.begin (); itr != curvesGraphsNames.end (); itr++) {
1983 
1984  QString curvesGraphName = *itr;
1985  m_cmbCurve->addItem (curvesGraphName);
1986  }
1987 
1988  // Select the curve that is associated with the current coordinate system
1989  m_cmbCurve->setCurrentText (m_cmdMediator->selectedCurveName ());
1990 }
1991 
1992 void MainWindow::loadDocumentFile (const QString &fileName)
1993 {
1994  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadDocumentFile fileName=" << fileName.toLatin1 ().data ();
1995 
1996  QApplication::setOverrideCursor(Qt::WaitCursor);
1997  CmdMediator *cmdMediator = new CmdMediator (*this,
1998  fileName);
1999 
2000  if (cmdMediator->successfulRead ()) {
2001 
2002  setCurrentPathFromFile (fileName);
2003  rebuildRecentFileListForCurrentFile(fileName);
2004  m_currentFile = fileName; // This enables the FileSaveAs menu option
2005 
2006  if (m_cmdMediator != 0) {
2007  delete m_cmdMediator;
2008  m_cmdMediator = 0;
2009  }
2010 
2011  m_cmdMediator = cmdMediator;
2012  setupAfterLoadNewDocument (fileName,
2013  tr ("File opened"),
2014  IMPORT_TYPE_SIMPLE);
2015 
2016  // Start select mode
2017  m_actionDigitizeSelect->setChecked (true); // We assume user wants to first select existing stuff
2018  slotDigitizeSelect(); // Trigger transition so cursor gets updated immediately
2019 
2020  m_engaugeFile = fileName;
2021  m_originalFile = fileName; // This is needed by updateAfterCommand below if an error report is generated
2022  m_originalFileWasImported = false;
2023 
2024  updateGridLines ();
2025  updateAfterCommand (); // Enable Save button now that m_engaugeFile is set
2026 
2027  QApplication::restoreOverrideCursor();
2028 
2029  } else {
2030 
2031  QApplication::restoreOverrideCursor();
2032 
2033  QMessageBox::warning (this,
2034  engaugeWindowTitle(),
2035  QString("%1 %2 %3 %4:\n%5.")
2036  .arg (tr ("Cannot read file"))
2037  .arg (fileName)
2038  .arg (tr ("from directory"))
2039  .arg (QDir::currentPath ())
2040  .arg(cmdMediator->reasonForUnsuccessfulRead ()));
2041  delete cmdMediator;
2042 
2043  }
2044 }
2045 
2046 void MainWindow::loadErrorReportFile(const QString &errorReportFile)
2047 {
2048  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadErrorReportFile"
2049  << " file=" << errorReportFile.toLatin1().data();
2050 
2051  QFile file (errorReportFile);
2052  if (!file.exists()) {
2053  // Convert path from relative to absolute so file-not-found errors are easier to fix
2054  QFileInfo fileInfo (errorReportFile);
2055 
2056  QMessageBox::critical (this,
2057  engaugeWindowTitle(),
2058  tr ("File not found:") + " " + fileInfo.absoluteFilePath());
2059  exit (-1);
2060  }
2061 
2062  // Open the error report file as if it was a regular Document file
2063  QXmlStreamReader reader (&file);
2064  file.open(QIODevice::ReadOnly | QIODevice::Text);
2065  m_cmdMediator = new CmdMediator(*this,
2066  errorReportFile);
2067 
2068  // Load the commands into the shadow command stack
2069  m_cmdStackShadow->loadCommands (*this,
2070  m_cmdMediator->document(),
2071  reader);
2072  file.close();
2073 
2074  setupAfterLoadNewDocument (errorReportFile,
2075  tr ("Error report opened"),
2076  IMPORT_TYPE_SIMPLE);
2077 
2078  // Start select mode
2079  m_actionDigitizeSelect->setChecked (true); // We assume user wants to first select existing stuff
2080  slotDigitizeSelect(); // Trigger transition so cursor gets updated immediately
2081 
2082  updateAfterCommand ();
2083 }
2084 
2085 bool MainWindow::loadImage (const QString &fileName,
2086  const QImage &image,
2087  ImportType importType)
2088 {
2089  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImage"
2090  << " fileName=" << fileName.toLatin1 ().data ()
2091  << " importType=" << importType;
2092 
2093  bool success;
2094  if (importType == IMPORT_TYPE_IMAGE_REPLACE) {
2095  success = loadImageReplacingImage (fileName,
2096  image,
2097  importType);
2098  } else {
2099  success = loadImageNewDocument (fileName,
2100  image,
2101  importType);
2102  }
2103 
2104  return success;
2105 }
2106 
2107 bool MainWindow::loadImageNewDocument (const QString &fileName,
2108  const QImage &image,
2109  ImportType importType)
2110 {
2111  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImageNewDocument"
2112  << " fileName=" << fileName.toLatin1 ().data ()
2113  << " importType=" << importType;
2114 
2115  ENGAUGE_ASSERT (importType != IMPORT_TYPE_IMAGE_REPLACE);
2116 
2117  QApplication::setOverrideCursor(Qt::WaitCursor);
2118  CmdMediator *cmdMediator = new CmdMediator (*this,
2119  image);
2120  QApplication::restoreOverrideCursor();
2121 
2122  setCurrentPathFromFile (fileName);
2123  // We do not call rebuildRecentFileListForCurrentFile for an image file, so only proper Engauge document files appear in the recent file list
2124  m_engaugeFile = EMPTY_FILENAME; // Forces first Save to be treated as Save As
2125 
2126  if (m_cmdMediator != 0) {
2127  delete m_cmdMediator;
2128  m_cmdMediator = 0;
2129  }
2130 
2131  m_cmdMediator = cmdMediator;
2132  bool accepted = setupAfterLoadNewDocument (fileName,
2133  tr ("File imported"),
2134  importType);
2135 
2136  if (accepted) {
2137 
2138  // Show the wizard if user selected it and we are not running a script
2139  if (m_actionHelpChecklistGuideWizard->isChecked () &&
2140  (m_fileCmdScript == 0)) {
2141 
2142  // Show wizard
2143  ChecklistGuideWizard *wizard = new ChecklistGuideWizard (*this,
2144  m_cmdMediator->document().coordSystemCount());
2145  if (wizard->exec() == QDialog::Accepted) {
2146 
2147  for (CoordSystemIndex coordSystemIndex = 0; coordSystemIndex < m_cmdMediator->document().coordSystemCount(); coordSystemIndex++) {
2148 
2149  // Populate the checklist guide
2150  m_dockChecklistGuide->setTemplateHtml (wizard->templateHtml(coordSystemIndex),
2151  wizard->curveNames(coordSystemIndex));
2152 
2153  // Update Document
2154  CurvesGraphs curvesGraphs;
2155  wizard->populateCurvesGraphs (coordSystemIndex,
2156  curvesGraphs);
2157  m_cmdMediator->document().setCurvesGraphs(curvesGraphs);
2158  }
2159 
2160  // Unhide the checklist guide
2161  m_actionViewChecklistGuide->setChecked (true);
2162 
2163  // Update the curve dropdown
2164  loadCurveListFromCmdMediator();
2165 
2166  // Update the CoordSystem dropdown
2167  loadCoordSystemListFromCmdMediator();
2168  }
2169  delete wizard;
2170  }
2171 
2172  // Start axis mode
2173  m_actionDigitizeAxis->setChecked (true); // We assume user first wants to digitize axis points
2174 
2175  // Trigger transition so cursor gets updated immediately
2176  if (modeMap ()) {
2177  slotDigitizeScale ();
2178  } else if (modeGraph ()) {
2179  slotDigitizeAxis ();
2180  }
2181 
2182  updateControls ();
2183  }
2184 
2185  return accepted;
2186 }
2187 
2188 bool MainWindow::loadImageReplacingImage (const QString &fileName,
2189  const QImage &image,
2190  ImportType importType)
2191 {
2192  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::loadImageReplacingImage"
2193  << " fileName=" << fileName.toLatin1 ().data ()
2194  << " importType=" << importType;
2195 
2196  ENGAUGE_ASSERT (importType == IMPORT_TYPE_IMAGE_REPLACE);
2197 
2198  setCurrentPathFromFile (fileName);
2199  // We do not call rebuildRecentFileListForCurrentFile for an image file, so only proper Engauge document files appear in the recent file list
2200  m_engaugeFile = EMPTY_FILENAME; // Forces first Save to be treated as Save As
2201 
2202  ENGAUGE_ASSERT (m_cmdMediator != 0); // Menu option should only be available when a document is currently open
2203 
2204  m_cmdMediator->document().setPixmap (image);
2205 
2206  bool accepted = setupAfterLoadReplacingImage (fileName,
2207  tr ("File imported"),
2208  importType);
2209 
2210  // No checklist guide wizard is displayed when just replacing the image
2211 
2212  return accepted;
2213 }
2214 
2215 void MainWindow::loadInputFileForErrorReport(QDomDocument &domInputFile) const
2216 {
2217  QFile file (m_originalFile);
2218 
2219  // File should be available for opening, if not then the dom will be left empty. We assume it has not been
2220  // modified since opened
2221  if (!file.open (QIODevice::ReadOnly)) {
2222  return;
2223  }
2224 
2225  domInputFile.setContent (&file);
2226  file.close();
2227 }
2228 
2229 void MainWindow::loadToolTips()
2230 {
2231  if (m_actionViewToolTips->isChecked ()) {
2232 
2233  // Show tool tips
2234  m_actionDigitizeSelect->setToolTip (m_actionDigitizeSelect->text());
2235  m_actionDigitizeAxis->setToolTip (m_actionDigitizeAxis->text());
2236  m_actionDigitizeScale->setToolTip (m_actionDigitizeScale->text());
2237  m_actionDigitizeCurve->setToolTip (m_actionDigitizeCurve->text());
2238  m_actionDigitizePointMatch->setToolTip (m_actionDigitizePointMatch->text());
2239  m_actionDigitizeColorPicker->setToolTip (m_actionDigitizeColorPicker->text());
2240  m_actionDigitizeSegment->setToolTip (m_actionDigitizeSegment->text());
2241  m_cmbBackground->setToolTip (tr ("Background image."));
2242  m_cmbCurve->setToolTip (tr ("Currently selected curve."));
2243  m_viewPointStyle->setToolTip (tr ("Point style for currently selected curve."));
2244  m_viewSegmentFilter->setToolTip (tr ("Segment Fill filter for currently selected curve."));
2245 
2246  } else {
2247 
2248  // Remove any previous tool tips
2249  m_actionDigitizeSelect->setToolTip ("");
2250  m_actionDigitizeAxis->setToolTip ("");
2251  m_actionDigitizeScale->setToolTip ("");
2252  m_actionDigitizeCurve->setToolTip ("");
2253  m_actionDigitizePointMatch->setToolTip ("");
2254  m_actionDigitizeColorPicker->setToolTip ("");
2255  m_actionDigitizeSegment->setToolTip ("");
2256  m_cmbBackground->setToolTip ("");
2257  m_cmbCurve->setToolTip ("");
2258  m_viewPointStyle->setToolTip ("");
2259  m_viewSegmentFilter->setToolTip ("");
2260 
2261  }
2262 }
2263 
2264 bool MainWindow::modeGraph () const
2265 {
2266  bool success = false;
2267 
2268  if (m_cmdMediator != 0) {
2269  success = (m_cmdMediator->document().documentAxesPointsRequired() != DOCUMENT_AXES_POINTS_REQUIRED_2);
2270  }
2271 
2272  return success;
2273 }
2274 
2275 bool MainWindow::modeMap () const
2276 {
2277  bool success = false;
2278 
2279  if (m_cmdMediator != 0) {
2280  success = (m_cmdMediator->document().documentAxesPointsRequired() == DOCUMENT_AXES_POINTS_REQUIRED_2);
2281  }
2282 
2283  return success;
2284 }
2285 
2286 bool MainWindow::maybeSave()
2287 {
2288  if (m_cmdMediator != 0) {
2289  if (m_cmdMediator->isModified()) {
2290  QMessageBox::StandardButton ret = QMessageBox::warning (this,
2291  engaugeWindowTitle(),
2292  tr("The document has been modified.\n"
2293  "Do you want to save your changes?"),
2294  QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
2295  if (ret == QMessageBox::Save) {
2296  return slotFileSave();
2297  } else if (ret == QMessageBox::Cancel) {
2298  return false;
2299  }
2300  }
2301  }
2302 
2303  return true;
2304 }
2305 
2306 DocumentModelExportFormat MainWindow::modelExportOverride (const DocumentModelExportFormat &modelExportFormatBefore,
2307  const ExportToFile &exportStrategy,
2308  const QString &fileName) const
2309 {
2310  DocumentModelExportFormat modelExportFormatAfter = modelExportFormatBefore;
2311 
2312  // See if delimiter setting overrides commas/tabs for files with csv/tsv file extensions respectively
2313  if (!modelExportFormatAfter.overrideCsvTsv()) {
2314 
2315  // Extract file extensions
2316  QString csvExtension = QString (".%1")
2317  .arg (exportStrategy.fileExtensionCsv());
2318  QString tsvExtension = QString (".%1")
2319  .arg (exportStrategy.fileExtensionTsv());
2320  QString fileExtensionVersusCsv = fileName.right (csvExtension.size());
2321  QString fileExtensionVersusTsv = fileName.right (tsvExtension.size());
2322 
2323  // Override if CSV or TSV was selected. We cannot use QFileDialog::selectedNameFilter() since that is
2324  // broken in Linux, so we use the file extension
2325  if (csvExtension.compare (fileExtensionVersusCsv, Qt::CaseInsensitive) == 0) {
2326  modelExportFormatAfter.setDelimiter (EXPORT_DELIMITER_COMMA);
2327  } else if (tsvExtension.compare (fileExtensionVersusTsv, Qt::CaseInsensitive) == 0) {
2328  modelExportFormatAfter.setDelimiter (EXPORT_DELIMITER_TAB);
2329  }
2330  }
2331 
2332  return modelExportFormatAfter;
2333 }
2334 
2336 {
2337  return m_modelMainWindow;
2338 }
2339 
2340 void MainWindow::rebuildRecentFileListForCurrentFile(const QString &filePath)
2341 {
2342  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::rebuildRecentFileListForCurrentFile";
2343 
2344  setWindowFilePath (filePath);
2345 
2346  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
2347  QStringList recentFilePaths = settings.value (SETTINGS_RECENT_FILE_LIST).toStringList();
2348  recentFilePaths.removeAll (filePath); // Remove previous instance of the current filePath
2349  recentFilePaths.prepend (filePath); // Insert current filePath at start
2350  while (recentFilePaths.count () > (int) MAX_RECENT_FILE_LIST_SIZE) {
2351  recentFilePaths.removeLast (); // Remove entry since the number of entries exceeds the limit
2352  }
2353  settings.setValue (SETTINGS_RECENT_FILE_LIST, recentFilePaths);
2354 
2355  updateRecentFileList();
2356 }
2357 
2358 void MainWindow::resizeEvent(QResizeEvent * /* event */)
2359 {
2360  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::resizeEvent";
2361 
2362  if (m_actionZoomFill->isChecked ()) {
2363  slotViewZoomFactor (ZOOM_FILL);
2364  }
2365 }
2366 
2367 bool MainWindow::saveDocumentFile (const QString &fileName)
2368 {
2369  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::saveDocumentFile fileName=" << fileName.toLatin1 ().data ();
2370 
2371  QFile file(fileName);
2372  if (!file.open(QFile::WriteOnly)) {
2373  QMessageBox::warning (this,
2374  engaugeWindowTitle(),
2375  QString ("%1 %2: \n%3.")
2376  .arg(tr ("Cannot write file"))
2377  .arg(fileName)
2378  .arg(file.errorString()));
2379  return false;
2380  }
2381 
2382  rebuildRecentFileListForCurrentFile (fileName);
2383 
2384  QApplication::setOverrideCursor (Qt::WaitCursor);
2385  QXmlStreamWriter writer(&file);
2386  writer.setAutoFormatting(true);
2387  writer.writeStartDocument();
2388  writer.writeDTD("<!DOCTYPE engauge>");
2389  m_cmdMediator->document().saveXml(writer);
2390  writer.writeEndDocument();
2391  QApplication::restoreOverrideCursor ();
2392 
2393  // Notify the undo stack that the current state is now considered "clean". This will automatically trigger a
2394  // signal back to this class that will update the modified marker in the title bar
2395  m_cmdMediator->setClean ();
2396 
2397  setCurrentFile(fileName);
2398  m_engaugeFile = fileName;
2399  updateAfterCommand (); // Enable Save button now that m_engaugeFile is set
2400  m_statusBar->showTemporaryMessage("File saved");
2401 
2402  return true;
2403 }
2404 
2405 void MainWindow::saveErrorReportFileAndExit (const char *context,
2406  const char *file,
2407  int line,
2408  const char *comment) const
2409 {
2410  // Skip if currently performing a regression test - in which case the preferred behavior is to let the current test fail and
2411  // continue on to execute the remaining tests
2412  if ((m_cmdMediator != 0) && !m_isErrorReportRegressionTest) {
2413 
2414  QString report = saveErrorReportFileAndExitXml (context,
2415  file,
2416  line,
2417  comment);
2418 #ifdef NETWORKING
2419  DlgErrorReportNetworking dlg (report);
2420 
2421  // Ask user if report should be uploaded, and if the document is included when it is uploaded
2422  if (dlg.exec() == QDialog::Accepted) {
2423 
2424  // Upload the error report to the server
2425  m_networkClient->uploadErrorReport (dlg.xmlToUpload());
2426  }
2427 #else
2428  DlgErrorReportLocal dlg (report);
2429  dlg.exec();
2430  exit (-1);
2431 #endif
2432  }
2433 }
2434 
2435 QString MainWindow::saveErrorReportFileAndExitXml (const char *context,
2436  const char *file,
2437  int line,
2438  const char *comment) const
2439 {
2440  const bool DEEP_COPY = true;
2441 
2442  QString xmlErrorReport;
2443  QXmlStreamWriter writer (&xmlErrorReport);
2444  writer.setAutoFormatting(true);
2445 
2446  // Entire error report contains metadata, commands and other details
2447  writer.writeStartElement(DOCUMENT_SERIALIZE_ERROR_REPORT);
2448 
2449  // Version
2450  writer.writeStartElement(DOCUMENT_SERIALIZE_APPLICATION);
2451  writer.writeAttribute(DOCUMENT_SERIALIZE_APPLICATION_VERSION_NUMBER, VERSION_NUMBER);
2452  writer.writeEndElement();
2453 
2454  // Document
2455  // Insert snapshot xml into writer stream, by reading from reader stream. Highest level of snapshot is DOCUMENT_SERIALIZE_APPLICATION
2456  QXmlStreamReader reader (m_startingDocumentSnapshot);
2457  while (!reader.atEnd ()) {
2458  reader.readNext ();
2459  if (reader.tokenType() != QXmlStreamReader::StartDocument &&
2460  reader.tokenType() != QXmlStreamReader::EndDocument) {
2461  writer.writeCurrentToken (reader);
2462  }
2463  }
2464 
2465  // Operating system
2466  writer.writeStartElement(DOCUMENT_SERIALIZE_OPERATING_SYSTEM);
2467  writer.writeAttribute(DOCUMENT_SERIALIZE_OPERATING_SYSTEM_ENDIAN, EndianToString (QSysInfo::ByteOrder));
2468  writer.writeAttribute(DOCUMENT_SERIALIZE_OPERATING_SYSTEM_WORD_SIZE, QString::number (QSysInfo::WordSize));
2469  writer.writeEndElement();
2470 
2471  // Placeholder for original file, before the commands in the command stack were applied
2472  writer.writeStartElement(DOCUMENT_SERIALIZE_FILE);
2473  writer.writeAttribute(DOCUMENT_SERIALIZE_FILE_IMPORTED,
2474  m_originalFileWasImported ? DOCUMENT_SERIALIZE_BOOL_TRUE : DOCUMENT_SERIALIZE_BOOL_FALSE);
2475  writer.writeEndElement();
2476 
2477  // Commands
2478  m_cmdMediator->saveXml(writer);
2479 
2480  // Error
2481  writer.writeStartElement(DOCUMENT_SERIALIZE_ERROR);
2482  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_CONTEXT, context);
2483  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_FILE, file);
2484  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_LINE, QString::number (line));
2485  writer.writeAttribute(DOCUMENT_SERIALIZE_ERROR_COMMENT, comment);
2486  writer.writeEndElement();
2487 
2488  writer.writeEndElement();
2489 
2490  // Put string into DOM
2491  QDomDocument domErrorReport ("ErrorReport");
2492  domErrorReport.setContent (xmlErrorReport);
2493 
2494  // Postprocessing
2495  if (!m_originalFileWasImported) {
2496 
2497  // Insert the original file into its placeholder, by manipulating the source and target xml as DOM documents. Very early
2498  // in the loading process, the original file may not be specified yet (m_originalFile is empty)
2499  QDomDocument domInputFile;
2500  loadInputFileForErrorReport (domInputFile);
2501  QDomDocumentFragment fragmentFileFrom = domErrorReport.createDocumentFragment();
2502  if (!domInputFile.isNull()) {
2503  fragmentFileFrom.appendChild (domErrorReport.importNode (domInputFile.documentElement(), DEEP_COPY));
2504  }
2505  QDomNodeList nodesFileTo = domErrorReport.elementsByTagName (DOCUMENT_SERIALIZE_FILE);
2506  if (nodesFileTo.count () > 0) {
2507  QDomNode nodeFileTo = nodesFileTo.at (0);
2508  nodeFileTo.appendChild (fragmentFileFrom);
2509  }
2510 
2511  // Replace DOCUMENT_SERIALIZE_IMAGE by same node with CDATA removed, since:
2512  // 1) it is very big and working with smaller files, especially in emails, is easier
2513  // 2) removing the image better preserves user's privacy
2514  // 3) having the actual image does not help that much when debugging
2515  QDomNodeList nodesDocument = domErrorReport.elementsByTagName (DOCUMENT_SERIALIZE_DOCUMENT);
2516  for (int i = 0 ; i < nodesDocument.count(); i++) {
2517  QDomNode nodeDocument = nodesDocument.at (i);
2518  QDomElement elemImage = nodeDocument.firstChildElement(DOCUMENT_SERIALIZE_IMAGE);
2519  if (!elemImage.isNull()) {
2520 
2521  // Get old image attributes so we can create an empty document with the same size
2522  if (elemImage.hasAttribute (DOCUMENT_SERIALIZE_IMAGE_WIDTH) &&
2523  elemImage.hasAttribute (DOCUMENT_SERIALIZE_IMAGE_HEIGHT)) {
2524 
2525  int width = elemImage.attribute(DOCUMENT_SERIALIZE_IMAGE_WIDTH).toInt();
2526  int height = elemImage.attribute(DOCUMENT_SERIALIZE_IMAGE_HEIGHT).toInt();
2527 
2528  QDomNode nodeReplacement;
2529  QDomElement elemReplacement = nodeReplacement.toElement();
2530  elemReplacement.setAttribute (DOCUMENT_SERIALIZE_IMAGE_WIDTH, width);
2531  elemReplacement.setAttribute (DOCUMENT_SERIALIZE_IMAGE_HEIGHT, height);
2532 
2533  // Replace with the new and then remove the old
2534  nodeDocument.insertBefore (nodeReplacement,
2535  elemImage);
2536  nodeDocument.removeChild(elemImage);
2537  }
2538  }
2539  }
2540  }
2541 
2542  return domErrorReport.toString();
2543 }
2544 
2545 void MainWindow::saveStartingDocumentSnapshot()
2546 {
2547  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::saveStartingDocumentSnapshot";
2548 
2549  QXmlStreamWriter writer (&m_startingDocumentSnapshot);
2550  writer.setAutoFormatting (true);
2551  m_cmdMediator->document().saveXml (writer);
2552 }
2553 
2555 {
2556  ENGAUGE_CHECK_PTR (m_scene);
2557  return *m_scene;
2558 }
2559 
2560 BackgroundImage MainWindow::selectOriginal(BackgroundImage backgroundImage)
2561 {
2562  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::selectBackgroundOriginal";
2563 
2564  BackgroundImage previousBackground = (BackgroundImage) m_cmbBackground->currentData().toInt();
2565 
2566  int index = m_cmbBackground->findData (backgroundImage);
2567  ENGAUGE_ASSERT (index >= 0);
2568 
2569  m_cmbBackground->setCurrentIndex(index);
2570 
2571  return previousBackground;
2572 }
2573 
2575 {
2576  return m_cmbCurve->currentText ();
2577 }
2578 
2579 void MainWindow::setCurrentFile (const QString &fileName)
2580 {
2581  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setCurrentFile";
2582 
2583  QString fileNameStripped;
2584  if (!fileName.isEmpty()) {
2585 
2586  // Strip out path and file extension
2587  QFileInfo fileInfo (fileName);
2588  fileNameStripped = fileInfo.baseName();
2589  }
2590 
2591  m_currentFile = fileNameStripped;
2592  m_currentFileWithPathAndFileExtension = fileName;
2593 
2594  updateWindowTitle ();
2595 }
2596 
2597 void MainWindow::setCurrentPathFromFile (const QString &fileName)
2598 {
2599  QDir dir = QFileInfo (fileName).absoluteDir();
2600 
2601  if (dir.exists ()) {
2602 
2603  bool success = QDir::setCurrent (dir.absolutePath ()); // Return to chosen directory the next time
2604  ENGAUGE_ASSERT (success);
2605 
2606  } else {
2607 
2608  // File was a url so it is irrelevant to the current directory
2609  }
2610 }
2611 
2612 void MainWindow::setNonFillZoomFactor (ZoomFactor newZoomFactor)
2613 {
2614  ENGAUGE_ASSERT (newZoomFactor != ZOOM_FILL);
2615 
2616  // Update controls and apply zoom factor
2617  m_zoomMapToAction [newZoomFactor]->setChecked (true);
2618  slotViewZoomFactor (newZoomFactor);
2619 }
2620 
2621 void MainWindow::setPixmap (const QString &curveSelected,
2622  const QPixmap &pixmap)
2623 {
2624  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setPixmap";
2625 
2626  m_digitizeStateContext->setImageIsLoaded (m_cmdMediator,
2627  true);
2628 
2629  // We cannot reliably use m_cmbCurve->currentText below for the selected curve since that control
2630  // can be pointing to a curve that no longer exists so this method requires curveSelected as an argument
2631  m_backgroundStateContext->setPixmap (m_transformation,
2632  m_cmdMediator->document().modelGridRemoval(),
2633  m_cmdMediator->document().modelColorFilter(),
2634  pixmap,
2635  curveSelected);
2636 }
2637 
2638 void MainWindow::settingsRead (bool isReset)
2639 {
2640  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
2641 
2642  if (isReset) {
2643  // Delete all settings. Default values are specified, later, for each settings as it is loaded
2644  settings.clear ();
2645  }
2646 
2647  settingsReadEnvironment (settings);
2648  settingsReadMainWindow (settings);
2649 }
2650 
2651 void MainWindow::settingsReadEnvironment (QSettings &settings)
2652 {
2653  settings.beginGroup (SETTINGS_GROUP_ENVIRONMENT);
2654  QDir::setCurrent (settings.value (SETTINGS_CURRENT_DIRECTORY,
2655  QDir::currentPath ()).toString ());
2656  settings.endGroup ();
2657 }
2658 
2659 void MainWindow::settingsReadMainWindow (QSettings &settings)
2660 {
2661  settings.beginGroup(SETTINGS_GROUP_MAIN_WINDOW);
2662 
2663  // Main window geometry
2664  resize (settings.value (SETTINGS_SIZE,
2665  QSize (600, 600)).toSize ());
2666  move (settings.value (SETTINGS_POS,
2667  QPoint (200, 200)).toPoint ());
2668 
2669  // Help window geometry
2670 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
2671  QSize helpSize = settings.value (SETTINGS_HELP_SIZE,
2672  QSize (900, 600)).toSize();
2673  m_helpWindow->resize (helpSize);
2674  if (settings.contains (SETTINGS_HELP_POS)) {
2675  QPoint helpPos = settings.value (SETTINGS_HELP_POS).toPoint();
2676  m_helpWindow->move (helpPos);
2677  }
2678 #endif
2679 
2680  // Checklist guide wizard
2681  m_actionHelpChecklistGuideWizard->setChecked (settings.value (SETTINGS_CHECKLIST_GUIDE_WIZARD,
2682  true).toBool ());
2683 
2684  // Background toolbar visibility
2685  bool viewBackgroundToolBar = settings.value (SETTINGS_VIEW_BACKGROUND_TOOLBAR,
2686  true).toBool ();
2687  m_actionViewBackground->setChecked (viewBackgroundToolBar);
2688  m_toolBackground->setVisible (viewBackgroundToolBar);
2689  BackgroundImage backgroundImage = (BackgroundImage) settings.value (SETTINGS_BACKGROUND_IMAGE,
2690  BACKGROUND_IMAGE_FILTERED).toInt ();
2691  int indexBackground = m_cmbBackground->findData (QVariant (backgroundImage));
2692  m_cmbBackground->setCurrentIndex (indexBackground);
2693 
2694  // Digitize toolbar visibility
2695  bool viewDigitizeToolBar = settings.value (SETTINGS_VIEW_DIGITIZE_TOOLBAR,
2696  true).toBool ();
2697  m_actionViewDigitize->setChecked (viewDigitizeToolBar);
2698  m_toolDigitize->setVisible (viewDigitizeToolBar);
2699 
2700  // Views toolbar visibility
2701  bool viewSettingsViewsToolBar = settings.value (SETTINGS_VIEW_SETTINGS_VIEWS_TOOLBAR,
2702  true).toBool ();
2703  m_actionViewSettingsViews->setChecked (viewSettingsViewsToolBar);
2704  m_toolSettingsViews->setVisible (viewSettingsViewsToolBar);
2705 
2706  // Coordinate system toolbar visibility
2707  bool viewCoordSystemToolbar = settings.value (SETTINGS_VIEW_COORD_SYSTEM_TOOLBAR,
2708  false).toBool ();
2709  m_actionViewCoordSystem->setChecked (viewCoordSystemToolbar);
2710  m_toolCoordSystem->setVisible (viewCoordSystemToolbar);
2711 
2712  // Tooltips visibility
2713  bool viewToolTips = settings.value (SETTINGS_VIEW_TOOL_TIPS,
2714  true).toBool ();
2715  m_actionViewToolTips->setChecked (viewToolTips);
2716  loadToolTips ();
2717 
2718  // Statusbar visibility
2719  StatusBarMode statusBarMode = (StatusBarMode) settings.value (SETTINGS_VIEW_STATUS_BAR,
2720  false).toInt ();
2721  m_statusBar->setStatusBarMode (statusBarMode);
2722  m_actionStatusNever->setChecked (statusBarMode == STATUS_BAR_MODE_NEVER);
2723  m_actionStatusTemporary->setChecked (statusBarMode == STATUS_BAR_MODE_TEMPORARY);
2724  m_actionStatusAlways->setChecked (statusBarMode == STATUS_BAR_MODE_ALWAYS);
2725 
2726  addDockWindow (m_dockChecklistGuide,
2727  settings,
2728  SETTINGS_CHECKLIST_GUIDE_DOCK_AREA,
2729  SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY,
2730  Qt::RightDockWidgetArea);
2731  addDockWindow (m_dockFittingWindow,
2732  settings,
2733  SETTINGS_FITTING_WINDOW_DOCK_AREA,
2734  SETTINGS_FITTING_WINDOW_DOCK_GEOMETRY,
2735  Qt::RightDockWidgetArea);
2736  addDockWindow (m_dockGeometryWindow,
2737  settings,
2738  SETTINGS_GEOMETRY_WINDOW_DOCK_AREA,
2739  SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY,
2740  Qt::RightDockWidgetArea);
2741 
2742  // Main window settings. Preference for initial zoom factor is 100%, rather than fill mode, for issue #25. Some or all
2743  // settings are saved to the application AND saved to m_modelMainWindow for use in DlgSettingsMainWindow. Note that
2744  // TranslatorContainer has previously extracted the locale from the settings
2745  QLocale localeDefault;
2746  QLocale::Language language = (QLocale::Language) settings.value (SETTINGS_LOCALE_LANGUAGE,
2747  QVariant (localeDefault.language())).toInt();
2748  QLocale::Country country = (QLocale::Country) settings.value (SETTINGS_LOCALE_COUNTRY,
2749  QVariant (localeDefault.country())).toInt();
2750  QLocale locale (language,
2751  country);
2752  slotViewZoom ((ZoomFactor) settings.value (SETTINGS_ZOOM_FACTOR,
2753  QVariant (ZOOM_1_TO_1)).toInt());
2754  m_modelMainWindow.setLocale (locale);
2755  m_modelMainWindow.setZoomFactorInitial((ZoomFactorInitial) settings.value (SETTINGS_ZOOM_FACTOR_INITIAL,
2756  QVariant (DEFAULT_ZOOM_FACTOR_INITIAL)).toInt());
2757  m_modelMainWindow.setZoomControl ((ZoomControl) settings.value (SETTINGS_ZOOM_CONTROL,
2758  QVariant (ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)).toInt());
2759  m_modelMainWindow.setMainTitleBarFormat ((MainTitleBarFormat) settings.value (SETTINGS_MAIN_TITLE_BAR_FORMAT,
2760  QVariant (MAIN_TITLE_BAR_FORMAT_PATH)).toInt());
2761  m_modelMainWindow.setPdfResolution (settings.value (SETTINGS_IMPORT_PDF_RESOLUTION,
2762  QVariant (DEFAULT_IMPORT_PDF_RESOLUTION)).toInt ());
2763  m_modelMainWindow.setImportCropping ((ImportCropping) settings.value (SETTINGS_IMPORT_CROPPING,
2764  QVariant (DEFAULT_IMPORT_CROPPING)).toInt ());
2765  m_modelMainWindow.setMaximumGridLines (settings.value (SETTINGS_MAXIMUM_GRID_LINES,
2766  QVariant (DEFAULT_MAXIMUM_GRID_LINES)).toInt ());
2767  m_modelMainWindow.setHighlightOpacity (settings.value (SETTINGS_HIGHLIGHT_OPACITY,
2768  QVariant (DEFAULT_HIGHLIGHT_OPACITY)).toDouble ());
2769  m_modelMainWindow.setSmallDialogs (settings.value (SETTINGS_SMALL_DIALOGS,
2770  QVariant (DEFAULT_SMALL_DIALOGS)).toBool ());
2771  m_modelMainWindow.setDragDropExport (settings.value (SETTINGS_DRAG_DROP_EXPORT,
2772  QVariant (DEFAULT_DRAG_DROP_EXPORT)).toBool ());
2773 
2775  updateSmallDialogs();
2776 
2777  settings.endGroup();
2778 }
2779 
2780 void MainWindow::settingsWrite ()
2781 {
2782  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
2783 
2784  settings.beginGroup (SETTINGS_GROUP_ENVIRONMENT);
2785  settings.setValue (SETTINGS_CURRENT_DIRECTORY, QDir::currentPath ());
2786  settings.endGroup ();
2787 
2788  settings.beginGroup (SETTINGS_GROUP_MAIN_WINDOW);
2789  settings.setValue (SETTINGS_SIZE, size ());
2790  settings.setValue (SETTINGS_POS, pos ());
2791 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
2792  settings.setValue (SETTINGS_HELP_SIZE, m_helpWindow->size());
2793  settings.setValue (SETTINGS_HELP_POS, m_helpWindow->pos ());
2794 #endif
2795  if (m_dockChecklistGuide->isFloating()) {
2796 
2797  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, Qt::NoDockWidgetArea);
2798  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_GEOMETRY, m_dockChecklistGuide->saveGeometry ());
2799 
2800  } else {
2801 
2802  settings.setValue (SETTINGS_CHECKLIST_GUIDE_DOCK_AREA, dockWidgetArea (m_dockChecklistGuide));
2803 
2804  }
2805  if (m_dockFittingWindow->isFloating()) {
2806 
2807  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_AREA, Qt::NoDockWidgetArea);
2808  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_GEOMETRY, m_dockFittingWindow->saveGeometry());
2809  } else {
2810 
2811  settings.setValue (SETTINGS_FITTING_WINDOW_DOCK_AREA, dockWidgetArea (m_dockFittingWindow));
2812  }
2813  if (m_dockGeometryWindow->isFloating()) {
2814 
2815  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, Qt::NoDockWidgetArea);
2816  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_GEOMETRY, m_dockGeometryWindow->saveGeometry ());
2817 
2818  } else {
2819 
2820  settings.setValue (SETTINGS_GEOMETRY_WINDOW_DOCK_AREA, dockWidgetArea (m_dockGeometryWindow));
2821 
2822  }
2823  settings.setValue (SETTINGS_BACKGROUND_IMAGE, m_cmbBackground->currentData().toInt());
2824  settings.setValue (SETTINGS_CHECKLIST_GUIDE_WIZARD, m_actionHelpChecklistGuideWizard->isChecked ());
2825  settings.setValue (SETTINGS_DRAG_DROP_EXPORT, m_modelMainWindow.dragDropExport ());
2826  settings.setValue (SETTINGS_HIGHLIGHT_OPACITY, m_modelMainWindow.highlightOpacity());
2827  settings.setValue (SETTINGS_IMPORT_CROPPING, m_modelMainWindow.importCropping());
2828  settings.setValue (SETTINGS_IMPORT_PDF_RESOLUTION, m_modelMainWindow.pdfResolution ());
2829  settings.setValue (SETTINGS_LOCALE_LANGUAGE, m_modelMainWindow.locale().language());
2830  settings.setValue (SETTINGS_LOCALE_COUNTRY, m_modelMainWindow.locale().country());
2831  settings.setValue (SETTINGS_MAIN_TITLE_BAR_FORMAT, m_modelMainWindow.mainTitleBarFormat());
2832  settings.setValue (SETTINGS_MAXIMUM_GRID_LINES, m_modelMainWindow.maximumGridLines());
2833  settings.setValue (SETTINGS_SMALL_DIALOGS, m_modelMainWindow.smallDialogs());
2834  settings.setValue (SETTINGS_VIEW_BACKGROUND_TOOLBAR, m_actionViewBackground->isChecked());
2835  settings.setValue (SETTINGS_VIEW_DIGITIZE_TOOLBAR, m_actionViewDigitize->isChecked ());
2836  settings.setValue (SETTINGS_VIEW_STATUS_BAR, m_statusBar->statusBarMode ());
2837  settings.setValue (SETTINGS_VIEW_SETTINGS_VIEWS_TOOLBAR, m_actionViewSettingsViews->isChecked ());
2838  settings.setValue (SETTINGS_VIEW_COORD_SYSTEM_TOOLBAR, m_actionViewCoordSystem->isChecked ());
2839  settings.setValue (SETTINGS_VIEW_TOOL_TIPS, m_actionViewToolTips->isChecked ());
2840  settings.setValue (SETTINGS_ZOOM_CONTROL, m_modelMainWindow.zoomControl());
2841  settings.setValue (SETTINGS_ZOOM_FACTOR, currentZoomFactor ());
2842  settings.setValue (SETTINGS_ZOOM_FACTOR_INITIAL, m_modelMainWindow.zoomFactorInitial());
2843  settings.endGroup ();
2844 }
2845 
2846 bool MainWindow::setupAfterLoadNewDocument (const QString &fileName,
2847  const QString &temporaryMessage ,
2848  ImportType importType)
2849 {
2850  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setupAfterLoadNewDocument"
2851  << " file=" << fileName.toLatin1().data()
2852  << " message=" << temporaryMessage.toLatin1().data()
2853  << " importType=" << importType;
2854 
2855  // The steps in this method should theoretically be a superset of the steps in setupAfterLoadNewDocument. Therefore, any
2856  // changes to this method should be considered for application to the other method also
2857 
2858  const QString EMPTY_CURVE_NAME_TO_SKIP_BACKGROUND_PROCESSING; // For bootstrapping the preview
2859 
2860  // At this point the code assumes CmdMediator for the NEW Document is already stored in m_cmdMediator
2861 
2862  m_digitizeStateContext->resetOnLoad (m_cmdMediator); // Before setPixmap
2863  m_backgroundStateContext->setCurveSelected (m_transformation,
2864  m_cmdMediator->document().modelGridRemoval(),
2865  m_cmdMediator->document().modelColorFilter(),
2866  EMPTY_CURVE_NAME_TO_SKIP_BACKGROUND_PROCESSING); // Before setPixmap
2867  setPixmap (m_cmdMediator->document().curvesGraphsNames().first(),
2868  m_cmdMediator->pixmap ()); // Set background immediately so it is visible as a preview when any dialogs are displayed
2869 
2870  // Image is visible now so the user can refer to it when we ask for the number of coordinate systems. Note that the Document
2871  // may already have multiple CoordSystem if user loaded a file that had multiple CoordSystem entries
2872  if (importType == IMPORT_TYPE_ADVANCED) {
2873 
2874  applyZoomFactorAfterLoad(); // Apply the currently selected zoom factor
2875 
2876  DlgImportAdvanced dlgImportAdvanced (*this);
2877  dlgImportAdvanced.exec();
2878 
2879  if (dlgImportAdvanced.result() == QDialog::Rejected) {
2880  return false;
2881  }
2882 
2883  int numberCoordSystem = dlgImportAdvanced.numberCoordSystem();
2884  m_cmdMediator->document().addCoordSystems (numberCoordSystem - 1);
2885  m_cmdMediator->setDocumentAxesPointsRequired (dlgImportAdvanced.documentAxesPointsRequired());
2886  }
2887 
2888  m_transformation.resetOnLoad();
2889  m_transformationStateContext->resetOnLoad();
2890  m_scene->resetOnLoad();
2891 
2892  connect (m_actionEditUndo, SIGNAL (triggered ()), m_cmdMediator, SLOT (undo ()));
2893  connect (m_actionEditUndo, SIGNAL (triggered ()), m_cmdStackShadow, SLOT (slotUndo ()));
2894  connect (m_actionEditRedo, SIGNAL (triggered ()), m_cmdMediator, SLOT (redo ())); // No effect until CmdMediator::undo and CmdStackShadow::slotUndo get called
2895  connect (m_actionEditRedo, SIGNAL (triggered ()), m_cmdStackShadow, SLOT (slotRedo ())); // No effect after CmdMediator::undo and CmdStackShadow::slotUndo get called
2896  connect (m_cmdMediator, SIGNAL (canRedoChanged(bool)), this, SLOT (slotCanRedoChanged (bool)));
2897  connect (m_cmdMediator, SIGNAL (canUndoChanged(bool)), this, SLOT (slotCanUndoChanged (bool)));
2898  connect (m_cmdMediator, SIGNAL (redoTextChanged (const QString &)), this, SLOT (slotRedoTextChanged (const QString &)));
2899  connect (m_cmdMediator, SIGNAL (undoTextChanged (const QString &)), this, SLOT (slotUndoTextChanged (const QString &)));
2900  loadCurveListFromCmdMediator ();
2901  loadCoordSystemListFromCmdMediator ();
2903 
2904  m_isDocumentExported = false;
2905 
2906  // Background must be set (by setPixmap) before slotViewZoomFactor which relies on the background. At this point
2907  // the transformation is undefined (unless the code is changed) so grid removal will not work
2908  // but updateTransformationAndItsDependencies will call this again to fix that issue. Note that the selected
2909  // curve name was set (by setCurveSelected) earlier before the call to setPixmap
2910  m_backgroundStateContext->setCurveSelected (m_transformation,
2911  m_cmdMediator->document().modelGridRemoval(),
2912  m_cmdMediator->document().modelColorFilter(),
2913  m_cmbCurve->currentText ());
2914  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) m_cmbBackground->currentIndex ());
2915 
2916  applyZoomFactorAfterLoad(); // Zoom factor must be reapplied after background image is set, to have any effect
2917 
2918  setCurrentFile(fileName);
2919  m_statusBar->showTemporaryMessage (temporaryMessage);
2920  m_statusBar->wakeUp ();
2921 
2922  saveStartingDocumentSnapshot();
2923 
2924  updateAfterCommand(); // Replace stale points by points in new Document
2925 
2926  return true;
2927 }
2928 
2929 bool MainWindow::setupAfterLoadReplacingImage (const QString &fileName,
2930  const QString &temporaryMessage ,
2931  ImportType importType)
2932 {
2933  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::setupAfterLoadReplacingImage"
2934  << " file=" << fileName.toLatin1().data()
2935  << " message=" << temporaryMessage.toLatin1().data()
2936  << " importType=" << importType;
2937 
2938  // The steps in this method should theoretically be just a subset of the steps in setupAfterLoadNewDocument
2939 
2940  // After this point there should be no commands in CmdMediator, since we effectively have a new document
2941  m_cmdMediator->clear();
2942 
2943  setPixmap (m_cmdMediator->document().curvesGraphsNames().first(),
2944  m_cmdMediator->pixmap ()); // Set background immediately so it is visible as a preview when any dialogs are displayed
2945 
2946  m_isDocumentExported = false;
2947 
2948  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) m_cmbBackground->currentIndex ());
2949 
2950  applyZoomFactorAfterLoad(); // Zoom factor must be reapplied after background image is set, to have any effect
2951 
2952  setCurrentFile(fileName);
2953  m_statusBar->showTemporaryMessage (temporaryMessage);
2954  m_statusBar->wakeUp ();
2955 
2956  saveStartingDocumentSnapshot();
2957 
2958  updateAfterCommand(); // Replace stale points by points in new Document
2959 
2960  return true;
2961 }
2962 
2963 void MainWindow::showEvent (QShowEvent *event)
2964 {
2965  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::showEvent"
2966  << " files=" << m_loadStartupFiles.join (",").toLatin1().data();
2967 
2968  QMainWindow::showEvent (event);
2969 
2970  if (m_loadStartupFiles.count() > 0) {
2971 
2972  m_timerLoadStartupFiles = new QTimer;
2973  m_timerLoadStartupFiles->setSingleShot (true);
2974  connect (m_timerLoadStartupFiles, SIGNAL (timeout ()), this, SLOT (slotLoadStartupFiles ()));
2975  m_timerLoadStartupFiles->start (0); // Zero delay still waits until execution finishes and gui is available
2976 
2977  }
2978 }
2979 
2980 void MainWindow::showTemporaryMessage (const QString &temporaryMessage)
2981 {
2982  m_statusBar->showTemporaryMessage (temporaryMessage);
2983 }
2984 
2985 void MainWindow::slotBtnPrintAll ()
2986 {
2987  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnPrintAll";
2988 
2989  ghostsCreate ();
2990 
2991  QPrinter printer (QPrinter::HighResolution);
2992  QPrintDialog dlg (&printer, this);
2993  if (dlg.exec() == QDialog::Accepted) {
2994  QPainter painter (&printer);
2995  m_view->render (&painter);
2996  painter.end();
2997  }
2998 
2999  ghostsDestroy ();
3000 }
3001 
3002 void MainWindow::slotBtnShowAllPressed ()
3003 {
3004  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnShowAllPressed";
3005 
3006  // Start of press-release sequence
3007  ghostsCreate ();
3008 }
3009 
3010 void MainWindow::slotBtnShowAllReleased ()
3011 {
3012  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotBtnShowAllReleased";
3013 
3014  // End of press-release sequence
3015  ghostsDestroy ();
3016 }
3017 
3018 void MainWindow::slotCanRedoChanged (bool canRedo)
3019 {
3020  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotCanRedoChanged";
3021 
3022  m_actionEditRedo->setEnabled (canRedo || m_cmdStackShadow->canRedo());
3023 }
3024 
3025 void MainWindow::slotCanUndoChanged (bool canUndo)
3026 {
3027  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotCanUndoChanged";
3028 
3029  m_actionEditUndo->setEnabled (canUndo);
3030 }
3031 
3032 void MainWindow::slotChecklistClosed()
3033 {
3034  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotChecklistClosed";
3035 
3036  m_actionViewChecklistGuide->setChecked (false);
3037 }
3038 
3039 void MainWindow::slotCleanChanged(bool clean)
3040 {
3041  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCleanChanged";
3042 
3043  setWindowModified (!clean);
3044 }
3045 
3046 void MainWindow::slotCmbBackground(int currentIndex)
3047 {
3048  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbBackground";
3049 
3050  switch (currentIndex) {
3051  case BACKGROUND_IMAGE_NONE:
3052  if (!m_actionViewBackgroundNone->isChecked()) {
3053  m_actionViewBackgroundNone->toggle();
3054  }
3055  break;
3056 
3057  case BACKGROUND_IMAGE_ORIGINAL:
3058  if (!m_actionViewBackgroundOriginal->isChecked ()) {
3059  m_actionViewBackgroundOriginal->toggle();
3060  }
3061  break;
3062 
3063  case BACKGROUND_IMAGE_FILTERED:
3064  if (!m_actionViewBackgroundFiltered->isChecked ()) {
3065  m_actionViewBackgroundFiltered->toggle();
3066  }
3067  break;
3068  }
3069 
3070  m_backgroundStateContext->setBackgroundImage ((BackgroundImage) currentIndex);
3071 }
3072 
3073 void MainWindow::slotCmbCoordSystem(int index)
3074 {
3075  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbCoordSystem";
3076 
3077  CmdSelectCoordSystem *cmd = new CmdSelectCoordSystem (*this,
3078  m_cmdMediator->document(),
3079  index);
3080 
3081  m_cmdMediator->push (cmd);
3082 }
3083 
3084 void MainWindow::slotCmbCurve(int /* index */)
3085 {
3086  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotCmbCurve";
3087 
3088  m_backgroundStateContext->setCurveSelected (m_transformation,
3089  m_cmdMediator->document().modelGridRemoval(),
3090  m_cmdMediator->document().modelColorFilter(),
3091  m_cmbCurve->currentText ());
3092  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
3093  m_cmdMediator->setSelectedCurveName (m_cmbCurve->currentText ()); // Save for next time current coordinate system returns
3094 
3095  updateViewedCurves();
3097  updateFittingWindow();
3098  updateGeometryWindow();
3099 }
3100 
3101 void MainWindow::slotContextMenuEventAxis (QString pointIdentifier)
3102 {
3103  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventAxis point=" << pointIdentifier.toLatin1 ().data ();
3104 
3105  m_digitizeStateContext->handleContextMenuEventAxis (m_cmdMediator,
3106  pointIdentifier);
3107 }
3108 
3109 void MainWindow::slotContextMenuEventGraph (QStringList pointIdentifiers)
3110 {
3111  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotContextMenuEventGraph point=" << pointIdentifiers.join(",").toLatin1 ().data ();
3112 
3113  m_digitizeStateContext->handleContextMenuEventGraph (m_cmdMediator,
3114  pointIdentifiers);
3115 }
3116 
3117 void MainWindow::slotDigitizeAxis ()
3118 {
3119  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeAxis";
3120 
3121  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3122  DIGITIZE_STATE_AXIS);
3123  m_cmbCurve->setEnabled (false); // Graph curve is irrelevant in this mode
3124  m_viewPointStyle->setEnabled (true); // Point style is important in this mode
3125  m_viewSegmentFilter->setEnabled (true); // Filtering is important in this mode
3126  updateControls (); // For Paste which is state dependent
3127 }
3128 
3129 void MainWindow::slotDigitizeColorPicker ()
3130 {
3131  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeColorPicker";
3132 
3133  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3134  DIGITIZE_STATE_COLOR_PICKER);
3135  m_cmbCurve->setEnabled (true);
3136  m_viewPointStyle->setEnabled (true);
3137  m_viewSegmentFilter->setEnabled (true);
3138  updateControls (); // For Paste which is state dependent
3139 }
3140 
3141 void MainWindow::slotDigitizeCurve ()
3142 {
3143  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeCurve";
3144 
3145  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3146  DIGITIZE_STATE_CURVE);
3147  m_cmbCurve->setEnabled (true);
3148  m_viewPointStyle->setEnabled (true);
3149  m_viewSegmentFilter->setEnabled (true);
3150  updateControls (); // For Paste which is state dependent
3151 }
3152 
3153 void MainWindow::slotDigitizePointMatch ()
3154 {
3155  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizePointMatch";
3156 
3157  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3158  DIGITIZE_STATE_POINT_MATCH);
3159  m_cmbCurve->setEnabled (true);
3160  m_viewPointStyle->setEnabled (true);
3161  m_viewSegmentFilter->setEnabled (true);
3162  updateControls (); // For Paste which is state dependent
3163 }
3164 
3165 void MainWindow::slotDigitizeScale ()
3166 {
3167  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeScale";
3168 
3169  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3170  DIGITIZE_STATE_SCALE);
3171  m_cmbCurve->setEnabled (false);
3172  m_viewPointStyle->setEnabled (false);
3173  m_viewSegmentFilter->setEnabled (false);
3174  updateControls (); // For Paste which is state dependent
3175 }
3176 
3177 void MainWindow::slotDigitizeSegment ()
3178 {
3179  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeSegment";
3180 
3181  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3182  DIGITIZE_STATE_SEGMENT);
3183  m_cmbCurve->setEnabled (true);
3184  m_viewPointStyle->setEnabled (true);
3185  m_viewSegmentFilter->setEnabled (true);
3186  updateControls (); // For Paste which is state dependent
3187 }
3188 
3189 void MainWindow::slotDigitizeSelect ()
3190 {
3191  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotDigitizeSelect";
3192 
3193  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3194  DIGITIZE_STATE_SELECT);
3195  m_cmbCurve->setEnabled (false);
3196  m_viewPointStyle->setEnabled (false);
3197  m_viewSegmentFilter->setEnabled (false);
3198  updateControls (); // For Paste which is state dependent
3199 }
3200 
3201 void MainWindow::slotEditCopy ()
3202 {
3203  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCopy";
3204 
3205  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
3206  bool tableFittingIsActive, tableFittingIsCopyable;
3207  bool tableGeometryIsActive, tableGeometryIsCopyable;
3208  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
3209  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
3210 
3211  if (tableFittingIsActive) {
3212 
3213  // Send to FittingWindow
3214  m_dockFittingWindow->doCopy ();
3215 
3216  } else if (tableGeometryIsActive) {
3217 
3218  // Send to GeometryWindow
3219  m_dockGeometryWindow->doCopy ();
3220 
3221  } else {
3222 
3223  // Process curve points in main window
3224  GraphicsItemsExtractor graphicsItemsExtractor;
3225  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
3226  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
3227 
3228  CmdCopy *cmd = new CmdCopy (*this,
3229  m_cmdMediator->document(),
3230  pointIdentifiers);
3231  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
3232  cmd);
3233  }
3234 }
3235 
3236 void MainWindow::slotEditCut ()
3237 {
3238  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditCut";
3239 
3240  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
3241  bool tableFittingIsActive, tableFittingIsCopyable;
3242  bool tableGeometryIsActive, tableGeometryIsCopyable;
3243  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
3244  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
3245 
3246  if (tableFittingIsActive || tableGeometryIsActive) {
3247 
3248  // Cannot delete from fitting or geometry windows
3249 
3250  } else {
3251 
3252  // Process curve points in main window
3253  GraphicsItemsExtractor graphicsItemsExtractor;
3254  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
3255  QStringList pointIdentifiers = graphicsItemsExtractor.selectedPointIdentifiers (items);
3256 
3257  CmdCut *cmd = new CmdCut (*this,
3258  m_cmdMediator->document(),
3259  pointIdentifiers);
3260  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
3261  cmd);
3262  }
3263 }
3264 
3265 void MainWindow::slotEditDelete ()
3266 {
3267  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditDelete";
3268 
3269  // Copy command is sent to FittingWindow or GeometryWindow, or processed locally
3270  bool tableFittingIsActive, tableFittingIsCopyable;
3271  bool tableGeometryIsActive, tableGeometryIsCopyable;
3272  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
3273  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
3274 
3275  if (tableFittingIsActive || tableGeometryIsActive) {
3276 
3277  // Cannot delete from fitting or geometry windows
3278 
3279  } else {
3280 
3281  // If this is a map, which has a scale bar with two axis points, then selection of just one axis point
3282  // for deletion should result in deletion of the other point also so this object will enforce that. Otherwise
3283  // this class has no effect below
3284  ScaleBarAxisPointsUnite scaleBarAxisPoints;
3285 
3286  // Process curve points in main window
3287  GraphicsItemsExtractor graphicsItemsExtractor;
3288  const QList<QGraphicsItem*> &items = m_scene->selectedItems();
3289  QStringList pointIdentifiers = scaleBarAxisPoints.unite (m_cmdMediator,
3290  graphicsItemsExtractor.selectedPointIdentifiers (items));
3291 
3292  CmdDelete *cmd = new CmdDelete (*this,
3293  m_cmdMediator->document(),
3294  pointIdentifiers);
3295  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
3296  cmd);
3297  }
3298 }
3299 
3300 void MainWindow::slotEditMenu ()
3301 {
3302  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditMenu";
3303 
3304  m_actionEditPasteAsNew->setEnabled (!QApplication::clipboard()->image().isNull());
3305  m_actionEditPasteAsNewAdvanced->setEnabled (!QApplication::clipboard()->image().isNull());
3306 }
3307 
3308 void MainWindow::slotEditPaste ()
3309 {
3310  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPaste";
3311 
3312  QList<QPoint> points;
3313  QList<double> ordinals;
3314 
3315  MimePointsImport mimePointsImport;
3316  mimePointsImport.retrievePoints (m_transformation,
3317  points,
3318  ordinals);
3319 
3320  CmdAddPointsGraph *cmd = new CmdAddPointsGraph (*this,
3321  m_cmdMediator->document(),
3322  m_cmbCurve->currentText (),
3323  points,
3324  ordinals);
3325  m_digitizeStateContext->appendNewCmd (m_cmdMediator,
3326  cmd);
3327 }
3328 
3329 void MainWindow::slotEditPasteAsNew ()
3330 {
3331  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPasteAsNew";
3332 
3333  filePaste (IMPORT_TYPE_SIMPLE);
3334 }
3335 
3336 void MainWindow::slotEditPasteAsNewAdvanced ()
3337 {
3338  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotEditPasteAsNewAdvanced";
3339 
3340  filePaste (IMPORT_TYPE_ADVANCED);
3341 }
3342 
3343 void MainWindow::slotFileClose()
3344 {
3345  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileClose";
3346 
3347  if (maybeSave ()) {
3348 
3349  // Transition from defined to undefined. This must be after the clearing of the screen
3350  // since the axes checker screen item (and maybe others) must still exist
3351  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
3352  *m_cmdMediator,
3353  m_transformation,
3354  selectedGraphCurve());
3355 
3356  // Transition to empty state so an inadvertent mouse press does not trigger, for example,
3357  // the creation of an axis point on a non-existent GraphicsScene (=crash)
3358  m_digitizeStateContext->requestImmediateStateTransition (m_cmdMediator,
3359  DIGITIZE_STATE_EMPTY);
3360 
3361  // Deallocate fitted curve
3362  if (m_fittingCurve != 0) {
3363  m_scene->removeItem (m_fittingCurve);
3364  m_fittingCurve = 0;
3365  }
3366 
3367  // Remove screen objects
3368  m_scene->resetOnLoad ();
3369 
3370  // Remove background
3371  m_backgroundStateContext->close ();
3372 
3373  // Remove scroll bars if they exist
3374  m_scene->setSceneRect (QRectF (0, 0, 1, 1));
3375 
3376  // Remove stale data from fitting window
3377  m_dockFittingWindow->clear ();
3378 
3379  // Remove stale data from geometry window
3380  m_dockGeometryWindow->clear ();
3381 
3382  // Deallocate Document
3383  delete m_cmdMediator;
3384 
3385  // Remove file information
3386  m_cmdMediator = 0;
3387  m_currentFile = "";
3388  m_engaugeFile = "";
3389  setWindowTitle (engaugeWindowTitle ());
3390 
3391  m_gridLines.clear();
3392  updateControls();
3393  }
3394 }
3395 
3396 void MainWindow::slotFileExport ()
3397 {
3398  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileExport";
3399 
3400  if (m_transformation.transformIsDefined()) {
3401 
3402  ExportToFile exportStrategy;
3403  QString filter = QString ("%1;;%2;;All files (*.*)")
3404  .arg (exportStrategy.filterCsv ())
3405  .arg (exportStrategy.filterTsv ());
3406 
3407  // OSX sandbox requires, for the default, a non-empty filename
3408  MainDirectoryPersist directoryPersist;
3409  QString defaultFileName = QString ("%1/%2.%3")
3410  .arg (directoryPersist.getDirectoryExportSave().path ())
3411  .arg (m_currentFile)
3412  .arg (exportStrategy.fileExtensionCsv ());
3413  QFileDialog dlg;
3414  QString filterCsv = exportStrategy.filterCsv ();
3415  QString fileName = dlg.getSaveFileName (this,
3416  tr("Export"),
3417  defaultFileName,
3418  filter,
3419  &filterCsv);
3420  if (!fileName.isEmpty ()) {
3421 
3422  directoryPersist.setDirectoryExportSaveFromFilename(fileName);
3423  fileExport(fileName,
3424  exportStrategy);
3425  }
3426  } else {
3427  DlgRequiresTransform dlg ("Export");
3428  dlg.exec ();
3429  }
3430 }
3431 
3432 void MainWindow::slotFileImport ()
3433 {
3434  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImport";
3435 
3436  fileImportWithPrompts (IMPORT_TYPE_SIMPLE);
3437 }
3438 
3439 void MainWindow::slotFileImportAdvanced ()
3440 {
3441  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportAdvanced";
3442 
3443  fileImportWithPrompts (IMPORT_TYPE_ADVANCED);
3444 }
3445 
3446 void MainWindow::slotFileImportDraggedImage(QImage image)
3447 {
3448  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportDraggedImage";
3449 
3450  // No need to check return value from loadImage since there are no prompts that give the user a chance to cancel
3451  loadImage ("",
3452  image,
3453  IMPORT_TYPE_SIMPLE);
3454 }
3455 
3456 void MainWindow::slotFileImportDraggedImageUrl(QUrl url)
3457 {
3458  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportDraggedImageUrl url=" << url.toString ().toLatin1 ().data ();
3459 
3460 #ifdef NETWORKING
3461  m_loadImageFromUrl->startLoadImage (url);
3462 #endif
3463 }
3464 
3465 void MainWindow::slotFileImportImage(QString fileName, QImage image)
3466 {
3467  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportImage fileName=" << fileName.toLatin1 ().data ();
3468 
3469  // No need to check return value from loadImage since there are no prompts that give the user a chance to cancel
3470  loadImage (fileName,
3471  image,
3472  IMPORT_TYPE_SIMPLE);
3473 }
3474 
3475 void MainWindow::slotFileImportImageReplace ()
3476 {
3477  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileImportImageReplace";
3478 
3479  fileImportWithPrompts (IMPORT_TYPE_IMAGE_REPLACE);
3480 }
3481 
3482 void MainWindow::slotFileOpen()
3483 {
3484  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileOpen";
3485 
3486  if (maybeSave ()) {
3487 
3488  // Allow selection of files with strange suffixes in case the file extension was changed. Since
3489  // the default is the first filter, the wildcard filter is added afterwards (it is the off-nominal case)
3490  QString filter = QString ("%1 (*.%2);; All Files (*.*)")
3491  .arg (ENGAUGE_FILENAME_DESCRIPTION)
3492  .arg (ENGAUGE_FILENAME_EXTENSION);
3493 
3494  MainDirectoryPersist directoryPersist;
3495  QString fileName = QFileDialog::getOpenFileName (this,
3496  tr("Open Document"),
3497  directoryPersist.getDirectoryImportOpen ().path (),
3498  filter);
3499  if (!fileName.isEmpty ()) {
3500 
3501  directoryPersist.setDirectoryImportOpenFromFilename (fileName);
3502  loadDocumentFile (fileName);
3503 
3504  }
3505  }
3506 }
3507 
3508 void MainWindow::slotFileOpenDraggedDigFile (QString fileName)
3509 {
3510  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileOpenDraggedDigFile";
3511 
3512  loadDocumentFile (fileName);
3513 }
3514 
3515 void MainWindow::slotFilePrint()
3516 {
3517  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFilePrint";
3518 
3519  QPrinter printer (QPrinter::HighResolution);
3520  QPrintDialog dlg (&printer, this);
3521  if (dlg.exec() == QDialog::Accepted) {
3522  QPainter painter (&printer);
3523  m_view->render (&painter);
3524  painter.end();
3525  }
3526 }
3527 
3528 bool MainWindow::slotFileSave()
3529 {
3530  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileSave";
3531 
3532  if (m_engaugeFile.isEmpty()) {
3533  return slotFileSaveAs();
3534  } else {
3535  return saveDocumentFile (m_engaugeFile);
3536  }
3537 }
3538 
3539 bool MainWindow::slotFileSaveAs()
3540 {
3541  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFileSaveAs";
3542 
3543  // Append engauge file extension if it is not already there
3544  QString filenameDefault = m_currentFile;
3545  if (!m_currentFile.endsWith (ENGAUGE_FILENAME_EXTENSION)) {
3546  filenameDefault = QString ("%1.%2")
3547  .arg (m_currentFile)
3548  .arg (ENGAUGE_FILENAME_EXTENSION);
3549  }
3550 
3551  if (!m_engaugeFile.isEmpty()) {
3552  filenameDefault = m_engaugeFile;
3553  }
3554 
3555  QString filterDigitizer = QString ("%1 (*.%2)")
3556  .arg (ENGAUGE_FILENAME_DESCRIPTION)
3557  .arg (ENGAUGE_FILENAME_EXTENSION);
3558  QString filterAll ("All files (*. *)");
3559 
3560  QStringList filters;
3561  filters << filterDigitizer;
3562  filters << filterAll;
3563 
3564  MainDirectoryPersist directoryPersist;
3565 
3566  QFileDialog dlg(this);
3567  dlg.setFileMode (QFileDialog::AnyFile);
3568  dlg.selectNameFilter (filterDigitizer);
3569  dlg.setNameFilters (filters);
3570 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
3571  // Prevent hang in OSX
3572  dlg.setWindowModality(Qt::WindowModal);
3573 #endif
3574  dlg.setAcceptMode(QFileDialog::AcceptSave);
3575  dlg.selectFile(filenameDefault);
3576  dlg.setDirectory (directoryPersist.getDirectoryExportSave ());
3577  if (dlg.exec()) {
3578 
3579  QStringList files = dlg.selectedFiles();
3580  directoryPersist.setDirectoryExportSaveFromFilename (files.at(0));
3581  return saveDocumentFile(files.at(0));
3582  }
3583 
3584  return false;
3585 }
3586 
3587 void MainWindow::slotFittingWindowClosed()
3588 {
3589  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFittingWindowClosed";
3590 
3591  m_actionViewFittingWindow->setChecked (false);
3592 }
3593 
3594 void MainWindow::slotFittingWindowCurveFit(FittingCurveCoefficients fittingCurveCoef,
3595  double xMin,
3596  double xMax,
3597  bool isLogXTheta,
3598  bool isLogYRadius)
3599 {
3600  // Do not output elements in fittingCurveCoef here since that list may be empty
3601  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotFittingWindowCurveFit"
3602  << " order=" << fittingCurveCoef.size() - 1;
3603 
3604  if (m_fittingCurve != 0) {
3605  m_scene->removeItem (m_fittingCurve);
3606  delete m_fittingCurve;
3607  m_fittingCurve = 0;
3608  }
3609 
3610  m_fittingCurve = new FittingCurve (fittingCurveCoef,
3611  xMin,
3612  xMax,
3613  isLogXTheta,
3614  isLogYRadius,
3615  m_transformation);
3616  m_fittingCurve->setVisible (m_actionViewFittingWindow->isChecked ());
3617  m_scene->addItem (m_fittingCurve);
3618 }
3619 
3620 void MainWindow::slotGeometryWindowClosed()
3621 {
3622  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotGeometryWindowClosed";
3623 
3624  m_actionViewGeometryWindow->setChecked (false);
3625 }
3626 
3627 void MainWindow::slotHelpAbout()
3628 {
3629  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpAbout";
3630 
3631  DlgAbout dlg (*this);
3632  dlg.exec ();
3633 }
3634 
3635 void MainWindow::slotHelpTutorial()
3636 {
3637  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotHelpTutorial";
3638 
3639  m_tutorialDlg->show ();
3640  m_tutorialDlg->exec ();
3641 }
3642 
3643 void MainWindow::slotKeyPress (Qt::Key key,
3644  bool atLeastOneSelectedItem)
3645 {
3646  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotKeyPress"
3647  << " key=" << QKeySequence (key).toString().toLatin1 ().data ()
3648  << " atLeastOneSelectedItem=" << (atLeastOneSelectedItem ? "true" : "false");
3649 
3650  m_digitizeStateContext->handleKeyPress (m_cmdMediator,
3651  key,
3652  atLeastOneSelectedItem);
3653 }
3654 
3655 void MainWindow::slotLoadStartupFiles ()
3656 {
3657  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotLoadStartupFiles";
3658 
3659  ENGAUGE_ASSERT (m_loadStartupFiles.count() > 0);
3660 
3661  QString fileName = m_loadStartupFiles.front(); // Get next file name
3662  m_loadStartupFiles.pop_front(); // Remove next file name
3663 
3664  // Load next file into this instance of Engauge
3665  LoadFileInfo loadFileInfo;
3666  if (loadFileInfo.loadsAsDigFile(fileName)) {
3667 
3668  loadDocumentFile (fileName);
3669 
3670  } else {
3671 
3672  fileImport (fileName,
3673  IMPORT_TYPE_SIMPLE);
3674 
3675  }
3676 
3677  if (m_loadStartupFiles.count() > 0) {
3678 
3679  // Fork off another instance of this application to handle the remaining files recursively. New process
3680  // is detached so killing/terminating this process does not automatically kill the child process(es) also
3681  QProcess::startDetached (QCoreApplication::applicationFilePath(),
3682  m_loadStartupFiles);
3683  }
3684 }
3685 
3686 void MainWindow::slotMouseMove (QPointF pos)
3687 {
3688 // LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotMouseMove pos=" << QPointFToString (pos).toLatin1 ().data ();
3689 
3690  // Ignore mouse moves before Document is loaded
3691  if (m_cmdMediator != 0) {
3692 
3693  // Get status bar coordinates
3694  QString coordsScreen, coordsGraph, resolutionGraph;
3695  m_transformation.coordTextForStatusBar (pos,
3696  coordsScreen,
3697  coordsGraph,
3698  resolutionGraph,
3699  modeMap ());
3700 
3701  // Update status bar coordinates
3702  m_statusBar->setCoordinates (coordsScreen,
3703  coordsGraph,
3704  resolutionGraph);
3705 
3706  // There used to be a call to updateGraphicsLinesToMatchGraphicsPoints here, but that resulted
3707  // in hundreds of gratuitous log messages as the cursor was moved around, and nothing important happened
3708 
3709  m_digitizeStateContext->handleMouseMove (m_cmdMediator,
3710  pos);
3711  }
3712 }
3713 
3714 void MainWindow::slotMousePress (QPointF pos)
3715 {
3716  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMousePress";
3717 
3718  m_scene->resetPositionHasChangedFlags();
3719 
3720  m_digitizeStateContext->handleMousePress (m_cmdMediator,
3721  pos);
3722 }
3723 
3724 void MainWindow::slotMouseRelease (QPointF pos)
3725 {
3726  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotMouseRelease";
3727 
3728  if (pos.x() < 0 || pos.y() < 0) {
3729 
3730  // Cursor is outside the image so drop this event. However, call updateControls since this may be
3731  // a click-and-drag to select in which case the controls (especially Copy and Cut) reflect the new selection
3732  updateControls ();
3733 
3734  } else {
3735 
3736  // Cursor is within the image so process this as a normal mouse release
3737  m_digitizeStateContext->handleMouseRelease (m_cmdMediator,
3738  pos);
3739  }
3740 }
3741 
3742 void MainWindow::slotRecentFileAction ()
3743 {
3744  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileAction";
3745 
3746  QAction *action = qobject_cast<QAction*>(sender ());
3747 
3748  if (action) {
3749  QString fileName = action->data().toString();
3750  loadDocumentFile (fileName);
3751  }
3752 }
3753 
3754 void MainWindow::slotRecentFileClear ()
3755 {
3756  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotRecentFileClear";
3757 
3758  QStringList emptyList;
3759 
3760  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
3761  settings.setValue (SETTINGS_RECENT_FILE_LIST,
3762  emptyList);
3763 
3764  updateRecentFileList();
3765 }
3766 
3767 void MainWindow::slotRedoTextChanged (const QString &text)
3768 {
3769  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotRedoTextChanged";
3770 
3771  QString completeText ("Redo");
3772  if (!text.isEmpty ()) {
3773  completeText += QString (" \"%1\"").arg (text);
3774  }
3775  m_actionEditRedo->setText (completeText);
3776 }
3777 
3778 void MainWindow::slotSettingsAxesChecker ()
3779 {
3780  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsAxesChecker";
3781 
3782  m_dlgSettingsAxesChecker->load (*m_cmdMediator);
3783  m_dlgSettingsAxesChecker->show ();
3784 }
3785 
3786 void MainWindow::slotSettingsColorFilter ()
3787 {
3788  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsColorFilter";
3789 
3790  m_dlgSettingsColorFilter->load (*m_cmdMediator);
3791  m_dlgSettingsColorFilter->show ();
3792 }
3793 
3794 void MainWindow::slotSettingsCoords ()
3795 {
3796  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCoords";
3797 
3798  m_dlgSettingsCoords->load (*m_cmdMediator);
3799  m_dlgSettingsCoords->show ();
3800 }
3801 
3802 void MainWindow::slotSettingsCurveAddRemove ()
3803 {
3804  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveAddRemove";
3805 
3806  m_dlgSettingsCurveAddRemove->load (*m_cmdMediator);
3807  m_dlgSettingsCurveAddRemove->show ();
3808 }
3809 
3810 void MainWindow::slotSettingsCurveProperties ()
3811 {
3812  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsCurveProperties";
3813 
3814  m_dlgSettingsCurveProperties->load (*m_cmdMediator);
3815  m_dlgSettingsCurveProperties->setCurveName (selectedGraphCurve ());
3816  m_dlgSettingsCurveProperties->show ();
3817 }
3818 
3819 void MainWindow::slotSettingsDigitizeCurve ()
3820 {
3821  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsDigitizeCurve";
3822 
3823  m_dlgSettingsDigitizeCurve->load (*m_cmdMediator);
3824  m_dlgSettingsDigitizeCurve->show ();
3825 }
3826 
3827 void MainWindow::slotSettingsExportFormat ()
3828 {
3829  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsExportFormat";
3830 
3831  if (transformIsDefined()) {
3832  m_dlgSettingsExportFormat->load (*m_cmdMediator);
3833  m_dlgSettingsExportFormat->show ();
3834  } else {
3835  DlgRequiresTransform dlg ("Export settings");
3836  dlg.exec();
3837  }
3838 }
3839 
3840 void MainWindow::slotSettingsGeneral ()
3841 {
3842  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGeneral";
3843 
3844  m_dlgSettingsGeneral->load (*m_cmdMediator);
3845  m_dlgSettingsGeneral->show ();
3846 }
3847 
3848 void MainWindow::slotSettingsGridDisplay()
3849 {
3850  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridDisplay";
3851 
3852  m_dlgSettingsGridDisplay->load (*m_cmdMediator);
3853  m_dlgSettingsGridDisplay->show ();
3854 }
3855 
3856 void MainWindow::slotSettingsGridRemoval ()
3857 {
3858  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsGridRemoval";
3859 
3860  m_dlgSettingsGridRemoval->load (*m_cmdMediator);
3861  m_dlgSettingsGridRemoval->show ();
3862 }
3863 
3864 void MainWindow::slotSettingsPointMatch ()
3865 {
3866  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsPointMatch";
3867 
3868  m_dlgSettingsPointMatch->load (*m_cmdMediator);
3869  m_dlgSettingsPointMatch->show ();
3870 }
3871 
3872 void MainWindow::slotSettingsSegments ()
3873 {
3874  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsSegments";
3875 
3876  m_dlgSettingsSegments->load (*m_cmdMediator);
3877  m_dlgSettingsSegments->show ();
3878 }
3879 
3880 void MainWindow::slotTableStatusChange ()
3881 {
3882  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTableStatusChange";
3883 
3884  // This slot is called when either window in FittingWindow or GeometryWindow loses/gains focus. This is
3885  // so the Copy menu item can be updated
3886  updateControls ();
3887 }
3888 
3889 void MainWindow::slotSettingsMainWindow ()
3890 {
3891  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotSettingsMainWindow";
3892 
3893  m_dlgSettingsMainWindow->loadMainWindowModel (*m_cmdMediator,
3894  m_modelMainWindow);
3895  m_dlgSettingsMainWindow->show ();
3896 }
3897 
3898 void MainWindow::slotTimeoutRegressionErrorReport ()
3899 {
3900  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionErrorReport"
3901  << " cmdStackIndex=" << m_cmdMediator->index()
3902  << " cmdStackCount=" << m_cmdMediator->count();
3903 
3904  if (m_cmdStackShadow->canRedo()) {
3905 
3906  // Always reset current directory before the command. This guarantees the upcoming redo step will work
3907  QDir::setCurrent (m_startupDirectory);
3908 
3909  m_cmdStackShadow->slotRedo();
3910 
3911  // Always reset current directory after the command. This guarantees the final export to file will work
3912  QDir::setCurrent (m_startupDirectory);
3913 
3914  } else {
3915 
3916 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
3917  exportAllCoordinateSystemsAfterRegressionTests ();
3918 #endif
3919 
3920  // Regression test has finished so exit. We unset the dirty flag so there is no prompt
3921  m_cmdMediator->setClean();
3922  close();
3923 
3924  }
3925 }
3926 
3927 void MainWindow::slotTimeoutRegressionFileCmdScript ()
3928 {
3929  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotTimeoutRegressionFileCmdScript";
3930 
3931  if (m_fileCmdScript->canRedo()) {
3932 
3933  // Always reset current directory before the command. This guarantees the upcoming redo step will work
3934  QDir::setCurrent (m_startupDirectory);
3935 
3936  m_fileCmdScript->redo(*this);
3937 
3938  // Always reset current directory after the command. This guarantees the final export to file will work
3939  QDir::setCurrent (m_startupDirectory);
3940 
3941  } else {
3942 
3943  // Script file might already have closed the Document so export only if last was not closed
3944  if (m_cmdMediator != 0) {
3945 
3946 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
3947  exportAllCoordinateSystemsAfterRegressionTests ();
3948 #endif
3949 
3950  // We unset the dirty flag so there is no "Save changes?" prompt
3951  m_cmdMediator->setClean();
3952 
3953  }
3954 
3955  // Regression test has finished so exit
3956  close();
3957 
3958  }
3959 }
3960 
3961 void MainWindow::slotUndoTextChanged (const QString &text)
3962 {
3963  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotUndoTextChanged";
3964 
3965  QString completeText ("Undo");
3966  if (!text.isEmpty ()) {
3967  completeText += QString (" \"%1\"").arg (text);
3968  }
3969  m_actionEditUndo->setText (completeText);
3970 }
3971 
3972 void MainWindow::slotViewGridLines ()
3973 {
3974  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::slotViewGridLines";
3975 
3976  updateGridLines ();
3977 }
3978 
3979 void MainWindow::slotViewGroupBackground(QAction *action)
3980 {
3981  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupBackground";
3982 
3983  // Set the combobox
3984  BackgroundImage backgroundImage;
3985  int indexBackground;
3986  if (action == m_actionViewBackgroundNone) {
3987  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_NONE));
3988  backgroundImage = BACKGROUND_IMAGE_NONE;
3989  } else if (action == m_actionViewBackgroundOriginal) {
3990  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
3991  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
3992  } else if (action == m_actionViewBackgroundFiltered) {
3993  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_FILTERED));
3994  backgroundImage = BACKGROUND_IMAGE_FILTERED;
3995  } else {
3996  ENGAUGE_ASSERT (false);
3997 
3998  // Defaults if assert is disabled so execution continues
3999  indexBackground = m_cmbBackground->findData (QVariant (BACKGROUND_IMAGE_ORIGINAL));
4000  backgroundImage = BACKGROUND_IMAGE_ORIGINAL;
4001  }
4002 
4003  m_cmbBackground->setCurrentIndex (indexBackground);
4004  m_backgroundStateContext->setBackgroundImage (backgroundImage);
4005 }
4006 
4007 void MainWindow::slotViewGroupCurves(QAction * /* action */)
4008 {
4009  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupCurves";
4010 
4011  updateViewedCurves ();
4012 }
4013 
4014 void MainWindow::slotViewGroupStatus(QAction *action)
4015 {
4016  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewGroupStatus";
4017 
4018  ENGAUGE_CHECK_PTR (m_statusBar); // At startup, make sure status bar is already set up when View menu gets initialized
4019 
4020  if (action == m_actionStatusNever) {
4021  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_NEVER);
4022  } else if (action == m_actionStatusTemporary) {
4023  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_TEMPORARY);
4024  } else {
4025  m_statusBar->setStatusBarMode(STATUS_BAR_MODE_ALWAYS);
4026  }
4027 }
4028 
4029 void MainWindow::slotViewToolBarBackground ()
4030 {
4031  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarBackground";
4032 
4033  if (m_actionViewBackground->isChecked ()) {
4034  m_toolBackground->show();
4035  } else {
4036  m_toolBackground->hide();
4037  }
4038 }
4039 
4040 void MainWindow::slotViewToolBarChecklistGuide ()
4041 {
4042  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarChecklistGuide";
4043 
4044  if (m_actionViewChecklistGuide->isChecked ()) {
4045  m_dockChecklistGuide->show();
4046  } else {
4047  m_dockChecklistGuide->hide();
4048  }
4049 }
4050 
4051 void MainWindow::slotViewToolBarCoordSystem ()
4052 {
4053  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarCoordSystem";
4054 
4055  if (m_actionViewCoordSystem->isChecked ()) {
4056  m_toolCoordSystem->show();
4057  } else {
4058  m_toolCoordSystem->hide();
4059  }
4060 }
4061 
4062 void MainWindow::slotViewToolBarDigitize ()
4063 {
4064  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarDigitize";
4065 
4066  if (m_actionViewDigitize->isChecked ()) {
4067  m_toolDigitize->show();
4068  } else {
4069  m_toolDigitize->hide();
4070  }
4071 }
4072 
4073 void MainWindow::slotViewToolBarFittingWindow()
4074 {
4075  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarFittingWindow";
4076 
4077  if (m_actionViewFittingWindow->isChecked()) {
4078  m_dockFittingWindow->show ();
4079  if (m_fittingCurve != 0) {
4080  m_fittingCurve->setVisible (true);
4081  }
4082  } else {
4083  m_dockFittingWindow->hide ();
4084  if (m_fittingCurve != 0) {
4085  m_fittingCurve->setVisible (false);
4086  }
4087  }
4088 }
4089 
4090 void MainWindow::slotViewToolBarGeometryWindow ()
4091 {
4092  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarGeometryWindow";
4093 
4094  if (m_actionViewGeometryWindow->isChecked ()) {
4095  m_dockGeometryWindow->show();
4096  } else {
4097  m_dockGeometryWindow->hide();
4098  }
4099 }
4100 
4101 void MainWindow::slotViewToolBarSettingsViews ()
4102 {
4103  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolBarSettingsViews";
4104 
4105  if (m_actionViewSettingsViews->isChecked ()) {
4106  m_toolSettingsViews->show();
4107  } else {
4108  m_toolSettingsViews->hide();
4109  }
4110 }
4111 
4112 void MainWindow::slotViewToolTips ()
4113 {
4114  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewToolTips";
4115 
4116  loadToolTips();
4117 }
4118 
4119 void MainWindow::slotViewZoom (int zoom)
4120 {
4121  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoom";
4122 
4123  // Update zoom controls and apply the zoom factor
4124  ZoomFactor zoomFactor = (ZoomFactor) zoom;
4125  m_zoomMapToAction [zoomFactor]->setChecked (true);
4126  slotViewZoomFactor ((ZoomFactor) zoom);
4127 }
4128 
4129 void MainWindow::slotViewZoomFactor (ZoomFactor zoomFactor)
4130 {
4131  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomFactor";
4132 
4133  if (zoomFactor == ZOOM_FILL) {
4134  m_backgroundStateContext->fitInView (*m_view);
4135  } else {
4136 
4137  ZoomTransition zoomTransition;
4138  double factor = zoomTransition.mapToFactor (zoomFactor);
4139 
4140  QTransform transform;
4141  transform.scale (factor, factor);
4142  m_view->setTransform (transform);
4143  }
4144 
4145  emit signalZoom(zoomFactor);
4146 }
4147 
4148 void MainWindow::slotViewZoomFactorInt (int zoom)
4149 {
4150  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomFactorInt";
4151 
4152  slotViewZoomFactor ((ZoomFactor) zoom);
4153 }
4154 
4155 void MainWindow::slotViewZoomIn ()
4156 {
4157  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomIn";
4158 
4159  ZoomTransition zoomTransition;
4160  ZoomFactor zoomFactorNew = zoomTransition.zoomIn (currentZoomFactor (),
4161  m_view->transform ().m11 (),
4162  m_view->transform ().m22 (),
4163  m_actionZoomFill->isChecked ());
4164  setNonFillZoomFactor (zoomFactorNew);
4165 }
4166 
4167 
4168 void MainWindow::slotViewZoomInFromWheelEvent ()
4169 {
4170  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomInFromWheelEvent";
4171 
4172  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
4173  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
4174 
4175  // Anchor the zoom to the cursor position
4176  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
4177 
4178  // Forward this event
4179  slotViewZoomIn ();
4180 
4181  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
4182  }
4183 }
4184 
4185 void MainWindow::slotViewZoomOut ()
4186 {
4187  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOut";
4188 
4189  // Try to zoom out
4190  ZoomTransition zoomTransition;
4191  ZoomFactor zoomFactorNew = zoomTransition.zoomOut (currentZoomFactor (),
4192  m_view->transform ().m11 (),
4193  m_view->transform ().m22 (),
4194  m_actionZoomFill->isChecked ());
4195  setNonFillZoomFactor (zoomFactorNew);
4196 }
4197 
4198 void MainWindow::slotViewZoomOutFromWheelEvent ()
4199 {
4200  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::slotViewZoomOutFromWheelEvent";
4201 
4202  if ((m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) ||
4203  (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL_PLUSMINUS)) {
4204 
4205  // Anchor the zoom to the cursor position
4206  m_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
4207 
4208  // Forward this event
4209  slotViewZoomOut ();
4210 
4211  m_view->setTransformationAnchor(QGraphicsView::NoAnchor);
4212  }
4213 }
4214 
4215 void MainWindow::startRegressionTestErrorReport(const QString &regressionInputFile)
4216 {
4217  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestErrorReport";
4218 
4219  // In order for point-deleting commands to work (CmdCut, CmdDelete) in the regression tests, we need to
4220  // reset the Point identifier index here:
4221  // 1) after loading of the file which has increased the index value to greater than 0
4222  // 2) before running any commands since those commands implicitly assume the index is zero
4224 
4225  // Save output/export file name
4226  m_regressionFile = exportFilenameFromInputFilename (regressionInputFile);
4227 
4228  m_timerRegressionErrorReport = new QTimer();
4229  m_timerRegressionErrorReport->setSingleShot(false);
4230  connect (m_timerRegressionErrorReport, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionErrorReport()));
4231 
4232  m_timerRegressionErrorReport->start(REGRESSION_INTERVAL);
4233 }
4234 
4235 void MainWindow::startRegressionTestFileCmdScript()
4236 {
4237  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::startRegressionTestFileCmdScript";
4238 
4239  m_timerRegressionFileCmdScript = new QTimer();
4240  m_timerRegressionFileCmdScript->setSingleShot(false);
4241  connect (m_timerRegressionFileCmdScript, SIGNAL (timeout()), this, SLOT (slotTimeoutRegressionFileCmdScript()));
4242 
4243  m_timerRegressionFileCmdScript->start(REGRESSION_INTERVAL);
4244 }
4245 
4247 {
4248  return m_transformation;
4249 }
4250 
4252 {
4253  return m_transformation.transformIsDefined();
4254 }
4255 
4257 {
4258  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommand";
4259 
4260  ENGAUGE_CHECK_PTR (m_cmdMediator);
4261 
4262  // Update transformation stuff, including the graph coordinates of every point in the Document, so coordinates in
4263  // status bar are up to date. Point coordinates in Document are also updated
4264  updateAfterCommandStatusBarCoords ();
4265 
4266  updateHighlightOpacity ();
4267 
4268  // Update graphics. Effectively, these steps do very little (just needed for highlight opacity)
4269  m_digitizeStateContext->updateAfterPointAddition (); // May or may not be needed due to point addition
4270 
4271  updateControls ();
4272  updateChecklistGuide ();
4273  updateFittingWindow ();
4274  updateGeometryWindow();
4275 
4276  // Final action at the end of a redo/undo is to checkpoint the Document and GraphicsScene to log files
4277  // so proper state can be verified
4278  writeCheckpointToLogFile ();
4279 
4280  // Since focus may have drifted over to Geometry Window or some other control we se focus on the GraphicsView
4281  // so the cursor is appropriate for the current state (otherwise it often ends up as default arrow)
4282  m_view->setFocus ();
4283 }
4284 
4285 void MainWindow::updateAfterCommandStatusBarCoords ()
4286 {
4287  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterCommandStatusBarCoords";
4288 
4289  // For some reason, mapFromGlobal(QCursor::pos) differs from event->pos by a little bit. We must compensate for
4290  // this so cursor coordinates in status bar match the DlgEditPointAxis inputs initially. After the mouse moves
4291  // the problem disappears since event->pos is available and QCursor::pos is no longer needed
4292  const QPoint HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT (1, 1);
4293 
4294  Transformation m_transformationBefore (m_transformation);
4295 
4296  updateTransformationAndItsDependencies();
4297 
4298  // Trigger state transitions for transformation if appropriate
4299  if (!m_transformationBefore.transformIsDefined() && m_transformation.transformIsDefined()) {
4300 
4301  // Transition from undefined to defined
4302  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_DEFINED,
4303  *m_cmdMediator,
4304  m_transformation,
4305  selectedGraphCurve());
4306 
4307  } else if (m_transformationBefore.transformIsDefined() && !m_transformation.transformIsDefined()) {
4308 
4309  // Transition from defined to undefined
4310  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
4311  *m_cmdMediator,
4312  m_transformation,
4313  selectedGraphCurve());
4314 
4315  } else if (m_transformation.transformIsDefined() && (m_transformationBefore != m_transformation)) {
4316 
4317  // There was not a define/undefined or undefined/defined transition, but the transformation changed so we
4318  // need to update the Checker
4319  m_transformationStateContext->updateAxesChecker(*m_cmdMediator,
4320  m_transformation);
4321 
4322  }
4323 
4324  QPoint posLocal = m_view->mapFromGlobal (QCursor::pos ()) - HACK_SO_GRAPH_COORDINATE_MATCHES_INPUT;
4325  QPointF posScreen = m_view->mapToScene (posLocal);
4326 
4327  slotMouseMove (posScreen); // Update the status bar coordinates to reflect the newly updated transformation
4328 }
4329 
4331 {
4332  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateAfterMouseRelease";
4333 
4334  updateControls ();
4335 }
4336 
4337 void MainWindow::updateChecklistGuide ()
4338 {
4339  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateChecklistGuide";
4340 
4341  m_isDocumentExported = true; // Set for next line and for all checklist guide updates after this
4342  m_dockChecklistGuide->update (*m_cmdMediator,
4343  m_isDocumentExported);
4344 }
4345 
4346 void MainWindow::updateControls ()
4347 {
4348  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateControls"
4349  << " selectedItems=" << m_scene->selectedItems().count();
4350 
4351  m_cmbBackground->setEnabled (!m_currentFile.isEmpty ());
4352 
4353  m_actionImportImageReplace->setEnabled (m_cmdMediator != 0);
4354 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
4355  m_menuFileOpenRecent->setEnabled ((m_actionRecentFiles.count () > 0) &&
4356  (m_actionRecentFiles.at(0)->isVisible ())); // Need at least one visible recent file entry
4357 #endif
4358  m_actionClose->setEnabled (!m_currentFile.isEmpty ());
4359  m_actionSave->setEnabled (!m_currentFile.isEmpty ());
4360  m_actionSaveAs->setEnabled (!m_currentFile.isEmpty ());
4361  m_actionExport->setEnabled (!m_currentFile.isEmpty ());
4362  m_actionPrint->setEnabled (!m_currentFile.isEmpty ());
4363 
4364  if (m_cmdMediator == 0) {
4365  m_actionEditUndo->setEnabled (false);
4366  m_actionEditRedo->setEnabled (false);
4367  } else {
4368  m_actionEditUndo->setEnabled (m_cmdMediator->canUndo ());
4369  m_actionEditRedo->setEnabled (m_cmdMediator->canRedo () || m_cmdStackShadow->canRedo ());
4370  }
4371  bool tableFittingIsActive, tableFittingIsCopyable;
4372  bool tableGeometryIsActive, tableGeometryIsCopyable;
4373  m_dockFittingWindow->getTableStatus (tableFittingIsActive, tableFittingIsCopyable); // Fitting window status
4374  m_dockGeometryWindow->getTableStatus (tableGeometryIsActive, tableGeometryIsCopyable); // Geometry window status
4375  m_actionEditCut->setEnabled (!tableFittingIsActive &&
4376  !tableGeometryIsActive &&
4377  m_scene->selectedItems().count () > 0);
4378  m_actionEditCopy->setEnabled ((!tableFittingIsActive && !tableGeometryIsActive && m_scene->selectedItems().count () > 0) ||
4379  (tableFittingIsActive && tableFittingIsCopyable) ||
4380  (tableGeometryIsActive && tableGeometryIsCopyable));
4381  m_actionEditPaste->setEnabled (m_digitizeStateContext->canPaste (m_transformation,
4382  m_view->size ()));
4383  m_actionEditDelete->setEnabled (!tableFittingIsActive &&
4384  !tableGeometryIsActive &&
4385  m_scene->selectedItems().count () > 0);
4386  // m_actionEditPasteAsNew and m_actionEditPasteAsNewAdvanced are updated when m_menuEdit is about to be shown
4387 
4388  m_actionDigitizeAxis->setEnabled (modeGraph ());
4389  m_actionDigitizeScale->setEnabled (modeMap ());
4390  m_actionDigitizeCurve ->setEnabled (!m_currentFile.isEmpty ());
4391  m_actionDigitizePointMatch->setEnabled (!m_currentFile.isEmpty ());
4392  m_actionDigitizeColorPicker->setEnabled (!m_currentFile.isEmpty ());
4393  m_actionDigitizeSegment->setEnabled (!m_currentFile.isEmpty ());
4394  m_actionDigitizeSelect->setEnabled (!m_currentFile.isEmpty ());
4395  if (m_transformation.transformIsDefined()) {
4396  m_actionViewGridLines->setEnabled (true);
4397  } else {
4398  m_actionViewGridLines->setEnabled (false);
4399  m_actionViewGridLines->setChecked (false);
4400  }
4401  m_actionViewBackground->setEnabled (!m_currentFile.isEmpty());
4402  m_actionViewChecklistGuide->setEnabled (!m_dockChecklistGuide->browserIsEmpty());
4403  m_actionViewDigitize->setEnabled (!m_currentFile.isEmpty ());
4404  m_actionViewSettingsViews->setEnabled (!m_currentFile.isEmpty ());
4405 
4406  m_actionSettingsCoords->setEnabled (!m_currentFile.isEmpty ());
4407  m_actionSettingsCurveAddRemove->setEnabled (!m_currentFile.isEmpty ());
4408  m_actionSettingsCurveProperties->setEnabled (!m_currentFile.isEmpty ());
4409  m_actionSettingsDigitizeCurve->setEnabled (!m_currentFile.isEmpty ());
4410  m_actionSettingsExport->setEnabled (!m_currentFile.isEmpty ());
4411  m_actionSettingsColorFilter->setEnabled (!m_currentFile.isEmpty ());
4412  m_actionSettingsAxesChecker->setEnabled (!m_currentFile.isEmpty ());
4413  m_actionSettingsGridDisplay->setEnabled (!m_currentFile.isEmpty () && m_transformation.transformIsDefined());
4414  m_actionSettingsGridRemoval->setEnabled (!m_currentFile.isEmpty ());
4415  m_actionSettingsPointMatch->setEnabled (!m_currentFile.isEmpty ());
4416  m_actionSettingsSegments->setEnabled (!m_currentFile.isEmpty ());
4417  m_actionSettingsGeneral->setEnabled (!m_currentFile.isEmpty ());
4418 
4419  m_groupBackground->setEnabled (!m_currentFile.isEmpty ());
4420  m_groupCurves->setEnabled (!m_currentFile.isEmpty ());
4421  m_groupZoom->setEnabled (!m_currentFile.isEmpty ());
4422 
4423  m_actionZoomIn->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
4424  m_actionZoomOut->setEnabled (!m_currentFile.isEmpty ()); // Disable at startup so shortcut has no effect
4425 }
4426 
4427 void MainWindow::updateCoordSystem(CoordSystemIndex coordSystemIndex)
4428 {
4429  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateCoordSystem";
4430 
4431  // Set current curve in the Document and in the MainWindow combobox together so they are in sync. Setting
4432  // the selected curve prevents a crash in updateTransformationAndItsDependencies
4433  m_cmdMediator->document().setCoordSystemIndex (coordSystemIndex);
4434  loadCurveListFromCmdMediator ();
4435 
4436  updateTransformationAndItsDependencies(); // Transformation state may have changed
4437  updateSettingsAxesChecker(m_cmdMediator->document().modelAxesChecker()); // Axes checker dependes on transformation state
4438 
4439  // Nice trick for showing that a new coordinate system is in effect is to show the axes checker
4440  m_transformationStateContext->updateAxesChecker (*m_cmdMediator,
4441  m_transformation);
4442 
4444 }
4445 
4446 void MainWindow::updateDigitizeStateIfSoftwareTriggered (DigitizeState digitizeState)
4447 {
4448  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
4449 
4450  switch (digitizeState) {
4451  case DIGITIZE_STATE_AXIS:
4452  m_actionDigitizeAxis->setChecked(true);
4453  slotDigitizeAxis(); // Call the slot that the setChecked call fails to trigger
4454  break;
4455 
4456  case DIGITIZE_STATE_COLOR_PICKER:
4457  m_actionDigitizeColorPicker->setChecked(true);
4458  slotDigitizeColorPicker(); // Call the slot that the setChecked call fails to trigger
4459  break;
4460 
4461  case DIGITIZE_STATE_CURVE:
4462  m_actionDigitizeCurve->setChecked(true);
4463  slotDigitizeCurve(); // Call the slot that the setChecked call fails to trigger
4464  break;
4465 
4466  case DIGITIZE_STATE_EMPTY:
4467  break;
4468 
4469  case DIGITIZE_STATE_POINT_MATCH:
4470  m_actionDigitizePointMatch->setChecked(true);
4471  slotDigitizePointMatch(); // Call the slot that the setChecked call fails to trigger
4472  break;
4473 
4474  case DIGITIZE_STATE_SCALE:
4475  m_actionDigitizeScale->setChecked(true);
4476  slotDigitizeScale(); // Call the slot that the setChecked call fails to trigger
4477  break;
4478 
4479  case DIGITIZE_STATE_SEGMENT:
4480  m_actionDigitizeSegment->setChecked(true);
4481  slotDigitizeSegment(); // Call the slot that the setChecked call fails to trigger
4482  break;
4483 
4484  case DIGITIZE_STATE_SELECT:
4485  m_actionDigitizeSelect->setChecked(true);
4486  slotDigitizeSelect(); // Call the slot that the setChecked call fails to trigger
4487  break;
4488 
4489  default:
4490  LOG4CPP_ERROR_S ((*mainCat)) << "MainWindow::updateDigitizeStateIfSoftwareTriggered";
4491  break;
4492  }
4493 }
4494 
4495 void MainWindow::updateFittingWindow ()
4496 {
4497  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateFittingWindow";
4498 
4499  if (m_cmdMediator != 0 &&
4500  m_cmbCurve != 0) {
4501 
4502  // Update fitting window
4503  m_dockFittingWindow->update (*m_cmdMediator,
4504  m_modelMainWindow,
4505  m_cmbCurve->currentText (),
4506  m_transformation);
4507  }
4508 }
4509 
4510 void MainWindow::updateGeometryWindow ()
4511 {
4512  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGeometryWindow";
4513 
4514  if (m_cmdMediator != 0 &&
4515  m_cmbCurve != 0) {
4516 
4517  // Update geometry window
4518  m_dockGeometryWindow->update (*m_cmdMediator,
4519  m_modelMainWindow,
4520  m_cmbCurve->currentText (),
4521  m_transformation);
4522  }
4523 }
4524 
4526 {
4527  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGraphicsLinesToMatchGraphicsPoints";
4528 
4530  m_transformation);
4531 }
4532 
4533 void MainWindow::updateGridLines ()
4534 {
4535  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateGridLines";
4536 
4537  // Remove old grid lines
4538  m_gridLines.clear ();
4539 
4540  // Create new grid lines
4541  GridLineFactory factory (*m_scene,
4542  m_cmdMediator->document().modelCoords());
4543  factory.createGridLinesForEvenlySpacedGrid (m_cmdMediator->document().modelGridDisplay(),
4544  m_cmdMediator->document(),
4545  m_modelMainWindow,
4546  m_transformation,
4547  m_gridLines);
4548 
4549  m_gridLines.setVisible (m_actionViewGridLines->isChecked());
4550 }
4551 
4552 void MainWindow::updateHighlightOpacity ()
4553 {
4554  if (m_cmdMediator != 0) {
4555 
4556  // Update the QGraphicsScene with the populated Curves. This requires the points in the Document to be already updated
4557  // by updateAfterCommandStatusBarCoords
4558  m_scene->updateAfterCommand (*m_cmdMediator,
4559  m_modelMainWindow.highlightOpacity(),
4560  m_dockGeometryWindow);
4561  }
4562 }
4563 
4564 void MainWindow::updateRecentFileList()
4565 {
4566  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateRecentFileList";
4567 
4568 #if !defined(OSX_DEBUG) && !defined(OSX_RELEASE)
4569  QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
4570  QStringList recentFilePaths = settings.value(SETTINGS_RECENT_FILE_LIST).toStringList();
4571 
4572  // Determine the desired size of the path list
4573  unsigned int count = recentFilePaths.size();
4574  if (count > MAX_RECENT_FILE_LIST_SIZE) {
4575  count = MAX_RECENT_FILE_LIST_SIZE;
4576  }
4577 
4578  // Add visible entries
4579  unsigned int i;
4580  for (i = 0; i < count; i++) {
4581  QString strippedName = QFileInfo (recentFilePaths.at(i)).fileName();
4582  m_actionRecentFiles.at (i)->setText (strippedName);
4583  m_actionRecentFiles.at (i)->setData (recentFilePaths.at (i));
4584  m_actionRecentFiles.at (i)->setVisible (true);
4585  }
4586 
4587  // Hide any extra entries
4588  for (i = count; i < MAX_RECENT_FILE_LIST_SIZE; i++) {
4589  m_actionRecentFiles.at (i)->setVisible (false);
4590  }
4591 #endif
4592 }
4593 
4595 {
4596  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsAxesChecker";
4597 
4598  m_cmdMediator->document().setModelAxesChecker(modelAxesChecker);
4599  if (m_transformation.transformIsDefined()) {
4600  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_DEFINED,
4601  *m_cmdMediator,
4602  m_transformation,
4603  m_cmbCurve->currentText());
4604  } else {
4605  m_transformationStateContext->triggerStateTransition(TRANSFORMATION_STATE_UNDEFINED,
4606  *m_cmdMediator,
4607  m_transformation,
4608  m_cmbCurve->currentText());
4609  }
4610 }
4611 
4613 {
4614  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsColorFilter";
4615 
4616  m_cmdMediator->document().setModelColorFilter(modelColorFilter);
4617  m_backgroundStateContext->updateColorFilter (m_transformation,
4618  m_cmdMediator->document().modelGridRemoval(),
4619  modelColorFilter,
4620  m_cmbCurve->currentText());
4621  m_digitizeStateContext->handleCurveChange (m_cmdMediator);
4623 }
4624 
4626 {
4627  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCoords";
4628 
4629  m_cmdMediator->document().setModelCoords(modelCoords);
4630 }
4631 
4633 {
4634  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveAddRemove";
4635 
4636  m_cmdMediator->document().setCurvesGraphs (curvesGraphs);
4637  loadCurveListFromCmdMediator();
4639 }
4640 
4642 {
4643  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsCurveStyles";
4644 
4645  m_scene->updateCurveStyles(modelCurveStyles);
4646  m_cmdMediator->document().setModelCurveStyles(modelCurveStyles);
4648 }
4649 
4651 {
4652  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsDigitizeCurve";
4653 
4654  m_cmdMediator->document().setModelDigitizeCurve(modelDigitizeCurve);
4655  m_digitizeStateContext->updateModelDigitizeCurve (m_cmdMediator,
4656  modelDigitizeCurve);
4657 }
4658 
4660 {
4661  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsExportFormat";
4662 
4663  m_cmdMediator->document().setModelExport (modelExport);
4664 }
4665 
4667 {
4668  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGeneral";
4669 
4670  m_cmdMediator->document().setModelGeneral(modelGeneral);
4671 }
4672 
4674 {
4675  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridDisplay";
4676 
4677  m_cmdMediator->document().setModelGridDisplay(modelGridDisplay);
4678  updateGridLines ();
4679 }
4680 
4682 {
4683  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsGridRemoval";
4684 
4685  m_cmdMediator->document().setModelGridRemoval(modelGridRemoval);
4686 }
4687 
4688 void MainWindow::updateSettingsMainWindow()
4689 {
4690  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
4691 
4692  if (m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_ONLY ||
4693  m_modelMainWindow.zoomControl() == ZOOM_CONTROL_MENU_WHEEL) {
4694 
4695  m_actionZoomIn->setShortcut (tr (""));
4696  m_actionZoomOut->setShortcut (tr (""));
4697 
4698  } else {
4699 
4700  m_actionZoomIn->setShortcut (tr ("+"));
4701  m_actionZoomOut->setShortcut (tr ("-"));
4702 
4703  }
4704 
4705  if ((m_scene != 0) &&
4706  (m_cmdMediator != 0)) {
4707  m_scene->updateCurveStyles(m_cmdMediator->document().modelCurveStyles());
4708  }
4709 
4710  updateHighlightOpacity();
4711  updateWindowTitle();
4712  updateFittingWindow(); // Forward the drag and drop choice
4713  updateGeometryWindow(); // Forward the drag and drop choice
4714 }
4715 
4717 {
4718  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsMainWindow";
4719 
4720  m_modelMainWindow = modelMainWindow;
4722 }
4723 
4725 {
4726  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsPointMatch";
4727 
4728  m_cmdMediator->document().setModelPointMatch(modelPointMatch);
4729 }
4730 
4732 {
4733  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateSettingsSegments";
4734 
4735  m_cmdMediator->document().setModelSegments(modelSegments);
4736  m_digitizeStateContext->updateModelSegments(modelSegments);
4737 }
4738 
4739 void MainWindow::updateSmallDialogs ()
4740 {
4741  m_dlgSettingsAxesChecker->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4742  m_dlgSettingsColorFilter->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4743  m_dlgSettingsCoords->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4744  m_dlgSettingsCurveAddRemove->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4745  m_dlgSettingsCurveProperties->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4746  m_dlgSettingsDigitizeCurve->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4747  m_dlgSettingsExportFormat->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4748  m_dlgSettingsGeneral->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4749  m_dlgSettingsGridDisplay->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4750  m_dlgSettingsGridRemoval->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4751  m_dlgSettingsMainWindow->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4752  m_dlgSettingsPointMatch->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4753  m_dlgSettingsSegments->setSmallDialogs (m_modelMainWindow.smallDialogs ());
4754 }
4755 
4756 void MainWindow::updateTransformationAndItsDependencies()
4757 {
4758  m_transformation.update (!m_currentFile.isEmpty (),
4759  *m_cmdMediator,
4760  m_modelMainWindow);
4761 
4762  // Grid removal is affected by new transformation above
4763  m_backgroundStateContext->setCurveSelected (m_transformation,
4764  m_cmdMediator->document().modelGridRemoval(),
4765  m_cmdMediator->document().modelColorFilter(),
4766  m_cmbCurve->currentText ());
4767 
4768  // Grid display is also affected by new transformation above, if there was a transition into defined state
4769  // in which case that transition triggered the initialization of the grid display parameters
4770  updateGridLines();
4771 }
4772 
4773 void MainWindow::updateViewedCurves ()
4774 {
4775  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewedCurves";
4776 
4777  if (m_actionViewCurvesAll->isChecked ()) {
4778 
4779  m_scene->showCurves (true, true);
4780 
4781  } else if (m_actionViewCurvesSelected->isChecked ()) {
4782 
4783  m_scene->showCurves (true, false, selectedGraphCurve ());
4784 
4785  } else if (m_actionViewCurvesNone->isChecked ()) {
4786 
4787  m_scene->showCurves (false);
4788 
4789  } else {
4790  ENGAUGE_ASSERT (false);
4791  }
4792 }
4793 
4795 {
4796  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateViewsOfSettings";
4797 
4798  QString activeCurve = m_digitizeStateContext->activeCurve ();
4799 
4800  updateViewsOfSettings (activeCurve);
4801 }
4802 
4803 void MainWindow::updateViewsOfSettings (const QString &activeCurve)
4804 {
4805  if (activeCurve.isEmpty ()) {
4806 
4807  m_viewPointStyle->unsetPointStyle ();
4808  m_viewSegmentFilter->unsetColorFilterSettings ();
4809 
4810 
4811  } else {
4812 
4813  PointStyle pointStyle = m_cmdMediator->document().modelCurveStyles().curveStyle(activeCurve).pointStyle();
4814  m_viewPointStyle->setPointStyle (pointStyle);
4815 
4816  ColorFilterSettings colorFilterSettings = m_cmdMediator->document().modelColorFilter().colorFilterSettings(activeCurve);
4817  m_viewSegmentFilter->setColorFilterSettings (colorFilterSettings,
4818  m_cmdMediator->pixmap ());
4819 
4820  }
4821 }
4822 
4823 void MainWindow::updateWindowTitle ()
4824 {
4825  LOG4CPP_INFO_S ((*mainCat)) << "MainWindow::updateWindowTitle";
4826 
4827  const QString PLACEHOLDER ("[*]");
4828 
4829  QString title = QString (tr ("Engauge Digitizer %1")
4830  .arg (VERSION_NUMBER));
4831 
4832  QString fileNameMaybeStripped;
4833  if (!m_currentFileWithPathAndFileExtension.isEmpty()) {
4834 
4835  QFileInfo fileInfo (m_currentFileWithPathAndFileExtension);
4836 
4837  switch (m_modelMainWindow.mainTitleBarFormat())
4838  {
4839  case MAIN_TITLE_BAR_FORMAT_NO_PATH:
4840  fileNameMaybeStripped = fileInfo.baseName(); // Remove file extension and path for "clean look"
4841  break;
4842 
4843  case MAIN_TITLE_BAR_FORMAT_PATH:
4844  fileNameMaybeStripped = m_currentFileWithPathAndFileExtension;
4845  break;
4846  }
4847 
4848  title += QString (": %1")
4849  .arg (fileNameMaybeStripped);
4850  }
4851 
4852  // To prevent "QWidget::setWindowModified: The window title does not contain a [*] placeholder" warnings,
4853  // we always append a placeholder
4854  title += PLACEHOLDER;
4855 
4856  setWindowTitle (title);
4857 }
4858 
4860 {
4861  ENGAUGE_CHECK_PTR (m_view);
4862  return *m_view;
4863 }
4864 
4866 {
4867  ENGAUGE_CHECK_PTR (m_view);
4868  return *m_view;
4869 }
4870 
4871 void MainWindow::writeCheckpointToLogFile ()
4872 {
4873  // Document
4874  QString checkpointDoc;
4875  QTextStream strDoc (&checkpointDoc);
4876  m_cmdMediator->document().printStream(INDENTATION_PAST_TIMESTAMP,
4877  strDoc);
4878 
4879  // Scene
4880  QString checkpointScene;
4881  QTextStream strScene (&checkpointScene);
4882  m_scene->printStream (INDENTATION_PAST_TIMESTAMP,
4883  strScene);
4884 
4885  // Skip slow string manipulation if BEFORE call to LOG4CPP_DEBUG_S
4886  if (mainCat->getPriority() == log4cpp::Priority::DEBUG) {
4887 
4888  LOG4CPP_DEBUG_S ((*mainCat)) << "MainWindow::writeCheckpointToLogFile\n"
4889  << "--------------DOCUMENT CHECKPOINT START----------" << "\n"
4890  << checkpointDoc.toLatin1().data()
4891  << "---------------DOCUMENT CHECKPOINT END-----------" << "\n"
4892  << "----------------SCENE CHECKPOINT START-----------" << "\n"
4893  << checkpointScene.toLatin1().data()
4894  << "-----------------SCENE CHECKPOINT END------------" ;
4895  }
4896 }
void addCoordSystems(unsigned int numberCoordSystemToAdd)
Add some number (0 or more) of additional coordinate systems.
Definition: Document.cpp:147
Factory class for generating the points, composed of QGraphicsItem objects, along a GridLine...
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
QDir getDirectoryImportOpen() const
Get the current Import/Open directory.
void updateGraphicsLinesToMatchGraphicsPoints(const CurveStyles &modelCurveStyles, const Transformation &transformation)
A mouse move has just occurred so move the selected points, since they were dragged.
void updateCoordSystem(CoordSystemIndex coordSystemIndex)
Select a different CoordSystem.
Model for DlgSettingsGeneral and CmdSettingsGeneral.
void unsetPointStyle()
Apply no PointStyle.
Given a set of point identifiers, if a map is in effect (with its two axis endpoints) then both axis ...
void setPixmap(const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const DocumentModelColorFilter &modelColorFilter, const QPixmap &pixmapOriginal, const QString &curveSelected)
Update the images of all states, rather than just the current state.
DocumentAxesPointsRequired documentAxesPointsRequired() const
Get method for DocumentAxesPointsRequired.
Definition: Document.cpp:360
Dialog for sending error report with networking.
void setColorFilterSettings(const ColorFilterSettings &colorFilterSettings, const QPixmap &pixmap)
Apply the color filter of the currently selected curve. The pixmap is included so the background colo...
void printStream(QString indentation, QTextStream &str) const
Debugging method that supports print method of this class and printStream method of some other class(...
Definition: Document.cpp:836
unsigned int coordSystemCount() const
Number of CoordSystem.
Definition: Document.cpp:304
void setCurveName(const QString &curveName)
Load information for the specified curve name. When called externally, the load method must have been...
void createGhosts(QGraphicsScene &scene)
Create ghosts from the path/rect/polygon lists.
Definition: Ghosts.cpp:78
void updateColorFilter(const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const DocumentModelColorFilter &colorFilter, const QString &curveSelected)
Apply color filter settings.
Model for DlgSettingsPointMatch and CmdSettingsPointMatch.
Returns information about files.
Definition: LoadFileInfo.h:13
void updateAfterPointAddition()
Update the graphics attributes.
Color filter parameters for one curve. For a class, this is handled the same as LineStyle and PointSt...
void resetOnLoad(CmdMediator *cmdMediator)
Resetting makes re-initializes for documents after the first.
void updateSettingsMainWindow(const MainWindowModel &modelMainWindow)
Update with new main window properties.
void setSelectedCurveName(const QString &selectedCurveName)
Save curve name that is selected for the current coordinate system, for the next time the coordinate ...
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void setStatusBarMode(StatusBarMode statusBarMode)
Set the status bar visibility mode.
Definition: StatusBar.cpp:217
Model for DlgSettingsGridDisplay and CmdSettingsGridDisplay.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded...
DocumentModelColorFilter modelColorFilter() const
Get method for DocumentModelColorFilter.
Definition: Document.cpp:682
Command for cutting all selected Points.
Definition: CmdCut.h:18
void setModelAxesChecker(const DocumentModelAxesChecker &modelAxesChecker)
Set method for DocumentModelAxesChecker.
Definition: Document.cpp:945
void setModelGridRemoval(const DocumentModelGridRemoval &modelGridRemoval)
Set method for DocumentModelGridRemoval.
Definition: Document.cpp:1022
Dialog for saving error report to local hard drive.
void clear()
Deallocate and remove all grid lines.
Definition: GridLines.cpp:19
void updateDigitizeStateIfSoftwareTriggered(DigitizeState digitizeState)
After software-triggered state transition, this method manually triggers the action as if user had cl...
void setDragDropExport(bool dragDropExport)
Set method for drag and drop export.
unsigned int coordSystemIndexToBeRestored() const
Coordinate system index that was active before the ghosts.
Definition: Ghosts.cpp:73
static void setIdentifierIndex(unsigned int identifierIndex)
Reset the current index while performing a Redo.
Definition: Point.cpp:466
void printStream(QString indentation, QTextStream &str)
Debugging method that supports print method of this class and printStream method of some other class(...
void saveXml(QXmlStreamWriter &writer) const
Serialize to xml.
Wrapper around the Poppler library.
Definition: Pdf.h:28
Class that displays the current Segment Filter in a MainWindow toolbar.
Wrapper around OpenJPEG library, in C, for opening jpeg2000 files.
Definition: Jpeg2000.h:26
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
Dialog for editing Segments settings, for DigitizeStateSegment.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void fitInView(GraphicsView &view)
Zoom so background fills the window.
void setModelPointMatch(const DocumentModelPointMatch &modelPointMatch)
Set method for DocumentModelPointMatch.
Definition: Document.cpp:1029
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
Dialog for editing point match settings, for DigitizeStatePointMatch.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
Transformation transformation() const
Return read-only copy of transformation.
void updateModelDigitizeCurve(CmdMediator *cmdMediator, const DocumentModelDigitizeCurve &modelDigitizeCurve)
Update the digitize curve settings.
void setModelGeneral(const DocumentModelGeneral &modelGeneral)
Set method for DocumentModelGeneral.
Definition: Document.cpp:1008
void setEnabled(bool enabled)
Show the style with semi-transparency or full-transparency to indicate if associated Curve is active ...
Context class for transformation state machine.
Model for DlgSettingsCurveProperties and CmdSettingsCurveProperties.
Definition: CurveStyles.h:22
void createGridLinesForEvenlySpacedGrid(const DocumentModelGridDisplay &modelGridDisplay, const Document &document, const MainWindowModel &modelMainWindow, const Transformation &transformation, GridLines &gridLines)
Create a rectangular (cartesian) or annular (polar) grid of evenly spaced grid lines.
Wrapper around the QImage class for read and importing non-PDF files.
Definition: NonPdf.h:26
Dockable help window.
Definition: HelpWindow.h:16
void updateSettingsCurveAddRemove(const CurvesGraphs &curvesGraphs)
Update with new curves.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
bool canRedo() const
Returns true if there is at least one command on the stack.
QString activeCurve() const
Curve name for active Curve. This can include AXIS_CURVE_NAME, and empty string.
void setModelSegments(const DocumentModelSegments &modelSegments)
Set method for DocumentModelSegments.
Definition: Document.cpp:1036
MainTitleBarFormat mainTitleBarFormat() const
Get method for MainWindow titlebar filename format.
void handleContextMenuEventAxis(CmdMediator *cmdMediator, const QString &pointIdentifier)
See DigitizeStateAbstractBase::handleContextMenuEventAxis.
void updateAfterMouseRelease()
Call MainWindow::updateControls (which is private) after the very specific case - a mouse press/relea...
MainWindow(const QString &errorReportFile, const QString &fileCmdScriptFile, bool isRegressionTest, bool isGnuplot, bool isReset, QStringList loadStartupFiles, QWidget *parent=0)
Single constructor.
Definition: MainWindow.cpp:149
void handleCurveChange(CmdMediator *cmdMediator)
See DigitizeStateAbstractBase::handleCurveChange.
void setDirectoryExportSaveFromFilename(const QString &fileName)
Save the current Export/Save directory, after user has accepted the Export/Save dialog.
void setCoordinates(const QString &coordsScreen, const QString &coordsGraph, const QString &resolutionGraph)
Populate the coordinates fields. Unavailable values are empty. Html-encoding to highlight with colors...
Definition: StatusBar.cpp:198
void handleContextMenuEventGraph(CmdMediator *cmdMediator, const QStringList &pointIdentifiers)
See DigitizeStateAbstractBase::handleContextMenuEventGraph.
void cmdFileClose()
Close file. This is called from a file script command.
Definition: MainWindow.cpp:303
void setModelGridDisplay(const DocumentModelGridDisplay &modelGridDisplay)
Set method for DocumentModelGridDisplay.
Definition: Document.cpp:1015
void updateAfterCommand(CmdMediator &cmdMediator, double highlightOpacity, GeometryWindow *geometryWindow)
Update the Points and their Curves after executing a command.
bool modeMap() const
True if document scale is set using a scale bar, otherwise using axis points.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void updateViewsOfSettings(const QString &activeCurve)
Update curve-specific view of settings. Private version gets active curve name from DigitizeStateCont...
QString selectedGraphCurve() const
Curve name that is currently selected in m_cmbCurve.
void setHighlightOpacity(double highlightOpacity)
Set method for highlight opacity.
Class for showing points and lines for all coordinate systems simultaneously, even though the code no...
Definition: Ghosts.h:26
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:689
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void slotRedo()
Move next command from list to CmdMediator. Noop if there are no more commands.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
virtual void update(const CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow, const QString &curveSelected, const Transformation &transformation)
Populate the table with the specified Curve.
void getTableStatus(bool &tableIsActive, bool &tableIsCopyable) const
Give table status so MainWindow can determine if table can be copied.
void setModelDigitizeCurve(const DocumentModelDigitizeCurve &modelDigitizeCurve)
Set method for DocumentModelDigitizeCurve.
Definition: Document.cpp:994
PointStyle pointStyle() const
Get method for PointStyle.
Definition: CurveStyle.cpp:75
void triggerStateTransition(TransformationState transformationState, CmdMediator &cmdMediator, const Transformation &transformation, const QString &selectedGraphCurve)
Trigger a state transition to be performed immediately.
ZoomFactor zoomOut(ZoomFactor currentZoomFactor, double m11, double m22, bool actionZoomFillIsChecked) const
Zoom out.
Window that displays the geometry information, as a table, for the current curve. ...
void cmdFileOpen(const QString &fileName)
Open file. This is called from a file script command.
Definition: MainWindow.cpp:329
void setDocumentAxesPointsRequired(DocumentAxesPointsRequired documentAxesPointsRequired)
Set the number of axes points required.
virtual void update(const CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow, const QString &curveSelected, const Transformation &transformation)
Populate the table with the specified Curve.
CmdMediator * cmdMediator()
Accessor for commands to process the Document.
Definition: MainWindow.cpp:337
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
NonPdfReturn load(const QString &fileName, QImage &image, ImportCropping importCropping, bool isErrorReportRegressionTest) const
Try to load the specified file. Success is indicated in the function return value.
Definition: NonPdf.cpp:18
void setModelCoords(const DocumentModelCoords &modelCoords)
Set method for DocumentModelCoords.
Definition: Document.cpp:970
void wakeUp()
Enable all widgets in the status bar. This is called just after a Document becomes active...
Definition: StatusBar.cpp:300
BackgroundImage selectOriginal(BackgroundImage backgroundImage)
Make original background visible, for DigitizeStateColorPicker.
void setDirectoryImportOpenFromFilename(const QString &fileName)
Save the current Import/Open directory, after user has accepted the Import/Open dialog.
double mapToFactor(ZoomFactor zoomFactor) const
Return the floating precision zoom factor given the enum value.
static void bindToMainWindow(const MainWindow *mainWindow)
Bind to MainWindow so this class can access the command stack.
Dialog for editing grid removal settings.
Dialog for editing exporting settings.
void setDelimiter(ExportDelimiter exportDelimiter)
Set method for delimiter.
void setLocale(QLocale::Language language, QLocale::Country country)
Set method for locale given attributes.
void handleKeyPress(CmdMediator *cmdMediator, Qt::Key key, bool atLeastOneSelectedItem)
See DigitizeStateAbstractBase::handleKeyPress.
void uploadErrorReport(const QString &report)
Upload the error report asynchronously.
void setPixmap(const QImage &image)
Set method for the background pixmap.
Definition: Document.cpp:1043
QStringList selectedPointIdentifiers(const QList< QGraphicsItem * > &items) const
Return list of selected point identifiers.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void showTemporaryMessage(const QString &temporaryMessage)
Show temporary message in status bar.
void retrievePoints(const Transformation &transformation, QList< QPoint > &points, QList< double > &ordinals) const
Retrieve points from clipboard.
Dialog for editing curve names settings.
bool load(const QString &filename, QImage &image) const
Load image from jpeg2000 file.
Definition: Jpeg2000.cpp:192
void setImageIsLoaded(CmdMediator *cmdMediator, bool imageIsLoaded)
Set the image so QGraphicsView cursor and drag mode are accessible.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
int maximumGridLines() const
Maximum number of grid lines.
void setCoordSystemIndex(CoordSystemIndex coordSystemIndex)
Set the index of current active CoordSystem.
Definition: Document.cpp:912
void updateSettingsDigitizeCurve(const DocumentModelDigitizeCurve &modelDigitizeCurve)
Update with new curve digitization styles.
bool dragDropExport() const
Get method for drag and drop export.
void loadMainWindowModel(CmdMediator &cmdMediator, const MainWindowModel &modelMainWindow)
Replaced load method since the main window settings are independent of document, unlike other DlgSett...
This class consolidates utility routines that deal with graphics items that are getting extracted fro...
Tutorial using a strategy like a comic strip with decision points deciding which panels appear...
Definition: TutorialDlg.h:19
bool isModified() const
Dirty flag.
Definition: CmdMediator.cpp:82
void cmdFileExport(const QString &fileName)
Export file. This is called from a file script command.
Definition: MainWindow.cpp:311
bool smallDialogs() const
Get method for small dialogs flag.
Strategy class for exporting to a file. This strategy is external to the Document class so that class...
Definition: ExportToFile.h:25
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
CoordSystemIndex coordSystemIndex() const
Index of current active CoordSystem.
Definition: Document.cpp:311
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
Dockable text window containing checklist guide.
void setModelExport(const DocumentModelExportFormat &modelExport)
Set method for DocumentModelExportFormat.
Definition: Document.cpp:1001
Model for DlgSettingsDigitizeCurve and CmdSettingsDigitizeCurve.
GraphicsView & view()
View for the QImage and QGraphicsItems, without const.
Affine transformation between screen and graph coordinates, based on digitized axis points...
Dialog for editing filtering settings.
StatusBarMode statusBarMode() const
Current mode for status bar visibility. This is tracked locally so this class knows when to hide/show...
Definition: StatusBar.h:45
ZoomControl zoomControl() const
Get method for zoom control.
QString fileExtensionTsv() const
File extension for tsv export files.
Details for a specific Point.
Definition: PointStyle.h:20
Class for exporting during regression, when the Transformation has not yet been defined.
Container for all graph curves. The axes point curve is external to this class.
Definition: CurvesGraphs.h:24
void setBackgroundImage(BackgroundImage backgroundImage)
Transition to the specified state. This method is used by classes outside of the state machine to tri...
Model for DlgSettingsColorFilter and CmdSettingsColorFilter.
Wrapper around QStatusBar to manage permanent widgets.
Definition: StatusBar.h:24
GraphicsScene & scene()
Scene container for the QImage and QGraphicsItems.
void updateSettingsGridDisplay(const DocumentModelGridDisplay &modelGridDisplay)
Update with new grid display properties.
void setEnabled(bool enabled)
Show the style with semi-transparency or full-transparency to indicate if associated Curve is active ...
void updateSettingsCurveStyles(const CurveStyles &modelCurveStyles)
Update with new curve styles.
Client for interacting with Engauge server.
Definition: NetworkClient.h:16
void setModelCurveStyles(const CurveStyles &modelCurveStyles)
Set method for CurveStyles.
Definition: Document.cpp:977
Context class that manages the background image state machine.
bool browserIsEmpty() const
When browser is empty, it is pointless to show it.
CurveStyles modelCurveStyles() const
Get method for CurveStyles.
Definition: Document.cpp:696
QGraphicsView class with event handling added. Typically the events are sent to the active digitizing...
Definition: GraphicsView.h:20
virtual void doCopy()
Copy the current selection to the clipboard.
Container for all DigitizeStateAbstractBase subclasses. This functions as the context class in a stan...
Model for DlgSettingsMainWindow.
void appendNewCmd(CmdMediator *cmdMediator, QUndoCommand *cmd)
Append just-created QUndoCommand to command stack. This is called from DigitizeStateAbstractBase subc...
bool canRedo() const
Return true if there is a command available.
DocumentModelAxesChecker modelAxesChecker() const
Get method for DocumentModelAxesChecker.
Definition: Document.cpp:675
void updateModelSegments(const DocumentModelSegments &modelSegments)
Update the segments given the new settings.
bool canPaste(const Transformation &transformation, const QSize &viewSize) const
Return true if there is good data in the clipboard for pasting, and that operation is compatible with...
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded...
void coordTextForStatusBar(QPointF cursorScreen, QString &coordsScreen, QString &coordsGraph, QString &resolutionGraph, bool usingScaleBar)
Return string descriptions of cursor coordinates for status bar.
Command for adding one or more graph points. This is for Segment Fill mode.
Dialog for editing general settings.
void resetPositionHasChangedFlags()
Reset positionHasChanged flag for all items. Typically this is done as part of mousePressEvent.
void fileExport(const QString &filename) const
Export to the specified file. This is called when the Transformation has not been defined...
QPixmap pixmap() const
See Document::pixmap.
void setModelColorFilter(const DocumentModelColorFilter &modelColorFilter)
Set method for DocumentModelColorFilter.
Definition: Document.cpp:952
void close()
Open Document is being closed so remove the background.
QImage imageForCurveState() const
Image for the Curve state, even if the current state is different.
Model for DlgSettingsCoords and CmdSettingsCoords.
void setVisible(bool visible)
Make all grid lines visible or hidden.
Definition: GridLines.cpp:38
void updateAfterCommand()
See GraphicsScene::updateAfterCommand.
QString fileExtensionCsv() const
File extension for csv export files.
Curve that overlays the current scene so the regression-fitted curve is visible.
Definition: FittingCurve.h:16
void updateSettingsColorFilter(const DocumentModelColorFilter &modelColorFilter)
Update with new color filter properties.
Dialog for editing grid display settings.
void setCurveSelected(const Transformation &transformation, const DocumentModelGridRemoval &modelGridRemoval, const DocumentModelColorFilter &modelColorFilter, const QString &curveSelected)
Update the selected curve.
Command for deleting all selected Points.
Definition: CmdDelete.h:18
void setMaximumGridLines(int maximumGridLines)
Set method for maximum number of grid lines.
Dialog for editing DigitizeStateCurve settings.
void updateSettingsAxesChecker(const DocumentModelAxesChecker &modelAxesChecker)
Update with new axes indicator properties.
void updateSettingsPointMatch(const DocumentModelPointMatch &modelPointMatch)
Update with new point match properties.
void updateSettingsGeneral(const DocumentModelGeneral &modelGeneral)
Update with new general properties.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void redo(MainWindow &mainWindow)
Apply the next command. Requires non-empty stack.
void setPointStyle(const PointStyle &pointStyle)
Apply the PointStyle of the currently selected curve.
QImage imageFiltered() const
Background image that has been filtered for the current curve. This asserts if a curve-specific image...
void updateSettingsGridRemoval(const DocumentModelGridRemoval &modelGridRemoval)
Update with new grid removal properties.
Class that displays a view of the current Curve&#39;s point style.
void showTemporaryMessage(const QString &message)
Show temporary message in status bar. After a short interval the message will disappear.
Definition: StatusBar.cpp:227
void exportToFile(const DocumentModelExportFormat &modelExport, const Document &document, const MainWindowModel &modelMainWindow, const Transformation &transformation, QTextStream &str) const
Export Document points according to the settings.
double highlightOpacity() const
Get method for highlight opacity.
void updateCurveStyles(const CurveStyles &modelCurveStyles)
Update curve styles after settings changed.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: Document.cpp:346
void unsetColorFilterSettings()
Apply no color filter.
Dialog for setting the advanced parameters in a newly imported Document.
Wizard for setting up the checklist guide.
const ColorFilterSettings colorFilterSettings(const QString &curveName) const
Get method for copying one color filter. Cannot return just a reference or else there is a warning ab...
Dialog for editing main window settings, which are entirely independent of all documents.
void handleMouseMove(CmdMediator *cmdMediator, QPointF pos)
See DigitizeStateAbstractBase::handleMouseMove.
int pdfResolution() const
Get method for resolution of imported PDF files, in dots per inch.
QDir getDirectoryExportSave() const
Get the current Export/Save directory.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
bool transformIsDefined() const
Transform is defined when at least three axis points have been digitized.
Model for DlgSettingsAxesChecker and CmdSettingsAxesChecker.
QString filterTsv() const
QFileDialog filter for TSV files.
Command stack that shadows the CmdMediator command stack at startup when reading commands from an err...
void updateSettingsExportFormat(const DocumentModelExportFormat &modelExport)
Update with new export properties.
Dialog for editing coordinates settings.
Import of point data from clipboard.
Load QImage from url. This is trivial for a file, but requires an asynchronous download step for http...
virtual bool eventFilter(QObject *, QEvent *)
Catch secret keypresses.
void startLoadImage(const QUrl &url)
Start the asynchronous loading of an image from the specified url.
void load(CmdMediator &cmdMediator)
Load settings from Document.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
bool loadsAsDigFile(const QString &urlString) const
Returns true if specified file name can be loaded as a DIG file.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded...
Perform calculations to determine the next zoom setting given the current zoom setting, when zooming in or out.
bool isGnuplot() const
Get method for gnuplot flag.
CurveStyle curveStyle(const QString &curveName) const
CurveStyle in specified curve.
Definition: CurveStyles.cpp:79
Dialog for editing curve properties settings.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void setZoomControl(ZoomControl zoomControl)
Set method for zoom control.
void setMainTitleBarFormat(MainTitleBarFormat mainTitleBarFormat)
Set method for MainWindow titlebar filename format.
void handleMouseRelease(CmdMediator *cmdMediator, QPointF pos)
See DigitizeStateAbstractBase::handleMouseRelease.
void captureGraphicsItems(QGraphicsScene &scene)
Take a snapshot of the graphics items.
Definition: Ghosts.cpp:26
Command queue stack.
Definition: CmdMediator.h:23
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void setZoomFactorInitial(ZoomFactorInitial zoomFactorInitial)
Set method for initial zoom factor.
void saveErrorReportFileAndExit(const char *comment, const char *file, int line, const char *context) const
Save error report and exit.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void signalZoom(int)
Send zoom selection, picked from menu or keystroke, to StatusBar.
Model for DlgSettingsSegments and CmdSettingsSegments.
void destroyGhosts(QGraphicsScene &scene)
Destory ghosts. Called at end of algorithm.
Definition: Ghosts.cpp:119
void cmdFileImport(const QString &fileName)
Import file. This is called from a file script command.
Definition: MainWindow.cpp:320
void setCurvesGraphs(const CurvesGraphs &curvesGraphs)
Let CmdAbstract classes overwrite CurvesGraphs.
Definition: Document.cpp:926
void updateAxesChecker(CmdMediator &cmdMediator, const Transformation &transformation)
Apply the new DocumentModelAxesChecker.
void resizeEvent(QResizeEvent *event)
Intercept resize event so graphics scene can be appropriately resized when in Fill mode...
QString selectedCurveName() const
Currently selected curve name. This is used to set the selected curve combobox in MainWindow...
QStringList supportedImageWildcards() const
List the supported jpeg2000 file extensions, for filtering import files.
Definition: Jpeg2000.cpp:305
void updateSettingsCoords(const DocumentModelCoords &modelCoords)
Update with new coordinate properties.
void loadCommands(MainWindow &mainWindow, Document &document, QXmlStreamReader &reader)
Load commands from serialized xml.
void update(const CmdMediator &cmdMediator, bool documentIsExported)
Update using current CmdMediator/Document state.
ZoomFactorInitial zoomFactorInitial() const
Get method for initial zoom factor.
File that manages a command stack for regression testing of file import/open/export/close.
Definition: FileCmdScript.h:20
QString xmlToUpload() const
Xml to be uploaded. Includes document if user has approved.
void setSmallDialogs(bool smallDialogs)
Set method for small dialogs flag.
PdfReturn load(const QString &fileName, QImage &image, int resolution, ImportCropping importCropping, bool isErrorReportRegressionTest) const
Try to load the specified file. Success is indicated in the function return value.
Definition: Pdf.cpp:25
void handleMousePress(CmdMediator *cmdMediator, QPointF pos)
See DigitizeStateAbstractBase::handleMousePress.
Add point and line handling to generic QGraphicsScene.
Definition: GraphicsScene.h:33
QString filterCsv() const
QFileDialog filter for CSV files.
ImportCropping importCropping() const
Get method for import cropping.
Command for moving all selected Points by a specified translation.
Definition: CmdCopy.h:18
DocumentModelGridDisplay modelGridDisplay() const
Get method for DocumentModelGridDisplay.
Definition: Document.cpp:724
Window that displays curve fitting as applied to the currently selected curve.
Definition: FittingWindow.h:34
void saveXml(QXmlStreamWriter &writer) const
Save document to xml.
Definition: Document.cpp:878
QLocale locale() const
Get method for locale.
Model for DlgSettingsGridRemoval and CmdSettingsGridRemoval. The settings are unstable until the user...
QString reasonForUnsuccessfulRead() const
See Document::reasonForUnsuccessfulRead.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void updateSettingsSegments(const DocumentModelSegments &modelSegments)
Update with new segments properties.
Command for changing the currently selected CoordSystem.
ZoomFactor zoomIn(ZoomFactor currentZoomFactor, double m11, double m22, bool actionZoomFillIsChecked) const
Zoom in.
void showCurves(bool show, bool showAll=false, const QString &curveName="")
Show or hide all Curves (if showAll is true) or just the selected Curve (if showAll is false);...
Dialog for editing axes checker settings.
void setPdfResolution(int resolution)
Set method for resolution of imported PDF files, in dots per inch.
Dialog to be displayed whenever some operation or processing cannot be performed since the axis point...
void updateGraphicsLinesToMatchGraphicsPoints()
Update the graphics lines so they follow the graphics points, after a drag, addition, removal, and such.
Persist the directory between successive Import/Open operations, or successive Export/Save operations...
void populateCurvesGraphs(CoordSystemIndex coordSystemIndex, CurvesGraphs &curvesGraphs)
Create entries in CurvesGraphs for each curve name that user provided.
DocumentModelGridRemoval modelGridRemoval() const
Get method for DocumentModelGridRemoval.
Definition: Document.cpp:731
void setImportCropping(ImportCropping importCropping)
Set method for import cropping.
MainWindowModel modelMainWindow() const
Get method for main window model.
QString templateHtml(CoordSystemIndex coordSystemIndex) const
Template html comprising the checklist for display.
QStringList unite(CmdMediator *cmdMediator, const QStringList &pointIdentifiersIn) const
Add.
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: CmdMediator.cpp:62
void setTemplateHtml(const QString &html, const QStringList &curveNames)
Populate the browser with template html.
DocumentModelExportFormat modelExport() const
Get method for DocumentModelExportFormat.
Definition: Document.cpp:710
virtual void clear()
Clear stale information.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
QStringList curveNames(CoordSystemIndex coordSystemIndex) const
Curve names to be placed into Document.
bool successfulRead() const
Wrapper for Document::successfulRead.
About Engauge dialog. This provides a hidden shortcut for triggering ENGAUGE_ASSERT.
Definition: DlgAbout.h:15
bool overrideCsvTsv() const
Get method for csv/tsv format override.
virtual void clear()
Clear stale information.
virtual void showEvent(QShowEvent *)
Processing performed after gui becomes available.
bool transformIsDefined() const
Return true if all three axis points have been defined.
void requestImmediateStateTransition(CmdMediator *cmdMediator, DigitizeState digitizeState)
Perform immediate state transition. Called from outside state machine.
virtual void doCopy()
Copy the current selection to the clipboard.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.