1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released      *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission.     *
5  ******************************************************************************************************/
6 
7 #include "CallbackBoundingRects.h"
8 #include "CmdMediator.h"
9 #include "CmdSettingsExportFormat.h"
10 #include "DocumentModelExportFormat.h"
11 #include "DlgSettingsExportFormat.h"
12 #include "ExportFileExtension.h"
13 #include "ExportFileExtensionOverride.h"
14 #include "ExportFileFunctions.h"
15 #include "ExportFileRelations.h"
16 #include "ExportToFile.h"
17 #include "Logger.h"
18 #include "MainWindow.h"
19 #include "MainWindowModel.h"
20 #include <QCheckBox>
21 #include <QComboBox>
22 #include <QDoubleValidator>
23 #include <QGridLayout>
24 #include <QGroupBox>
25 #include <QHBoxLayout>
26 #include <QLabel>
27 #include <QLineEdit>
28 #include <QListWidget>
29 #include <QPushButton>
30 #include <QRadioButton>
31 #include <QScrollBar>
32 #include <QSettings>
33 #include <QTabWidget>
34 #include <QTextEdit>
35 #include <QTextStream>
36 #include <QVBoxLayout>
37 #include "Settings.h"
38 #include "Transformation.h"
39 
40 // Colors that should match the help text for m_editPreview
41 const QString COLOR_FUNCTIONS = ("#DDDDFF");
42 const QString COLOR_RELATIONS = ("#DDFFDD");
43 
44 const int MIN_INDENT_COLUMN_WIDTH = 20;
45 const int MIN_HEADER_EMPTY_COLUMN_WIDTH = 10;
46 const int MIN_EDIT_WIDTH = 110;
47 const int MAX_EDIT_WIDTH = 180;
48 
49 const int TAB_WIDGET_INDEX_FUNCTIONS = 0;
50 const int TAB_WIDGET_INDEX_RELATIONS = 1;
51 
52 const QString EMPTY_PREVIEW;
53 
54 const int MINIMUM_DIALOG_WIDTH_EXPORT_FORMAT = 600;
55 const int MINIMUM_HEIGHT = 780;
56 
DlgSettingsExportFormat(MainWindow & mainWindow)57 DlgSettingsExportFormat::DlgSettingsExportFormat(MainWindow &mainWindow) :
58   DlgSettingsAbstractBase (tr ("Export Format"),
59                            "DlgSettingsExportFormat",
60                            mainWindow),
61   m_validatorFunctionsPointsEvenlySpacing (nullptr),
62   m_validatorRelationsPointsEvenlySpacing (nullptr),
63   m_modelExportBefore (nullptr),
64   m_modelExportAfter (nullptr),
65   m_haveFunction (false),
66   m_haveRelation (false)
67 {
68   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::DlgSettingsExportFormat";
69 
70   QWidget *subPanel = createSubPanel ();
71   finishPanel (subPanel,
72                MINIMUM_DIALOG_WIDTH_EXPORT_FORMAT);
73 }
74 
~DlgSettingsExportFormat()75 DlgSettingsExportFormat::~DlgSettingsExportFormat()
76 {
77   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::~DlgSettingsExportFormat";
78 
79   delete m_validatorFunctionsPointsEvenlySpacing;
80   delete m_validatorRelationsPointsEvenlySpacing;
81 }
82 
createCurveSelection(QGridLayout * layout,int & row)83 void DlgSettingsExportFormat::createCurveSelection (QGridLayout *layout, int &row)
84 {
85   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createCurveSelection";
86 
87   QLabel *labelIncluded = new QLabel (tr ("Included"));
88   layout->addWidget (labelIncluded, row, 0);
89 
90   QLabel *labelExcluded = new QLabel (tr ("Not included"));
91   layout->addWidget (labelExcluded, row++, 2);
92 
93   m_listIncluded = new QListWidget;
94   m_listIncluded->setSortingEnabled (false); // Preserve order from Document
95   m_listIncluded->setWhatsThis (tr ("List of curves to be included in the exported file.\n\n"
96                                     "The order of the curves here does not affect the order in the exported file. That "
97                                     "order is determined by the Curves settings."));
98   m_listIncluded->setSelectionMode (QAbstractItemView::MultiSelection);
99   layout->addWidget (m_listIncluded, row, 0, 4, 1);
100   connect (m_listIncluded, SIGNAL (itemSelectionChanged ()), this, SLOT (slotListIncluded()));
101 
102   m_listExcluded = new QListWidget;
103   m_listExcluded->setSortingEnabled (false); // Preserve order from Document
104   m_listExcluded->setWhatsThis (tr ("List of curves to be excluded from the exported file"));
105   m_listExcluded->setSelectionMode (QAbstractItemView::MultiSelection);
106   layout->addWidget (m_listExcluded, row++, 2, 4, 1);
107   connect (m_listExcluded, SIGNAL (itemSelectionChanged ()), this, SLOT (slotListExcluded()));
108 
109   m_btnInclude = new QPushButton (QString ("<<%1").arg (tr ("Include")));
110   m_btnInclude->setEnabled (false);
111   m_btnInclude->setWhatsThis (tr ("Move the currently selected curve(s) from the excluded list"));
112   layout->addWidget (m_btnInclude, row++, 1);
113   connect (m_btnInclude, SIGNAL (released ()), this, SLOT (slotInclude()));
114 
115   m_btnExclude = new QPushButton (QString ("%1>>").arg (tr ("Exclude")));
116   m_btnExclude->setEnabled (false);
117   m_btnExclude->setWhatsThis (tr ("Move the currently selected curve(s) from the included list"));
118   layout->addWidget (m_btnExclude, row++, 1);
119   connect (m_btnExclude, SIGNAL (released ()), this, SLOT (slotExclude()));
120 
121   row++;
122 }
123 
createDelimiters(QHBoxLayout * layoutMisc)124 void DlgSettingsExportFormat::createDelimiters (QHBoxLayout *layoutMisc)
125 {
126   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createDelimiters";
127 
128   QGroupBox *groupDelimiters = new QGroupBox (tr ("Delimiters"));
129   layoutMisc->addWidget (groupDelimiters, 1);
130 
131   QVBoxLayout *layoutDelimiters = new QVBoxLayout;
132   groupDelimiters->setLayout (layoutDelimiters);
133 
134   m_btnDelimitersCommas = new QRadioButton (exportDelimiterToString (EXPORT_DELIMITER_COMMA));
135   m_btnDelimitersCommas->setWhatsThis (tr ("Exported file will have commas between adjacent values, unless overridden by tabs in TSV files."));
136   layoutDelimiters->addWidget (m_btnDelimitersCommas);
137   connect (m_btnDelimitersCommas, SIGNAL (released ()), this, SLOT (slotDelimitersCommas()));
138 
139   m_btnDelimitersSpaces = new QRadioButton (exportDelimiterToString (EXPORT_DELIMITER_SPACE));
140   m_btnDelimitersSpaces->setWhatsThis (tr ("Exported file will have spaces between adjacent values, unless overridden by commas in CSV files, "
141                                            "or tabs in TSV files."));
142   layoutDelimiters->addWidget (m_btnDelimitersSpaces);
143   connect (m_btnDelimitersSpaces, SIGNAL (released ()), this, SLOT (slotDelimitersSpaces()));
144 
145   m_btnDelimitersTabs = new QRadioButton (exportDelimiterToString (EXPORT_DELIMITER_TAB));
146   m_btnDelimitersTabs->setWhatsThis (tr ("Exported file will have tabs between adjacent values, unless overridden by commas in CSV files."));
147   layoutDelimiters->addWidget (m_btnDelimitersTabs);
148   connect (m_btnDelimitersTabs, SIGNAL (released ()), this, SLOT (slotDelimitersTabs()));
149 
150   m_btnDelimitersSemicolons = new QRadioButton (exportDelimiterToString (EXPORT_DELIMITER_SEMICOLON));
151   m_btnDelimitersSemicolons->setWhatsThis (tr ("Exported file will have semicolons between adjacent values, unless overridden by commas in CSV files."));
152   layoutDelimiters->addWidget (m_btnDelimitersSemicolons);
153   connect (m_btnDelimitersSemicolons, SIGNAL (released ()), this, SLOT (slotDelimitersSemicolons()));
154 
155   m_chkOverrideCsvTsv = new QCheckBox (tr ("Override in CSV/TSV files"));
156   m_chkOverrideCsvTsv->setWhatsThis (tr ("Comma-separated value (CSV) files and tab-separated value (TSV) files will use commas and tabs "
157                                          "respectively, unless this setting is selected. Selecting this setting will apply the delimiter setting "
158                                          "to every file."));
159   connect (m_chkOverrideCsvTsv, SIGNAL (stateChanged (int)), this, SLOT (slotOverrideCsvTsv(int)));
160   layoutDelimiters->addWidget (m_chkOverrideCsvTsv);
161 }
162 
createFileLayout(QHBoxLayout * layoutMisc)163 void DlgSettingsExportFormat::createFileLayout (QHBoxLayout *layoutMisc)
164 {
165   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createFileLayout";
166 
167   QGroupBox *groupLayout = new QGroupBox (tr ("Layout"));
168   layoutMisc->addWidget (groupLayout, 1);
169 
170   QVBoxLayout *layoutLayout = new QVBoxLayout;
171   groupLayout->setLayout (layoutLayout);
172 
173   m_btnCurvesLayoutAllCurves = new QRadioButton (tr ("All curves on each line"));
174   m_btnCurvesLayoutAllCurves->setWhatsThis (tr ("Exported file will have, on each line, "
175                                                    "an X value, the Y value for the first curve, the Y value for the second curve,..."));
176   layoutLayout->addWidget (m_btnCurvesLayoutAllCurves);
177   connect (m_btnCurvesLayoutAllCurves, SIGNAL (released()), this, SLOT (slotFunctionsLayoutAllCurves ()));
178 
179   m_btnCurvesLayoutOneCurve = new QRadioButton (tr ("One curve on each line"));
180   m_btnCurvesLayoutOneCurve->setWhatsThis (tr ("Exported file will have all the points for "
181                                                   "the first curve, with one X-Y pair on each line, then the points for the second curve,..."));
182   layoutLayout->addWidget (m_btnCurvesLayoutOneCurve);
183   connect (m_btnCurvesLayoutOneCurve, SIGNAL (released()), this, SLOT (slotFunctionsLayoutOneCurve ()));
184 }
185 
createFunctionsPointsSelection(QHBoxLayout * layoutFunctions)186 void DlgSettingsExportFormat::createFunctionsPointsSelection (QHBoxLayout *layoutFunctions)
187 {
188   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createFunctionsPointsSelection";
189 
190   QGroupBox *groupPointsSelection = new QGroupBox (tr ("Function Points Selection"));
191   layoutFunctions->addWidget (groupPointsSelection, 1);
192 
193   QGridLayout *layoutPointsSelections = new QGridLayout;
194   groupPointsSelection->setLayout (layoutPointsSelections);
195 
196   layoutPointsSelections->setColumnMinimumWidth(0, MIN_INDENT_COLUMN_WIDTH);
197   layoutPointsSelections->setColumnStretch (0, 0);
198   layoutPointsSelections->setColumnStretch (1, 0);
199   layoutPointsSelections->setColumnStretch (2, 0);
200   layoutPointsSelections->setColumnStretch (3, 0);
201   layoutPointsSelections->setColumnStretch (4, 1);
202 
203   int row = 0;
204 
205   m_btnFunctionsPointsAllCurves = new QRadioButton (tr ("Interpolate Ys at Xs from all curves"));
206   m_btnFunctionsPointsAllCurves->setWhatsThis (tr ("Exported file will have values at every unique X "
207                                                    "value from every curve. Y values will be linearly interpolated if necessary"));
208   layoutPointsSelections->addWidget (m_btnFunctionsPointsAllCurves, row, 0, 1, 2);
209   connect (m_btnFunctionsPointsAllCurves, SIGNAL (released()), this, SLOT (slotFunctionsPointsAllCurves()));
210 
211   // Put extrapolation control up near interpolation controls and away from raw control which never uses extrapolation
212   m_chkExtrapolateOutsideEndpoints = new QCheckBox (tr ("Extrapolate outside endpoints"));
213   m_chkExtrapolateOutsideEndpoints->setWhatsThis (tr ("Enable or disable extrapolation outside of endpoints of each curve. If disabled, "
214                                                       "only points between the endpoints of each curve are exported"));
215   layoutPointsSelections->addWidget (m_chkExtrapolateOutsideEndpoints, row++, 4, 1, 1, Qt::AlignRight);
216   connect (m_chkExtrapolateOutsideEndpoints, SIGNAL (stateChanged (int)), this, SLOT (slotFunctionsExtrapolateOutsideEndpoints(int)));
217 
218   m_btnFunctionsPointsFirstCurve = new QRadioButton (tr ("Interpolate Ys at Xs from first curve"));
219   m_btnFunctionsPointsFirstCurve->setWhatsThis (tr ("Exported file will have values at every unique X "
220                                                     "value from the first curve. Y values will be linearly interpolated if necessary"));
221   layoutPointsSelections->addWidget (m_btnFunctionsPointsFirstCurve, row++, 0, 1, 4);
222   connect (m_btnFunctionsPointsFirstCurve, SIGNAL (released()), this, SLOT (slotFunctionsPointsFirstCurve()));
223 
224   m_btnFunctionsPointsEvenlySpaced = new QRadioButton (tr ("Interpolate Ys at evenly spaced X values that are automatically selected"));
225   m_btnFunctionsPointsEvenlySpaced->setWhatsThis (tr ("Exported file will have values at evenly spaced X values, separated by the interval selected below."));
226   layoutPointsSelections->addWidget (m_btnFunctionsPointsEvenlySpaced, row++, 0, 1, 4);
227   connect (m_btnFunctionsPointsEvenlySpaced, SIGNAL (released()), this, SLOT (slotFunctionsPointsEvenlySpaced()));
228 
229   QLabel *labelInterval = new QLabel (QString ("%1:").arg (tr ("Interval")));
230   layoutPointsSelections->addWidget (labelInterval, row, 1, 1, 1, Qt::AlignRight);
231 
232   m_editFunctionsPointsEvenlySpacing = new QLineEdit;
233   m_validatorFunctionsPointsEvenlySpacing = new QDoubleValidator; // Minimum value, to prevent overflow, is set later according to settings
234   m_editFunctionsPointsEvenlySpacing->setValidator (m_validatorFunctionsPointsEvenlySpacing);
235   m_editFunctionsPointsEvenlySpacing->setMinimumWidth (MIN_EDIT_WIDTH);
236   m_editFunctionsPointsEvenlySpacing->setMaximumWidth (MAX_EDIT_WIDTH);
237   m_editFunctionsPointsEvenlySpacing->setWhatsThis (tr ("Interval, in the units of X, between successive points in the X direction.\n\n"
238                                                         "If the scale is linear, then this interval is added to successive X values. If the scale is "
239                                                         "logarithmic, then this interval is multiplied to successive X values.\n\n"
240                                                         "The X values will be automatically aligned along simple numbers. If the first and/or last "
241                                                         "points are not along the aligned X values, then one or two additional points are added "
242                                                         "as necessary."));
243   layoutPointsSelections->addWidget (m_editFunctionsPointsEvenlySpacing, row, 2, 1, 1, Qt::AlignLeft);
244   connect (m_editFunctionsPointsEvenlySpacing, SIGNAL (textChanged(const QString &)), this, SLOT (slotFunctionsPointsEvenlySpacedInterval(const QString &)));
245 
246   m_cmbFunctionsPointsEvenlySpacingUnits = new QComboBox;
247   m_cmbFunctionsPointsEvenlySpacingUnits->setWhatsThis (tr ("Units for spacing interval.\n\n"
248                                                             "Pixel units are preferred when the spacing is to be independent of the X scale. The spacing will be "
249                                                             "consistent across the graph, even if the X scale is logarithmic.\n\n"
250                                                             "Graph units are preferred when the spacing is to depend on the X scale."));
251   m_cmbFunctionsPointsEvenlySpacingUnits->addItem(exportPointsIntervalUnitsToString (EXPORT_POINTS_INTERVAL_UNITS_GRAPH),
252                                                   QVariant (EXPORT_POINTS_INTERVAL_UNITS_GRAPH));
253   m_cmbFunctionsPointsEvenlySpacingUnits->addItem(exportPointsIntervalUnitsToString (EXPORT_POINTS_INTERVAL_UNITS_SCREEN),
254                                                   QVariant (EXPORT_POINTS_INTERVAL_UNITS_SCREEN));
255   connect (m_cmbFunctionsPointsEvenlySpacingUnits, SIGNAL (activated (const QString &)),
256            this, SLOT (slotFunctionsPointsEvenlySpacedIntervalUnits (const QString &))); // activated() ignores code changes
257   layoutPointsSelections->addWidget (m_cmbFunctionsPointsEvenlySpacingUnits, row, 3, 1, 1, Qt::AlignLeft);
258 
259   m_lblOverflowFunctions = new QLabel (tr ("Too many points"));
260   m_lblOverflowFunctions->setStyleSheet ("QLabel { color : red; }");
261   m_lblOverflowFunctions->setWhatsThis (tr ("Warning that interval is too small. Adjust interval or increase point limit in Main Window settings"));
262   layoutPointsSelections->addWidget (m_lblOverflowFunctions, row++, 4, 1, 1, Qt::AlignLeft);
263 
264   m_btnFunctionsPointsGridLines = new QRadioButton (tr ("Interpolate Ys at evenly spaced X values on grid lines"));
265   m_btnFunctionsPointsGridLines->setWhatsThis (tr ("Exported file will have values at evenly spaced X values at the vertical grid lines."));
266   layoutPointsSelections->addWidget (m_btnFunctionsPointsGridLines, row++, 0, 1, 4);
267   connect (m_btnFunctionsPointsGridLines, SIGNAL (released()), this, SLOT (slotFunctionsPointsGridLines()));
268 
269   m_btnFunctionsPointsRaw = new QRadioButton (tr ("Raw Xs and Ys"));
270   m_btnFunctionsPointsRaw->setWhatsThis (tr ("Exported file will have only original X and Y values"));
271   layoutPointsSelections->addWidget (m_btnFunctionsPointsRaw, row++, 0, 1, 4);
272   connect (m_btnFunctionsPointsRaw, SIGNAL (released()), this, SLOT (slotFunctionsPointsRaw()));
273 }
274 
createHeader(QHBoxLayout * layoutMisc)275 void DlgSettingsExportFormat::createHeader (QHBoxLayout *layoutMisc)
276 {
277   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createHeader";
278 
279   const int COLUMN_RADIO_BUTTONS = 0, COLUMN_EMPTY = 1, COLUMN_LABEL = 2;
280 
281   QGroupBox *groupHeader = new QGroupBox (tr ("Header"));
282   layoutMisc->addWidget (groupHeader, 1);
283 
284   QGridLayout *layoutHeader = new QGridLayout;
285   layoutHeader->setColumnMinimumWidth(COLUMN_EMPTY,
286                                       MIN_HEADER_EMPTY_COLUMN_WIDTH);
287   groupHeader->setLayout (layoutHeader);
288   int row = 0;
289 
290   m_btnHeaderNone = new QRadioButton (exportHeaderToString (EXPORT_HEADER_NONE));
291   m_btnHeaderNone->setWhatsThis (tr ("Exported file will have no header line"));
292   layoutHeader->addWidget (m_btnHeaderNone, row++, COLUMN_RADIO_BUTTONS, 1, 1);
293   connect (m_btnHeaderNone, SIGNAL (released ()), this, SLOT (slotHeaderNone()));
294 
295   m_btnHeaderSimple = new QRadioButton (exportHeaderToString (EXPORT_HEADER_SIMPLE));
296   m_btnHeaderSimple->setWhatsThis (tr ("Exported file will have simple header line"));
297   layoutHeader->addWidget (m_btnHeaderSimple, row++, COLUMN_RADIO_BUTTONS, 1, 1);
298   connect (m_btnHeaderSimple, SIGNAL (released ()), this, SLOT (slotHeaderSimple()));
299 
300   m_btnHeaderGnuplot = new QRadioButton (exportHeaderToString (EXPORT_HEADER_GNUPLOT));
301   m_btnHeaderGnuplot->setWhatsThis (tr ("Exported file will have gnuplot header line"));
302   layoutHeader->addWidget (m_btnHeaderGnuplot, row++, COLUMN_RADIO_BUTTONS, 1, 1);
303   connect (m_btnHeaderGnuplot, SIGNAL (released()), this, SLOT (slotHeaderGnuplot()));
304 
305   createXLabel (layoutHeader,
306                 COLUMN_LABEL);
307 }
308 
createOptionalSaveDefault(QHBoxLayout * layout)309 void DlgSettingsExportFormat::createOptionalSaveDefault (QHBoxLayout *layout)
310 {
311   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createOptionalSaveDefault";
312 
313   m_btnSaveDefault = new QPushButton (tr ("Save As Default"));
314   m_btnSaveDefault->setWhatsThis (tr ("Save the settings for use as future defaults."));
315   connect (m_btnSaveDefault, SIGNAL (released ()), this, SLOT (slotSaveDefault ()));
316   layout->addWidget (m_btnSaveDefault, 0, Qt::AlignLeft);
317 
318   m_btnLoadDefault = new QPushButton (tr ("Load Default"));
319   m_btnLoadDefault->setWhatsThis (tr ("Load the default settings."));
320   connect (m_btnLoadDefault, SIGNAL (released ()), this, SLOT (slotLoadDefault ()));
321   layout->addWidget (m_btnLoadDefault, 0, Qt::AlignLeft);
322 }
323 
createPreview(QGridLayout * layout,int & row)324 void DlgSettingsExportFormat::createPreview(QGridLayout *layout, int &row)
325 {
326   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createPreview";
327 
328   // Be sure to let user know that future (=unpredictable) selection of CSV or TSV file extension
329   // during export may change the the format, by allowing them to specify a file extension here
330   m_cmbFileExtension = new QComboBox;
331   m_cmbFileExtension->setWhatsThis (tr ("File extension used for preview. The CSV and TSV file extensions "
332                                         "normally use commas and tabs respectively, but that can be changed "
333                                         "in this dialog."));
334   m_cmbFileExtension->addItem(exportFileExtensionToPreviewString (EXPORT_FILE_EXTENSION_CSV),
335                               QVariant (EXPORT_FILE_EXTENSION_CSV));
336   m_cmbFileExtension->addItem(exportFileExtensionToPreviewString (EXPORT_FILE_EXTENSION_TSV),
337                               QVariant (EXPORT_FILE_EXTENSION_TSV));
338   m_cmbFileExtension->addItem(exportFileExtensionToPreviewString (EXPORT_FILE_EXTENSION_NOT_CSV_TSV),
339                               QVariant (EXPORT_FILE_EXTENSION_NOT_CSV_TSV));
340   connect (m_cmbFileExtension, SIGNAL (activated (const QString &)),
341            this, SLOT (slotFileExtension (const QString &))); // activated() ignores code changes
342   layout->addWidget (m_cmbFileExtension, row, 0, 1, 1, Qt::AlignLeft);
343 
344   // Legend. Padding and margin in rich text do not work so &nbsp; is used for spacing
345   QLabel *labelLegend = new QLabel;
346   labelLegend->setTextFormat (Qt::RichText);
347   QString legendHtml = QString ("<span style=\"background-color: %1\">&nbsp;Functions&nbsp;</span>"
348                                 "&nbsp;&nbsp;&nbsp;"
349                                 "<span style=\"background-color: %2\">&nbsp;Relations&nbsp;</span>")
350       .arg (COLOR_FUNCTIONS)
351       .arg (COLOR_RELATIONS);
352   labelLegend->setText (legendHtml);
353   layout->addWidget (labelLegend, row++, 2, 1, 1, Qt::AlignRight);
354 
355   m_editPreview = new QTextEdit;
356   m_editPreview->setReadOnly (true);
357   m_editPreview->setWhatsThis (tr ("Preview window shows how current settings affect the exported file.\n\n"
358                                    "Functions (shown here in blue) are output first, followed by relations "
359                                    "(shown here in green) if any exist."));
360   m_editPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
361   m_editPreview->document()->setDefaultStyleSheet("div { padding-left: 20px; }");
362   QPalette p = m_editPreview->palette();
363   p.setColor (QPalette::Base, QColor (240, 240, 240)); // Replace attention-getting white border by gray
364   m_editPreview->setPalette (p);
365 
366   layout->addWidget (m_editPreview, row++, 0, 1, 3);
367 }
368 
createRelationsPointsSelection(QHBoxLayout * layoutRelations)369 void DlgSettingsExportFormat::createRelationsPointsSelection (QHBoxLayout *layoutRelations)
370 {
371   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createRelationsPointsSelection";
372 
373   QGroupBox *groupPointsSelection = new QGroupBox (tr ("Relation Points Selection"));
374   layoutRelations->addWidget (groupPointsSelection);
375 
376   QGridLayout *layoutPointsSelections = new QGridLayout;
377   groupPointsSelection->setLayout (layoutPointsSelections);
378 
379   layoutPointsSelections->setColumnMinimumWidth(0, MIN_INDENT_COLUMN_WIDTH);
380   layoutPointsSelections->setColumnStretch (0, 0);
381   layoutPointsSelections->setColumnStretch (1, 0);
382   layoutPointsSelections->setColumnStretch (2, 0);
383   layoutPointsSelections->setColumnStretch (3, 0);
384   layoutPointsSelections->setColumnStretch (4, 1);
385 
386   int row = 0;
387 
388   m_btnRelationsPointsEvenlySpaced = new QRadioButton (tr ("Interpolate Xs and Ys at evenly spaced intervals."));
389   m_btnRelationsPointsEvenlySpaced->setWhatsThis (tr ("Exported file will have points evenly spaced along each relation, separated by the interval "
390                                                       "selected below. If the last interval does not end at the last point, then a shorter last interval "
391                                                       "is added that ends on the last point."));
392   layoutPointsSelections->addWidget (m_btnRelationsPointsEvenlySpaced, row++, 0, 1, 4);
393   connect (m_btnRelationsPointsEvenlySpaced, SIGNAL (released()), this, SLOT (slotRelationsPointsEvenlySpaced()));
394 
395   QLabel *labelInterval = new QLabel (QString ("%1:").arg (tr ("Interval")));
396   layoutPointsSelections->addWidget (labelInterval, row, 1, 1, 1, Qt::AlignRight);
397 
398   m_editRelationsPointsEvenlySpacing = new QLineEdit;
399   m_validatorRelationsPointsEvenlySpacing = new QDoubleValidator; // Minimum value, to prevent overflow, is set later according to settings
400   m_editRelationsPointsEvenlySpacing->setValidator (m_validatorRelationsPointsEvenlySpacing);
401   m_editRelationsPointsEvenlySpacing->setMinimumWidth (MIN_EDIT_WIDTH);
402   m_editRelationsPointsEvenlySpacing->setMaximumWidth (MAX_EDIT_WIDTH);
403   m_editRelationsPointsEvenlySpacing->setWhatsThis (tr ("Interval between successive points when "
404                                                         "exporting at evenly spaced (X,Y) coordinates."));
405   layoutPointsSelections->addWidget (m_editRelationsPointsEvenlySpacing, row, 2, 1, 1, Qt::AlignLeft);
406   connect (m_editRelationsPointsEvenlySpacing, SIGNAL (textChanged(const QString &)), this, SLOT (slotRelationsPointsEvenlySpacedInterval(const QString &)));
407 
408   m_cmbRelationsPointsEvenlySpacingUnits = new QComboBox;
409   m_cmbRelationsPointsEvenlySpacingUnits->setWhatsThis (tr ("Units for spacing interval.\n\n"
410                                                             "Pixel units are preferred when the spacing is to be independent of the X and Y scales. The spacing will be "
411                                                             "consistent across the graph, even if a scale is logarithmic or the X and Y scales are different.\n\n"
412                                                             "Graph units are usually preferred when the X and Y scales are identical."));
413   m_cmbRelationsPointsEvenlySpacingUnits->addItem(exportPointsIntervalUnitsToString (EXPORT_POINTS_INTERVAL_UNITS_GRAPH),
414                                                                                      QVariant (EXPORT_POINTS_INTERVAL_UNITS_GRAPH));
415   m_cmbRelationsPointsEvenlySpacingUnits->addItem(exportPointsIntervalUnitsToString (EXPORT_POINTS_INTERVAL_UNITS_SCREEN),
416                                                                                      QVariant (EXPORT_POINTS_INTERVAL_UNITS_SCREEN));
417   connect (m_cmbRelationsPointsEvenlySpacingUnits, SIGNAL (activated (const QString &)),
418            this, SLOT (slotRelationsPointsEvenlySpacedIntervalUnits (const QString &))); // activated() ignores code changes
419   layoutPointsSelections->addWidget (m_cmbRelationsPointsEvenlySpacingUnits, row, 3, 1, 1, Qt::AlignLeft);
420 
421   m_lblOverflowRelations = new QLabel (tr ("Too many points"));
422   m_lblOverflowRelations->setStyleSheet ("QLabel { color : red; }");
423   m_lblOverflowRelations->setWhatsThis (tr ("Warning that interval is too small. Adjust interval or increase point limit in Main Window settings"));
424   layoutPointsSelections->addWidget (m_lblOverflowRelations, row++, 4, 1, 1, Qt::AlignLeft);
425 
426   m_btnRelationsPointsRaw = new QRadioButton (tr ("Raw Xs and Ys"));
427   m_btnRelationsPointsRaw->setWhatsThis (tr ("Exported file will have only original X and Y values"));
428   layoutPointsSelections->addWidget (m_btnRelationsPointsRaw, row++, 0, 1, 4);
429   connect (m_btnRelationsPointsRaw, SIGNAL (released()), this, SLOT (slotRelationsPointsRaw()));
430 }
431 
createSubPanel()432 QWidget *DlgSettingsExportFormat::createSubPanel ()
433 {
434   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createSubPanel";
435 
436   QWidget *subPanel = new QWidget ();
437   QGridLayout *layout = new QGridLayout (subPanel);
438   subPanel->setLayout (layout);
439 
440   int row = 0;
441   createCurveSelection (layout, row);
442 
443   createTabWidget (layout,
444                    row);
445 
446   QWidget *widgetMisc = new QWidget;
447   layout->addWidget (widgetMisc, row++, 0, 1, 3);
448   QHBoxLayout *layoutMisc = new QHBoxLayout;
449   widgetMisc->setLayout (layoutMisc);
450 
451   createDelimiters (layoutMisc); // One row of radio buttons
452   createHeader (layoutMisc); // Two rows with radio buttons and then header label
453   createFileLayout (layoutMisc); // One row of radio buttons
454 
455   createPreview (layout, row);
456 
457   return subPanel;
458 }
459 
createTabWidget(QGridLayout * layout,int & row)460 void DlgSettingsExportFormat::createTabWidget (QGridLayout *layout,
461                                                int &row)
462 {
463   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createTabWidget";
464 
465   m_tabWidget = new QTabWidget;
466   // This gets connected below, after the tabs have been added
467   layout->addWidget (m_tabWidget, row++, 0, 1, 3);
468 
469   QWidget *widgetFunctions = new QWidget;
470   int indexFunctions = m_tabWidget->addTab (widgetFunctions, tr ("Functions"));
471   QWidget *tabFunctions = m_tabWidget->widget (indexFunctions);
472   tabFunctions->setWhatsThis (tr ("Functions Tab\n\n"
473                                   "Controls for specifying the format of functions during export"));
474   QHBoxLayout *layoutFunctions = new QHBoxLayout;
475   widgetFunctions->setLayout (layoutFunctions);
476 
477   QWidget *widgetRelations = new QWidget;
478   int indexRelations = m_tabWidget->addTab (widgetRelations, tr ("Relations"));
479   QWidget *tabRelations = m_tabWidget->widget (indexRelations);
480   tabRelations->setWhatsThis (tr ("Relations Tab\n\n"
481                                   "Controls for specifying the format of relations during export"));
482   QHBoxLayout *layoutRelations = new QHBoxLayout;
483   widgetRelations->setLayout (layoutRelations);
484 
485   // Now that the tabs have been added we can connect this signal
486   connect (m_tabWidget, SIGNAL (currentChanged (int)), this, SLOT (slotTabChanged (int)));
487 
488   createFunctionsPointsSelection (layoutFunctions);
489   createRelationsPointsSelection (layoutRelations);
490 }
491 
createXLabel(QGridLayout * layoutHeader,int colLabel)492 void DlgSettingsExportFormat::createXLabel (QGridLayout *layoutHeader,
493                                             int colLabel)
494 {
495   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::createXLabel";
496 
497   int row = 1; // Skip first row
498 
499   QLabel *title = new QLabel (QString ("%1:").arg (tr ("X Label")));
500   layoutHeader->addWidget (title, row++, colLabel, 1, 1);
501 
502   m_editXLabel = new QLineEdit;
503   m_editXLabel->setWhatsThis (tr ("Label in the header for x values"));
504   layoutHeader->addWidget (m_editXLabel, row++, colLabel, 1, 1);
505   connect (m_editXLabel, SIGNAL (textChanged (const QString &)), this, SLOT (slotXLabel(const QString &)));
506 }
507 
exportedTextToExportedHtml(const QString & text,const QString & color) const508 QString DlgSettingsExportFormat::exportedTextToExportedHtml (const QString &text,
509                                                              const QString &color) const
510 {
511   QRegExp re ("<br>$");
512 
513   QString textCopy (text);
514   QString replaced = textCopy
515       .replace ("\n", "<br>")
516       .replace (" ", "&nbsp;")
517       .replace (re, "")
518       .replace ("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
519 
520   QString html = QString ("<div style=\"display: inline; background-color: %1\">%2</div>")
521     .arg (color)
522     .arg (replaced);
523 
524   return html;
525 }
526 
goodIntervalFunctions() const527 bool DlgSettingsExportFormat::goodIntervalFunctions() const
528 {
529   // LOG4CPP_INFO_S is below
530 
531   QString textFunctions = m_editFunctionsPointsEvenlySpacing->text();
532   int posFunctions;
533 
534   bool isGood = (m_validatorFunctionsPointsEvenlySpacing->validate (textFunctions, posFunctions) == QValidator::Acceptable);
535 
536   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::goodIntervalFunctions"
537                               << " text=" << textFunctions.toLatin1().data()
538                               << " good=" << (isGood ? "true" : "false")
539                               << " bottom=" << m_validatorFunctionsPointsEvenlySpacing->bottom()
540                               << " top=" << m_validatorFunctionsPointsEvenlySpacing->top();
541 
542   return isGood;
543 }
544 
goodIntervalRelations() const545 bool DlgSettingsExportFormat::goodIntervalRelations() const
546 {
547   // LOG4CPP_INFO_S is below
548 
549   QString textRelations = m_editRelationsPointsEvenlySpacing->text();
550   int posRelations;
551 
552   bool isGood = (m_validatorRelationsPointsEvenlySpacing->validate (textRelations, posRelations) == QValidator::Acceptable);
553 
554   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::goodIntervalRelations"
555                               << " text=" << textRelations.toLatin1().data()
556                               << " good=" << (isGood ? "true" : "false")
557                               << " bottom=" << m_validatorRelationsPointsEvenlySpacing->bottom()
558                               << " top=" << m_validatorRelationsPointsEvenlySpacing->top();
559 
560   return isGood;
561 }
562 
handleOk()563 void DlgSettingsExportFormat::handleOk ()
564 {
565   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::handleOk";
566 
567   CmdSettingsExportFormat *cmd = new CmdSettingsExportFormat (mainWindow (),
568                                                   cmdMediator ().document(),
569                                                   *m_modelExportBefore,
570                                                   *m_modelExportAfter);
571   cmdMediator ().push (cmd);
572 
573   hide ();
574 }
575 
initializeIntervalConstraints()576 void DlgSettingsExportFormat::initializeIntervalConstraints ()
577 {
578   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::initializeIntervalConstraints";
579 
580   const int maxPointsAcrossRange = mainWindow().modelMainWindow().maximumExportedPointsPerCurve ();
581 
582   // Get min and max of graph and screen coordinates
583   CallbackBoundingRects ftor (cmdMediator().document().documentAxesPointsRequired(),
584                               mainWindow().transformation());
585 
586   Functor2wRet<const QString &, const Point &, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
587                                                                                                      &CallbackBoundingRects::callback);
588   cmdMediator().iterateThroughCurvesPointsGraphs (ftorWithCallback);
589 
590   // If there are no points, then interval will be zero. That special case must be handled downstream to prevent infinite loops
591   bool isEmpty;
592   QPointF boundingRectGraphMin = ftor.boundingRectGraphMin (isEmpty);
593   QPointF boundingRectGraphMax = ftor.boundingRectGraphMax (isEmpty);
594   double maxSizeGraph = boundingRectGraphMax.x() - boundingRectGraphMin.x();
595   double maxSizeScreen = ftor.boundingRectScreen(isEmpty).width();
596   m_minIntervalGraph = maxSizeGraph / maxPointsAcrossRange; // Should be unaffected by y range
597   m_minIntervalScreen = maxSizeScreen / maxPointsAcrossRange; // Should be unaffected by y range
598 }
599 
load(CmdMediator & cmdMediator)600 void DlgSettingsExportFormat::load (CmdMediator &cmdMediator)
601 {
602   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::load";
603 
604   setCmdMediator (cmdMediator);
605 
606   // Flush old data
607   delete m_modelExportBefore;
608   delete m_modelExportAfter;
609 
610   // Save new data
611   m_modelExportBefore = new DocumentModelExportFormat (cmdMediator.document());
612   m_modelExportAfter = new DocumentModelExportFormat (cmdMediator.document());
613 
614   // Populate controls. First load excluded curves
615   m_listExcluded->clear();
616   QStringList curveNamesExcluded = m_modelExportAfter->curveNamesNotExported();
617   QStringList::const_iterator itr;
618   for (itr = curveNamesExcluded.begin (); itr != curveNamesExcluded.end(); ++itr) {
619     QString curveNameNotExported = *itr;
620     m_listExcluded->addItem (curveNameNotExported);
621   }
622 
623   // Include curves that are not excluded
624   m_listIncluded->clear();
625   QStringList curveNamesAll = cmdMediator.document().curvesGraphsNames();
626   for (itr = curveNamesAll.begin (); itr != curveNamesAll.end(); itr++) {
627     QString curveName = *itr;
628     if (!curveNamesExcluded.contains (curveName)) {
629       m_listIncluded->addItem (curveName);
630     }
631   }
632 
633   ExportPointsSelectionFunctions pointsSelectionFunctions = m_modelExportAfter->pointsSelectionFunctions();
634   m_btnFunctionsPointsAllCurves->setChecked (pointsSelectionFunctions == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_ALL_CURVES);
635   m_btnFunctionsPointsFirstCurve->setChecked (pointsSelectionFunctions == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_FIRST_CURVE);
636   m_btnFunctionsPointsEvenlySpaced->setChecked (pointsSelectionFunctions == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_PERIODIC);
637   m_btnFunctionsPointsGridLines->setChecked (pointsSelectionFunctions == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_GRID_LINES);
638   m_btnFunctionsPointsRaw->setChecked (pointsSelectionFunctions == EXPORT_POINTS_SELECTION_FUNCTIONS_RAW);
639 
640   ExportLayoutFunctions layoutFunctions = m_modelExportAfter->layoutFunctions ();
641   m_btnCurvesLayoutAllCurves->setChecked (layoutFunctions == EXPORT_LAYOUT_ALL_PER_LINE);
642   m_btnCurvesLayoutOneCurve->setChecked (layoutFunctions == EXPORT_LAYOUT_ONE_PER_LINE);
643 
644   ExportPointsSelectionRelations pointsSelectionRelations = m_modelExportAfter->pointsSelectionRelations();
645   m_btnRelationsPointsEvenlySpaced->setChecked (pointsSelectionRelations == EXPORT_POINTS_SELECTION_RELATIONS_INTERPOLATE);
646   m_btnRelationsPointsRaw->setChecked (pointsSelectionRelations == EXPORT_POINTS_SELECTION_RELATIONS_RAW);
647 
648   ExportDelimiter delimiter = m_modelExportAfter->delimiter ();
649   m_btnDelimitersCommas->setChecked (delimiter == EXPORT_DELIMITER_COMMA);
650   m_btnDelimitersSpaces->setChecked (delimiter == EXPORT_DELIMITER_SPACE);
651   m_btnDelimitersTabs->setChecked (delimiter == EXPORT_DELIMITER_TAB);
652   m_btnDelimitersSemicolons->setChecked (delimiter == EXPORT_DELIMITER_SEMICOLON);
653 
654   m_chkExtrapolateOutsideEndpoints->setChecked (m_modelExportAfter->extrapolateOutsideEndpoints ());
655 
656   m_chkOverrideCsvTsv->setChecked (m_modelExportAfter->overrideCsvTsv());
657 
658   ExportHeader header = m_modelExportAfter->header ();
659   m_btnHeaderNone->setChecked (header == EXPORT_HEADER_NONE);
660   m_btnHeaderSimple->setChecked (header == EXPORT_HEADER_SIMPLE);
661   m_btnHeaderGnuplot->setChecked (header == EXPORT_HEADER_GNUPLOT);
662 
663   m_editXLabel->setText (m_modelExportAfter->xLabel());
664 
665   m_editFunctionsPointsEvenlySpacing->setText (QString::number (m_modelExportAfter->pointsIntervalFunctions()));
666   m_editRelationsPointsEvenlySpacing->setText (QString::number (m_modelExportAfter->pointsIntervalRelations()));
667 
668   ExportPointsIntervalUnits pointsIntervalUnitsFunctions = m_modelExportAfter->pointsIntervalUnitsFunctions();
669   ExportPointsIntervalUnits pointsIntervalUnitsRelations = m_modelExportAfter->pointsIntervalUnitsRelations();
670   int indexFunctions = m_cmbFunctionsPointsEvenlySpacingUnits->findData (QVariant (pointsIntervalUnitsFunctions));
671   int indexRelations = m_cmbRelationsPointsEvenlySpacingUnits->findData (QVariant (pointsIntervalUnitsRelations));
672   m_cmbFunctionsPointsEvenlySpacingUnits->setCurrentIndex (indexFunctions);
673   m_cmbRelationsPointsEvenlySpacingUnits->setCurrentIndex (indexRelations);
674 
675   m_cmbFileExtension->setCurrentText (exportFileExtensionToPreviewString (EXPORT_FILE_EXTENSION_CSV));
676 
677   initializeIntervalConstraints ();
678 
679   updateControlsUponLoad (); // Before updateControls so m_haveFunction and m_haveRelation are set
680   updateControls();
681   updateIntervalConstraints();
682   enableOk (false); // Disable Ok button since there not yet any changes
683   updatePreview();
684 }
685 
setSmallDialogs(bool smallDialogs)686 void DlgSettingsExportFormat::setSmallDialogs(bool smallDialogs)
687 {
688   if (!smallDialogs) {
689     setMinimumHeight (MINIMUM_HEIGHT);
690   }
691 }
692 
slotDelimitersCommas()693 void DlgSettingsExportFormat::slotDelimitersCommas()
694 {
695   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotDelimitersCommas";
696 
697   m_modelExportAfter->setDelimiter(EXPORT_DELIMITER_COMMA);
698   updateControls();
699   updatePreview();
700 }
701 
slotDelimitersSemicolons()702 void DlgSettingsExportFormat::slotDelimitersSemicolons()
703 {
704   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotDelimitersSemicolons";
705 
706   m_modelExportAfter->setDelimiter(EXPORT_DELIMITER_SEMICOLON);
707   updateControls();
708   updatePreview();
709 }
710 
slotDelimitersSpaces()711 void DlgSettingsExportFormat::slotDelimitersSpaces()
712 {
713   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotDelimitersSpaces";
714 
715   m_modelExportAfter->setDelimiter(EXPORT_DELIMITER_SPACE);
716   updateControls();
717   updatePreview();
718 }
719 
slotDelimitersTabs()720 void DlgSettingsExportFormat::slotDelimitersTabs()
721 {
722   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotDelimitersTabs";
723 
724   m_modelExportAfter->setDelimiter(EXPORT_DELIMITER_TAB);
725   updateControls();
726   updatePreview();
727 }
728 
slotExclude()729 void DlgSettingsExportFormat::slotExclude ()
730 {
731   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotExclude";
732 
733   // Perform forward pass to get excluded curves in the proper order
734   int i;
735   QStringList excluded;
736   for (i = 0; i < m_listIncluded->count(); i++) {
737     if (m_listIncluded->item(i)->isSelected()) {
738       excluded += m_listIncluded->item(i)->text();
739     }
740   }
741 
742   // Add the excluded curves to the excluded list
743   for (i = 0; i < excluded.count(); i++) {
744     QString curveName = excluded.at (i);
745     m_listExcluded->addItem (curveName);
746   }
747 
748   // Perform backwards pass to remove the excluded curves from the included list
749   for (i = m_listIncluded->count() - 1; i>= 0; i--) {
750     QString curveName = m_listIncluded->item(i)->text();
751     if (excluded.contains (curveName)) {
752       QListWidgetItem *item = m_listIncluded->item (i);
753       m_listIncluded->removeItemWidget (item);
754       delete item;
755     }
756   }
757 
758   m_modelExportAfter->setCurveNamesNotExported(excluded);
759   updateControls();
760   updatePreview();
761 }
762 
slotFileExtension(const QString &)763 void DlgSettingsExportFormat::slotFileExtension (const QString &)
764 {
765   updatePreview();
766 }
767 
slotFunctionsExtrapolateOutsideEndpoints(int)768 void DlgSettingsExportFormat::slotFunctionsExtrapolateOutsideEndpoints(int)
769 {
770   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsExtrapolateOutsideEndpoints";
771 
772   m_modelExportAfter->setExtrapolateOutsideEndpoints (m_chkExtrapolateOutsideEndpoints->isChecked());
773   updateControls();
774   updatePreview();
775 }
776 
slotFunctionsLayoutAllCurves()777 void DlgSettingsExportFormat::slotFunctionsLayoutAllCurves()
778 {
779   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsLayoutAllCurves";
780 
781   m_modelExportAfter->setLayoutFunctions(EXPORT_LAYOUT_ALL_PER_LINE);
782   updateControls();
783   updatePreview();
784 }
785 
slotFunctionsLayoutOneCurve()786 void DlgSettingsExportFormat::slotFunctionsLayoutOneCurve()
787 {
788   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsLayoutOneCurve";
789 
790   m_modelExportAfter->setLayoutFunctions(EXPORT_LAYOUT_ONE_PER_LINE);
791   updateControls();
792   updatePreview();
793 }
794 
slotFunctionsPointsAllCurves()795 void DlgSettingsExportFormat::slotFunctionsPointsAllCurves()
796 {
797   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsPointsAllCurves";
798 
799   m_modelExportAfter->setPointsSelectionFunctions(EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_ALL_CURVES);
800   updateControls();
801   updatePreview();
802 }
803 
slotFunctionsPointsEvenlySpaced()804 void DlgSettingsExportFormat::slotFunctionsPointsEvenlySpaced()
805 {
806   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsPointsEvenlySpaced";
807 
808   m_modelExportAfter->setPointsSelectionFunctions(EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_PERIODIC);
809   updateControls();
810   updatePreview();
811 }
812 
slotFunctionsPointsEvenlySpacedInterval(const QString &)813 void DlgSettingsExportFormat::slotFunctionsPointsEvenlySpacedInterval(const QString &)
814 {
815   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsPointsEvenlySpacedInterval";
816 
817   if (m_editFunctionsPointsEvenlySpacing->text().trimmed() == "") {
818     // Undefined value which is (1) not a problem and (2) an intermediate state
819     m_lblOverflowFunctions->hide ();
820     m_editPreview->setText(EMPTY_PREVIEW);
821   } else {
822     // Prevent infinite loop on empty and "-" values which get treated as zero interval
823     if (goodIntervalFunctions()) {
824       m_lblOverflowFunctions->hide (); // State transition
825       m_modelExportAfter->setPointsIntervalFunctions(m_editFunctionsPointsEvenlySpacing->text().toDouble());
826       updateControls();
827       updatePreview();
828     } else {
829       m_lblOverflowFunctions->show (); // State transition
830       m_editPreview->setText(EMPTY_PREVIEW);
831     }
832   }
833 }
834 
slotFunctionsPointsEvenlySpacedIntervalUnits(const QString &)835 void DlgSettingsExportFormat::slotFunctionsPointsEvenlySpacedIntervalUnits(const QString &)
836 {
837   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsPointsEvenlySpacedIntervalUnits";
838 
839   int index = m_cmbFunctionsPointsEvenlySpacingUnits->currentIndex();
840   ExportPointsIntervalUnits units = static_cast<ExportPointsIntervalUnits> (m_cmbFunctionsPointsEvenlySpacingUnits->itemData (index).toInt());
841 
842   // Prevent infinite loop on certain values
843   if (goodIntervalFunctions()) {
844     m_lblOverflowFunctions->hide (); // State transition
845     m_modelExportAfter->setPointsIntervalUnitsFunctions(units);
846     updateIntervalConstraints(); // Call this before updateControls so constraint checking is updated for ok button
847     updateControls();
848     updatePreview();
849   } else {
850     m_lblOverflowFunctions->show (); // State transition
851     m_editPreview->setText(EMPTY_PREVIEW);
852   }
853 }
854 
slotFunctionsPointsFirstCurve()855 void DlgSettingsExportFormat::slotFunctionsPointsFirstCurve()
856 {
857   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsPointsFirstCurve";
858 
859   m_modelExportAfter->setPointsSelectionFunctions(EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_FIRST_CURVE);
860   updateControls();
861   updatePreview();
862 }
863 
slotFunctionsPointsGridLines()864 void DlgSettingsExportFormat::slotFunctionsPointsGridLines()
865 {
866     LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsPointsGridLines";
867 
868     m_modelExportAfter->setPointsSelectionFunctions(EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_GRID_LINES);
869     updateControls();
870     updatePreview();
871 }
872 
slotFunctionsPointsRaw()873 void DlgSettingsExportFormat::slotFunctionsPointsRaw()
874 {
875   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotFunctionsPointsRaw";
876 
877   m_modelExportAfter->setPointsSelectionFunctions(EXPORT_POINTS_SELECTION_FUNCTIONS_RAW);
878   updateControls();
879   updatePreview();
880 }
881 
slotHeaderGnuplot()882 void DlgSettingsExportFormat::slotHeaderGnuplot()
883 {
884   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotHeaderGnuplot";
885 
886   m_modelExportAfter->setHeader(EXPORT_HEADER_GNUPLOT);
887   updateControls();
888   updatePreview();
889 }
890 
slotHeaderNone()891 void DlgSettingsExportFormat::slotHeaderNone()
892 {
893   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotHeaderNone";
894 
895   m_modelExportAfter->setHeader(EXPORT_HEADER_NONE);
896   updateControls();
897   updatePreview();
898 }
899 
slotHeaderSimple()900 void DlgSettingsExportFormat::slotHeaderSimple()
901 {
902   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotHeaderSimple";
903 
904   m_modelExportAfter->setHeader(EXPORT_HEADER_SIMPLE);
905   updateControls();
906   updatePreview();
907 }
908 
slotInclude()909 void DlgSettingsExportFormat::slotInclude ()
910 {
911   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotInclude";
912 
913   // Perform forward pass to get included curves in the proper order
914   int i;
915   QStringList included;
916   for (i = 0; i < m_listExcluded->count(); i++) {
917     if (m_listExcluded->item(i)->isSelected()) {
918       included += m_listExcluded->item(i)->text();
919     }
920   }
921 
922   // Add the included curves to the included list
923   for (i = 0; i < included.count(); i++) {
924     QString curveName = included.at (i);
925     m_listIncluded->addItem (curveName);
926   }
927 
928   // Perform backwards pass to remove the included curves from the excluded list
929   QStringList excluded;
930   for (i = m_listExcluded->count() - 1; i>= 0; i--) {
931     QString curveName = m_listExcluded->item(i)->text();
932     QListWidgetItem *item = m_listExcluded->item (i);
933     if (included.contains (curveName)) {
934       m_listExcluded->removeItemWidget (item);
935       delete item;
936     } else {
937       excluded += item->text();
938     }
939   }
940 
941   m_modelExportAfter->setCurveNamesNotExported(excluded);
942   updateControls();
943   updatePreview();
944 }
945 
slotListExcluded()946 void DlgSettingsExportFormat::slotListExcluded()
947 {
948   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotListExcluded";
949 
950   updateControls();
951   // Do not call updatePreview since this method changes nothing
952 }
953 
slotListIncluded()954 void DlgSettingsExportFormat::slotListIncluded()
955 {
956   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotListIncluded";
957 
958   updateControls();
959   // Do not call updatePreview since this method changes nothing
960 }
961 
slotLoadDefault()962 void DlgSettingsExportFormat::slotLoadDefault()
963 {
964   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotLoadDefault";
965 
966   // Get defaults from constructor
967   DocumentModelExportFormat modelExportDefaults;
968 
969   // Apply defaults to controls. That will trigger updates to m_modelExportAfter
970 
971   m_btnHeaderGnuplot->setChecked (modelExportDefaults.header() == EXPORT_HEADER_GNUPLOT);
972   m_btnHeaderNone->setChecked (modelExportDefaults.header() == EXPORT_HEADER_NONE);
973   m_btnHeaderSimple->setChecked (modelExportDefaults.header() == EXPORT_HEADER_SIMPLE);
974 
975   m_editXLabel->setText (modelExportDefaults.xLabel());
976 
977   m_btnDelimitersCommas->setChecked (modelExportDefaults.delimiter() == EXPORT_DELIMITER_COMMA);
978   m_btnDelimitersSemicolons->setChecked (modelExportDefaults.delimiter() == EXPORT_DELIMITER_SEMICOLON);
979   m_btnDelimitersSpaces->setChecked (modelExportDefaults.delimiter() == EXPORT_DELIMITER_SPACE);
980   m_btnDelimitersTabs->setChecked (modelExportDefaults.delimiter() == EXPORT_DELIMITER_TAB);
981 
982   m_chkOverrideCsvTsv->setChecked (modelExportDefaults.overrideCsvTsv());
983 
984   m_btnCurvesLayoutAllCurves->setChecked (modelExportDefaults.layoutFunctions() == EXPORT_LAYOUT_ALL_PER_LINE);
985   m_btnCurvesLayoutOneCurve->setChecked (modelExportDefaults.layoutFunctions() == EXPORT_LAYOUT_ONE_PER_LINE);
986 
987   m_editFunctionsPointsEvenlySpacing->setText (QString::number (modelExportDefaults.pointsIntervalFunctions ()));
988   m_editRelationsPointsEvenlySpacing->setText (QString::number (modelExportDefaults.pointsIntervalRelations ()));
989 
990   m_btnFunctionsPointsAllCurves->setChecked (modelExportDefaults.pointsSelectionFunctions() == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_ALL_CURVES);
991   m_btnFunctionsPointsFirstCurve->setChecked (modelExportDefaults.pointsSelectionFunctions() == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_FIRST_CURVE);
992   m_btnFunctionsPointsEvenlySpaced->setChecked (modelExportDefaults.pointsSelectionFunctions() == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_PERIODIC);
993   m_btnFunctionsPointsGridLines->setChecked (modelExportDefaults.pointsSelectionFunctions() == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_GRID_LINES);
994   m_btnFunctionsPointsRaw->setChecked (modelExportDefaults.pointsSelectionFunctions() == EXPORT_POINTS_SELECTION_FUNCTIONS_RAW);
995 
996   m_btnRelationsPointsEvenlySpaced->setChecked (modelExportDefaults.pointsSelectionRelations() == EXPORT_POINTS_SELECTION_RELATIONS_INTERPOLATE);
997   m_btnRelationsPointsRaw->setChecked (modelExportDefaults.pointsSelectionRelations() == EXPORT_POINTS_SELECTION_RELATIONS_RAW);
998 
999   m_chkExtrapolateOutsideEndpoints->setChecked (modelExportDefaults.extrapolateOutsideEndpoints());
1000 
1001   int indexFunctions = m_cmbFunctionsPointsEvenlySpacingUnits->findData (QVariant (modelExportDefaults.pointsIntervalUnitsFunctions ()));
1002   int indexRelations = m_cmbRelationsPointsEvenlySpacingUnits->findData (QVariant (modelExportDefaults.pointsIntervalUnitsRelations ()));
1003   m_cmbFunctionsPointsEvenlySpacingUnits->setCurrentIndex (indexFunctions);
1004   m_cmbRelationsPointsEvenlySpacingUnits->setCurrentIndex (indexRelations);
1005 
1006   // Apply defaults to 'after' settings
1007   *m_modelExportAfter = modelExportDefaults;
1008 
1009   updateControls();
1010   updatePreview();
1011 }
1012 
slotOverrideCsvTsv(int)1013 void DlgSettingsExportFormat::slotOverrideCsvTsv(int)
1014 {
1015   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotOverrideCsvTsv";
1016 
1017   m_modelExportAfter->setOverrideCsvTsv(m_chkOverrideCsvTsv->isChecked());
1018   updateControls();
1019   updatePreview();
1020 }
1021 
slotRelationsPointsEvenlySpaced()1022 void DlgSettingsExportFormat::slotRelationsPointsEvenlySpaced()
1023 {
1024   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotRelationsPointsEvenlySpaced";
1025 
1026   m_modelExportAfter->setPointsSelectionRelations(EXPORT_POINTS_SELECTION_RELATIONS_INTERPOLATE);
1027   updateControls();
1028   updatePreview();
1029 }
1030 
slotRelationsPointsEvenlySpacedInterval(const QString &)1031 void DlgSettingsExportFormat::slotRelationsPointsEvenlySpacedInterval(const QString &)
1032 {
1033   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotRelationsPointsEvenlySpacedInterval";
1034 
1035   if (m_editRelationsPointsEvenlySpacing->text().trimmed() == "") {
1036     // Undefined value which is (1) not a problem and (2) an intermediate state
1037     m_lblOverflowRelations->hide ();
1038     m_editPreview->setText(EMPTY_PREVIEW);
1039   } else {
1040     if (goodIntervalRelations()) {
1041       m_lblOverflowRelations->hide (); // State transition
1042       m_modelExportAfter->setPointsIntervalRelations(m_editRelationsPointsEvenlySpacing->text().toDouble());
1043       updateControls();
1044       updatePreview();
1045     } else {
1046       m_lblOverflowRelations->show (); // State transition
1047       m_editPreview->setText(EMPTY_PREVIEW);
1048     }
1049   }
1050 }
1051 
slotRelationsPointsEvenlySpacedIntervalUnits(const QString &)1052 void DlgSettingsExportFormat::slotRelationsPointsEvenlySpacedIntervalUnits(const QString &)
1053 {
1054   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotRelationsPointsEvenlySpacedIntervalUnits";
1055 
1056   int index = m_cmbRelationsPointsEvenlySpacingUnits->currentIndex();
1057   ExportPointsIntervalUnits units = static_cast<ExportPointsIntervalUnits> (m_cmbRelationsPointsEvenlySpacingUnits->itemData (index).toInt());
1058 
1059   if (goodIntervalRelations()) {
1060     m_lblOverflowRelations->hide (); // State transition
1061     m_modelExportAfter->setPointsIntervalUnitsRelations(units);
1062     updateIntervalConstraints(); // Call this before updateControls so constraint checking is updated for ok button
1063     updateControls();
1064     updatePreview();
1065   } else {
1066     m_lblOverflowRelations->show (); // State transition
1067     m_editPreview->setText(EMPTY_PREVIEW);
1068   }
1069 }
1070 
slotRelationsPointsRaw()1071 void DlgSettingsExportFormat::slotRelationsPointsRaw()
1072 {
1073   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotRelationsPointsRaw";
1074 
1075   m_modelExportAfter->setPointsSelectionRelations(EXPORT_POINTS_SELECTION_RELATIONS_RAW);
1076   updateControls();
1077   updatePreview();
1078 }
1079 
slotSaveDefault()1080 void DlgSettingsExportFormat::slotSaveDefault()
1081 {
1082   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotSaveDefault";
1083 
1084   QSettings settings (SETTINGS_ENGAUGE, SETTINGS_DIGITIZER);
1085   settings.beginGroup (SETTINGS_GROUP_EXPORT);
1086 
1087   // Sync these settings with DocumentModelExportFormat::DocumentModelExportFormat()
1088   // and DlgSettingsExportFormat::slotLoadDefault()
1089   settings.setValue (SETTINGS_EXPORT_DELIMITER,
1090                      QVariant (m_modelExportAfter->delimiter()));
1091   settings.setValue (SETTINGS_EXPORT_DELIMITER_OVERRIDE_CSV_TSV,
1092                      QVariant (m_modelExportAfter->overrideCsvTsv()));
1093   settings.setValue (SETTINGS_EXPORT_EXTRAPOLATE_OUTSIDE_ENDPOINTS,
1094                      QVariant (m_modelExportAfter->extrapolateOutsideEndpoints()));
1095   settings.setValue (SETTINGS_EXPORT_HEADER,
1096                      QVariant (m_modelExportAfter->header()));
1097   settings.setValue (SETTINGS_EXPORT_LAYOUT_FUNCTIONS,
1098                      QVariant (m_modelExportAfter->layoutFunctions()));
1099   settings.setValue (SETTINGS_EXPORT_POINTS_INTERVAL_FUNCTIONS,
1100                      QVariant (m_modelExportAfter->pointsIntervalFunctions()));
1101   settings.setValue (SETTINGS_EXPORT_POINTS_INTERVAL_RELATIONS,
1102                      QVariant (m_modelExportAfter->pointsIntervalRelations()));
1103   settings.setValue (SETTINGS_EXPORT_POINTS_INTERVAL_UNITS_FUNCTIONS,
1104                      QVariant (m_modelExportAfter->pointsIntervalUnitsFunctions()));
1105   settings.setValue (SETTINGS_EXPORT_POINTS_INTERVAL_UNITS_RELATIONS,
1106                      QVariant (m_modelExportAfter->pointsIntervalUnitsRelations()));
1107   settings.setValue (SETTINGS_EXPORT_POINTS_SELECTION_FUNCTIONS,
1108                      QVariant (m_modelExportAfter->pointsSelectionFunctions()));
1109   settings.setValue (SETTINGS_EXPORT_POINTS_SELECTION_RELATIONS,
1110                      QVariant (m_modelExportAfter->pointsSelectionRelations()));
1111   settings.setValue (SETTINGS_EXPORT_X_LABEL,
1112                      QVariant (m_modelExportAfter->xLabel()));
1113 
1114   settings.endGroup ();
1115 }
1116 
slotTabChanged(int)1117 void DlgSettingsExportFormat::slotTabChanged (int)
1118 {
1119   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotTabChanged";
1120 
1121   updatePreview();
1122 }
1123 
slotXLabel(const QString &)1124 void DlgSettingsExportFormat::slotXLabel(const QString &)
1125 {
1126   LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::slotXLabel";
1127 
1128   m_modelExportAfter->setXLabel (m_editXLabel->text());
1129   updateControls();
1130   updatePreview();
1131 }
1132 
updateControls()1133 void DlgSettingsExportFormat::updateControls ()
1134 {
1135   bool isGoodState = goodIntervalFunctions() &&
1136                      goodIntervalRelations();
1137   enableOk (isGoodState);
1138 
1139   // Function extrapolation never applies when using raw points
1140   m_chkExtrapolateOutsideEndpoints->setEnabled (!m_btnFunctionsPointsRaw->isChecked ());
1141 
1142   int selectedForInclude = m_listExcluded->selectedItems().count();
1143   int selectedForExclude = m_listIncluded->selectedItems().count();
1144   int inInclude = m_listIncluded->count();
1145 
1146   m_btnInclude->setEnabled (selectedForInclude > 0); // Need at least one selection
1147   m_btnExclude->setEnabled ((selectedForExclude > 0) && (inInclude - selectedForExclude > 0)); // Need at least one selection, and one left after the move
1148 
1149   m_editFunctionsPointsEvenlySpacing->setEnabled (m_haveFunction && m_btnFunctionsPointsEvenlySpaced->isChecked ());
1150   m_editRelationsPointsEvenlySpacing->setEnabled (m_haveRelation && m_btnRelationsPointsEvenlySpaced->isChecked ());
1151 
1152   m_editXLabel->setEnabled (!m_btnHeaderNone->isChecked());
1153 }
1154 
updateControlsUponLoad()1155 void DlgSettingsExportFormat::updateControlsUponLoad ()
1156 {
1157   CurveStyles curveStyles = cmdMediator().document().modelCurveStyles();
1158 
1159   m_haveFunction = false;
1160   m_haveRelation = false;
1161 
1162   QStringList curveNames = curveStyles.curveNames();
1163 
1164   QStringList::const_iterator itr;
1165   for (itr = curveNames.begin(); itr != curveNames.end (); itr++) {
1166     QString curveName = *itr;
1167     CurveStyle curveStyle = curveStyles.curveStyle (curveName);
1168     CurveConnectAs curveConnectAs = curveStyle.lineStyle().curveConnectAs();
1169     if (curveConnectAs == CONNECT_AS_FUNCTION_SMOOTH || curveConnectAs == CONNECT_AS_FUNCTION_STRAIGHT) {
1170       m_haveFunction = true;
1171     } else if (curveConnectAs == CONNECT_AS_RELATION_SMOOTH || curveConnectAs == CONNECT_AS_RELATION_STRAIGHT) {
1172       m_haveRelation = true;
1173     }
1174   }
1175 
1176   // Enable function-specific widgets if appropriate
1177   m_btnFunctionsPointsAllCurves->setEnabled (m_haveFunction);
1178   m_btnFunctionsPointsFirstCurve->setEnabled (m_haveFunction);
1179   m_btnFunctionsPointsEvenlySpaced->setEnabled (m_haveFunction);
1180   m_editFunctionsPointsEvenlySpacing->setEnabled (m_haveFunction);
1181   m_cmbFunctionsPointsEvenlySpacingUnits->setEnabled (m_haveFunction);
1182   m_btnFunctionsPointsRaw->setEnabled (m_haveFunction);
1183 
1184   // Enable relation-specific widgets if appropriate
1185   m_btnRelationsPointsEvenlySpaced->setEnabled (m_haveRelation);
1186   m_editRelationsPointsEvenlySpacing->setEnabled (m_haveRelation);
1187   m_cmbRelationsPointsEvenlySpacingUnits->setEnabled (m_haveRelation);
1188   m_btnRelationsPointsRaw->setEnabled (m_haveRelation);
1189 
1190   // Do not start with a tab that does not apply to the current set of functions/relations
1191   if (!m_haveRelation) {
1192     m_tabWidget->setCurrentIndex (TAB_WIDGET_INDEX_FUNCTIONS);
1193   } else if (!m_haveFunction) {
1194     m_tabWidget->setCurrentIndex (TAB_WIDGET_INDEX_RELATIONS);
1195   }
1196 }
1197 
updateIntervalConstraints()1198 void DlgSettingsExportFormat::updateIntervalConstraints ()
1199 {
1200   double functionsMin = (m_modelExportAfter->pointsIntervalUnitsFunctions() == EXPORT_POINTS_INTERVAL_UNITS_GRAPH ?
1201                            m_minIntervalGraph :
1202                            m_minIntervalScreen);
1203   double relationsMin = (m_modelExportAfter->pointsIntervalUnitsRelations() == EXPORT_POINTS_INTERVAL_UNITS_GRAPH ?
1204                            m_minIntervalGraph :
1205                            m_minIntervalScreen);
1206 
1207   if (cmdMediator().document().modelCoords().coordScaleYRadius() == COORD_SCALE_LOG) {
1208     // Override scale factor with log scale so Export classes are assured that multiplying by the scale factor will
1209     // cause an increase
1210     functionsMin = qMax (1.00000001, functionsMin);
1211   }
1212 
1213   if (m_tabWidget->currentIndex() == TAB_WIDGET_INDEX_FUNCTIONS) {
1214 
1215     if (m_modelExportAfter->pointsIntervalFunctions() < functionsMin) {
1216 
1217       m_editFunctionsPointsEvenlySpacing->setText (QString::number (functionsMin));
1218 
1219     }
1220 
1221     m_validatorFunctionsPointsEvenlySpacing->setBottom (functionsMin);
1222 
1223   } else {
1224 
1225     if (m_modelExportAfter->pointsIntervalRelations() < relationsMin) {
1226 
1227       m_editRelationsPointsEvenlySpacing->setText (QString::number (relationsMin));
1228 
1229     }
1230 
1231     m_validatorRelationsPointsEvenlySpacing->setBottom (relationsMin);
1232   }
1233 }
1234 
updatePreview()1235 void DlgSettingsExportFormat::updatePreview()
1236 {
1237   // Save the scroll position for continuity before and after the preview update
1238   int scrollPosition = m_editPreview->verticalScrollBar()->value();
1239 
1240   QString exportedTextFunctions, exportedTextRelations, exportedHtml;
1241   QTextStream strFunctions (&exportedTextFunctions);
1242   QTextStream strRelations (&exportedTextRelations);
1243 
1244   if (mainWindow().transformation().transformIsDefined()) {
1245 
1246     unsigned int numWritesSoFar = 0;
1247 
1248     // Cobble together enough of a filename, given the extension, to be parsable as a filename
1249     ExportFileExtension exportFileExtension = static_cast<ExportFileExtension> (m_cmbFileExtension->currentData().toInt());
1250     QString filename = exportFileExtensionToFilename (exportFileExtension);
1251 
1252     ExportFileExtensionOverride extensionOverride;
1253     ExportToFile exportToFile;
1254     DocumentModelExportFormat modelAfterWithFileExtension = extensionOverride.modelExportOverride(*m_modelExportAfter,
1255                                                                                                   exportToFile,
1256                                                                                                   filename);
1257 
1258     ExportFileFunctions exportStrategyFunctions;
1259     exportStrategyFunctions.exportToFile (modelAfterWithFileExtension,
1260                                           cmdMediator().document(),
1261                                           mainWindow().modelMainWindow(),
1262                                           mainWindow().transformation(),
1263                                           strFunctions,
1264                                           numWritesSoFar);
1265 
1266     ExportFileRelations exportStrategyRelations;
1267     exportStrategyRelations.exportToFile (modelAfterWithFileExtension,
1268                                           cmdMediator().document(),
1269                                           mainWindow().modelMainWindow(),
1270                                           mainWindow().transformation(),
1271                                           strRelations,
1272                                           numWritesSoFar);
1273 
1274     // Use html to set background color. A <div> fills the whole background, unlike a <span>.
1275     // Final carriage return is removed to prevent unwanted blank line. A requirement is that
1276     // if there are no functions then no empty <div> appears (too confusing), and likewise if
1277     // there are no relations
1278     QString exportedHtmlFunctions, exportedHtmlRelations;
1279     if (! exportedTextFunctions.isEmpty ()) {
1280 
1281       exportedHtmlFunctions = exportedTextToExportedHtml (exportedTextFunctions, COLOR_FUNCTIONS);
1282     }
1283     if (! exportedTextRelations.isEmpty ()) {
1284 
1285       exportedHtmlRelations = exportedTextToExportedHtml (exportedTextRelations, COLOR_RELATIONS);
1286     }
1287 
1288     exportedHtml = exportedHtmlFunctions + exportedHtmlRelations;
1289 
1290   } else {
1291 
1292     exportedHtml = tr ("Preview is unavailable until axis points are defined.");
1293   }
1294 
1295   m_editPreview->setHtml (exportedHtml);
1296 
1297   // Restore scroll position
1298   m_editPreview->verticalScrollBar()->setValue (scrollPosition);
1299 }
1300