Seamly2D
Code documentation
tmainwindow.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  * @file tmainwindow.cpp
3  ** @author Douglas S Caskey
4  ** @date 13 May, 2023
5  **
6  ** @brief
7  ** @copyright
8  ** This source code is part of the Seamly2D project, a pattern making
9  ** program to create and model patterns of clothing.
10  ** Copyright (C) 2017-2023 Seamly2D project
11  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
12  **
13  ** Seamly2D is free software: you can redistribute it and/or modify
14  ** it under the terms of the GNU General Public License as published by
15  ** the Free Software Foundation, either version 3 of the License, or
16  ** (at your option) any later version.
17  **
18  ** Seamly2D is distributed in the hope that it will be useful,
19  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  ** GNU General Public License for more details.
22  **
23  ** You should have received a copy of the GNU General Public License
24  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
25  **
26  *************************************************************************/
27 
28  /************************************************************************
29  **
30  ** @file tmainwindow.cpp
31  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
32  ** @date 10 7, 2015
33  **
34  ** @brief
35  ** @copyright
36  ** This source code is part of the Valentina project, a pattern making
37  ** program, whose allow create and modeling patterns of clothing.
38  ** Copyright (C) 2015 Valentina project
39  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
40  **
41  ** Valentina is free software: you can redistribute it and/or modify
42  ** it under the terms of the GNU General Public License as published by
43  ** the Free Software Foundation, either version 3 of the License, or
44  ** (at your option) any later version.
45  **
46  ** Valentina is distributed in the hope that it will be useful,
47  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
48  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49  ** GNU General Public License for more details.
50  **
51  ** You should have received a copy of the GNU General Public License
52  ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
53  **
54  *************************************************************************/
55 
56 #include "tmainwindow.h"
57 #include "ui_tmainwindow.h"
64 #include "../vpatterndb/calculator.h"
65 #include "../vpatterndb/pmsystems.h"
66 #include "../ifc/ifcdef.h"
67 #include "../ifc/xml/vvitconverter.h"
68 #include "../ifc/xml/vvstconverter.h"
69 #include "../ifc/xml/vpatternconverter.h"
70 #include "../vmisc/vlockguard.h"
71 #include "../vmisc/vsysexits.h"
72 #include "../vmisc/qxtcsvmodel.h"
73 #include "vlitepattern.h"
74 #include "../qmuparser/qmudef.h"
75 #include "../vtools/dialogs/support/edit_formula_dialog.h"
76 #include "version.h"
77 #include "mapplication.h" // Should be last because of definning qApp
78 
79 #include <QClipboard>
80 #include <QComboBox>
81 #include <QFileDialog>
82 #include <QFileInfo>
83 #include <QLabel>
84 #include <QMessageBox>
85 #include <QPrinter>
86 #include <QPrintPreviewDialog>
87 #include <QProcess>
88 #include <QTextCodec>
89 #include <QtNumeric>
90 
91 #if defined(Q_OS_MAC)
92 #include <QMimeData>
93 #include <QDrag>
94 #endif //defined(Q_OS_MAC)
95 
96 #define DIALOG_MAX_FORMULA_HEIGHT 64
97 
98 QT_WARNING_PUSH
99 QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes")
100 QT_WARNING_DISABLE_INTEL(1418)
101 
102 Q_LOGGING_CATEGORY(tMainWindow, "t.mainwindow")
103 
105 
106 // We need this enum in case we will add or delete a column. And also make code more readable.
108 
109 //---------------------------------------------------------------------------------------------------------------------
110 TMainWindow::TMainWindow(QWidget *parent)
111  : VAbstractMainWindow(parent),
112  ui(new Ui::TMainWindow),
113  individualMeasurements(nullptr),
114  data(nullptr),
115  mUnit(Unit::Cm),
116  pUnit(Unit::Cm),
118  currentSize(0),
119  currentHeight(0),
120  curFile(),
121  gradationHeights(nullptr),
122  gradationSizes(nullptr),
123  comboBoxUnits(nullptr),
124  formulaBaseHeight(0),
125  lock(nullptr),
126  search(),
127  labelGradationHeights(nullptr),
128  labelGradationSizes(nullptr),
129  labelPatternUnit(nullptr),
130  actionDockDiagram(nullptr),
131  dockDiagramVisible(true),
132  isInitialized(false),
133  mIsReadOnly(false),
134  recentFileActs(),
135  separatorAct(nullptr),
136  hackedWidgets()
137 {
138  ui->setupUi(this);
139 
140  qApp->Settings()->GetOsSeparator() ? setLocale(QLocale()) : setLocale(QLocale::c());
141 
142  ui->lineEditFind->setClearButtonEnabled(true);
143  ui->lineEditName->setClearButtonEnabled(true);
144  ui->lineEditFullName->setClearButtonEnabled(true);
145  ui->lineEditGivenName->setClearButtonEnabled(true);
146  ui->lineEditFamilyName->setClearButtonEnabled(true);
147  ui->lineEditEmail->setClearButtonEnabled(true);
148 
149  ui->lineEditFind->installEventFilter(this);
150  ui->plainTextEditFormula->installEventFilter(this);
151 
152  search = QSharedPointer<VTableSearch>(new VTableSearch(ui->tableWidget));
153  ui->tabWidget->setVisible(false);
154 
155  ui->mainToolBar->setContextMenuPolicy(Qt::PreventContextMenu);
156  ui->toolBarGradation->setContextMenuPolicy(Qt::PreventContextMenu);
157 
158  //MSVC doesn't support int arrays in initializer list
159  for (int i = 0; i < MaxRecentFiles; ++i)
160  {
161  recentFileActs[i] = nullptr;
162  }
163 
164  SetupMenu();
166  ReadSettings();
167 
168 #if defined(Q_OS_MAC)
169  // On Mac default icon size is 32x32.
170  ui->toolBarGradation->setIconSize(QSize(24, 24));
171 
172  ui->pushButtonShowInExplorer->setText(tr("Show in Finder"));
173 
174  // Mac OS Dock Menu
175  QMenu *menu = new QMenu(this);
176  connect(menu, &QMenu::aboutToShow, this, &TMainWindow::AboutToShowDockMenu);
177  AboutToShowDockMenu();
178  menu->setAsDockMenu();
179 #endif //defined(Q_OS_MAC)
180 }
181 
182 //---------------------------------------------------------------------------------------------------------------------
184 {
185  delete data;
186  delete individualMeasurements;
187  delete ui;
188 }
189 
190 //---------------------------------------------------------------------------------------------------------------------
192 {
193  return curFile;
194 }
195 
196 //---------------------------------------------------------------------------------------------------------------------
198 {
199  if (individualMeasurements != nullptr)
200  {
201  const int row = ui->tableWidget->currentRow();
202  RefreshTable();
203  ui->tableWidget->selectRow(row);
204  search->RefreshList(ui->lineEditFind->text());
205  }
206 }
207 
208 //---------------------------------------------------------------------------------------------------------------------
210 {
211  if (individualMeasurements != nullptr)
212  {
214  {
215  const int row = ui->tableWidget->currentRow();
217  RefreshData();
218  ui->tableWidget->selectRow(row);
219  }
220  }
221 }
222 
223 //---------------------------------------------------------------------------------------------------------------------
225 {
226  if (individualMeasurements != nullptr)
227  {
229  {
230  const int row = ui->tableWidget->currentRow();
232  RefreshData();
233  ui->tableWidget->selectRow(row);
234  }
235  }
236 }
237 
238 //---------------------------------------------------------------------------------------------------------------------
240 {
241  pUnit = unit;
243 }
244 
245 //---------------------------------------------------------------------------------------------------------------------
246 bool TMainWindow::LoadFile(const QString &path)
247 {
248  if (individualMeasurements == nullptr)
249  {
250  if (not QFileInfo(path).exists())
251  {
252  qCCritical(tMainWindow, "%s", qUtf8Printable(tr("File '%1' doesn't exist!").arg(path)));
253  if (qApp->IsTestMode())
254  {
255  qApp->exit(V_EX_NOINPUT);
256  }
257  return false;
258  }
259 
260  // Check if file already opened
261  QList<TMainWindow*>list = qApp->MainWindows();
262  for (int i = 0; i < list.size(); ++i)
263  {
264  if (list.at(i)->CurrentFile() == path)
265  {
266  list.at(i)->activateWindow();
267  close();
268  return false;
269  }
270  }
271 
272  VlpCreateLock(lock, path);
273 
274  if (not lock->IsLocked())
275  {
276  if (not IgnoreLocking(lock->GetLockError(), path))
277  {
278  return false;
279  }
280  }
281 
282  try
283  {
284  data = new VContainer(qApp->TrVars(), &mUnit);
285 
290 
292 
294  {
295  VException e(tr("File has unknown format."));
296  throw e;
297  }
298 
300  {
301  VVSTConverter converter(path);
304  individualMeasurements->setXMLContent(converter.Convert());// Read again after conversion
305  }
306  else
307  {
308  VVITConverter converter(path);
311  individualMeasurements->setXMLContent(converter.Convert());// Read again after conversion
312  }
313 
315  {
316  VException e(tr("File contains invalid known measurement(s)."));
317  throw e;
318  }
319 
321  pUnit = mUnit;
322 
325 
326  ui->labelToolTip->setVisible(false);
327  ui->tabWidget->setVisible(true);
328 
331 
332  SetCurrentFile(path);
333 
334  InitWindow();
335 
336  const bool freshCall = true;
337  RefreshData(freshCall);
338 
339  if (ui->tableWidget->rowCount() > 0)
340  {
341  ui->tableWidget->selectRow(0);
342  }
343 
344  MeasurementGUI();
345  }
346  catch (VException &e)
347  {
348  qCCritical(tMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
349  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
350  ui->labelToolTip->setVisible(true);
351  ui->tabWidget->setVisible(false);
352  delete individualMeasurements;
353  individualMeasurements = nullptr;
354  delete data;
355  data = nullptr;
356  lock.reset();
357 
358  if (qApp->IsTestMode())
359  {
360  qApp->exit(V_EX_NOINPUT);
361  }
362  return false;
363  }
364  }
365  else
366  {
367  qApp->NewMainWindow();
368  return qApp->MainWindow()->LoadFile(path);
369  }
370 
371  return true;
372 }
373 
374 //---------------------------------------------------------------------------------------------------------------------
375 void TMainWindow::ShowToolTip(const QString &toolTip)
376 {
377  Q_UNUSED(toolTip)
378  // do nothing
379 }
380 
381 //---------------------------------------------------------------------------------------------------------------------
383 {
384  // do nothing
385 }
386 
387 //---------------------------------------------------------------------------------------------------------------------
389 {
390  if (individualMeasurements == nullptr)
391  {
392  DialogNewMeasurements measurements(this);
393  if (measurements.exec() == QDialog::Rejected)
394  {
395  return;
396  }
397 
398  mUnit = measurements.MUnit();
399  pUnit = mUnit;
400  mType = measurements.Type();
401 
402  data = new VContainer(qApp->TrVars(), &mUnit);
403  currentHeight = measurements.BaseHeight();
404  currentSize = measurements.BaseSize();
405 
407  {
408  individualMeasurements = new VMeasurements(mUnit, measurements.BaseSize(), measurements.BaseHeight(), data);
413  }
414  else
415  {
419  }
420 
423 
424  SetCurrentFile("");
425  MeasurementsWasSaved(false);
426 
427  InitWindow();
428 
429  MeasurementGUI();
430  }
431  else
432  {
433  qApp->NewMainWindow();
434  qApp->MainWindow()->FileNew();
435  }
436 }
437 
438 //---------------------------------------------------------------------------------------------------------------------
440 {
441  const QString filter = tr("Individual measurements") + QLatin1String(" (*.vit);;") + tr("Multisize measurements") +
442  QLatin1String(" (*.vst);;") + tr("All files") + QLatin1String(" (*.*)");
443  //Use standard path to individual measurements
444  const QString pathTo = qApp->SeamlyMeSettings()->GetPathIndividualMeasurements();
445 
446  bool usedNotExistedDir = false;
447  QDir directory(pathTo);
448  if (not directory.exists())
449  {
450  usedNotExistedDir = directory.mkpath(".");
451  }
452 
453  Open(pathTo, filter);
454 
455  if (usedNotExistedDir)
456  {
457  QDir directory(pathTo);
458  directory.rmpath(".");
459  }
460 }
461 
462 //---------------------------------------------------------------------------------------------------------------------
464 {
465  const QString filter = tr("Multisize measurements") + QLatin1String(" (*.vst);;") + tr("Individual measurements") +
466  QLatin1String(" (*.vit);;") + tr("All files") + QLatin1String(" (*.*)");
467  //Use standard path to multisize measurements
468  QString pathTo = qApp->SeamlyMeSettings()->GetPathMultisizeMeasurements();
470 
471  Open(pathTo, filter);
472 }
473 
474 //---------------------------------------------------------------------------------------------------------------------
476 {
477  const QString filter = tr("Measurements") + QLatin1String(" (*.vst *.vit);;") + tr("All files") +
478  QLatin1String(" (*.*)");
479  //Use standard path to template files
480  QString pathTo = qApp->SeamlyMeSettings()->GetPathTemplate();
482  Open(pathTo, filter);
483 
484  if (individualMeasurements != nullptr)
485  {// The file was opened.
486  SetCurrentFile(""); // Force user to to save new file
487  lock.reset();// remove lock from template
488  }
489 }
490 
491 //---------------------------------------------------------------------------------------------------------------------
493 {
494  const QString filter = tr("Individual measurements") + QLatin1String(" (*.vit)");
495  //Use standard path to individual measurements
496  const QString pathTo = qApp->SeamlyMeSettings()->GetPathIndividualMeasurements();
497 
498  bool usedNotExistedDir = false;
499  QDir directory(pathTo);
500  if (not directory.exists())
501  {
502  usedNotExistedDir = directory.mkpath(".");
503  }
504 
505  const QString mPath = QFileDialog::getOpenFileName(this, tr("Select file"), pathTo, filter);
506 
507  if (not mPath.isEmpty())
508  {
509  if (individualMeasurements == nullptr)
510  {
511  LoadFromExistingFile(mPath);
512  }
513  else
514  {
515  qApp->NewMainWindow()->CreateFromExisting();
516  }
517  }
518 
519  if (usedNotExistedDir)
520  {
521  QDir directory(pathTo);
522  directory.rmpath(".");
523  }
524 }
525 
526 //---------------------------------------------------------------------------------------------------------------------
528 {
529  // Calling constructor of the dialog take some time. Because of this user have time to call the dialog twice.
530  static QPointer<DialogSeamlyMePreferences> guard;// Prevent any second run
531  if (guard.isNull())
532  {
533  QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
534  DialogSeamlyMePreferences *preferences = new DialogSeamlyMePreferences(this);
535  // QScopedPointer needs to be sure any exception will never block guard
536  QScopedPointer<DialogSeamlyMePreferences> dlg(preferences);
537  guard = preferences;
538  // Must be first
541  QGuiApplication::restoreOverrideCursor();
542  dlg->exec();
543  }
544 }
545 
546 //---------------------------------------------------------------------------------------------------------------------
548 {
549  ToolBarStyle(ui->toolBarGradation);
550  ToolBarStyle(ui->mainToolBar);
551 }
552 
553 //---------------------------------------------------------------------------------------------------------------------
554 void TMainWindow::closeEvent(QCloseEvent *event)
555 {
556  if (MaybeSave())
557  {
558  WriteSettings();
559  event->accept();
560  deleteLater();
561  }
562  else
563  {
564  event->ignore();
565  }
566 }
567 
568 //---------------------------------------------------------------------------------------------------------------------
569 void TMainWindow::changeEvent(QEvent *event)
570 {
571  if (event->type() == QEvent::LanguageChange)
572  {
573  qApp->Settings()->GetOsSeparator() ? setLocale(QLocale()) : setLocale(QLocale::c());
574 
575  // retranslate designer form (single inheritance approach)
576  ui->retranslateUi(this);
577 
579  {
580  ui->labelMType->setText(tr("Multisize measurements"));
581  ui->labelBaseSizeValue->setText(QString().setNum(individualMeasurements->BaseSize()) + QLatin1String(" ") +
583  ui->labelBaseHeightValue->setText(QString().setNum(individualMeasurements->BaseHeight()) + QLatin1String(" ") +
585 
586  labelGradationHeights = new QLabel(tr("Height:"));
587  labelGradationSizes = new QLabel(tr("Size:"));
588  }
589  else
590  {
591  ui->labelMType->setText(tr("Individual measurements"));
592 
593  const qint32 index = ui->comboBoxGender->currentIndex();
594  ui->comboBoxGender->blockSignals(true);
595  ui->comboBoxGender->clear();
596  InitGender(ui->comboBoxGender);
597  ui->comboBoxGender->setCurrentIndex(index);
598  ui->comboBoxGender->blockSignals(false);
599  }
600 
601  {
602  const qint32 index = ui->comboBoxPMSystem->currentIndex();
603  ui->comboBoxPMSystem->blockSignals(true);
604  ui->comboBoxPMSystem->clear();
605  InitPMSystems(ui->comboBoxPMSystem);
606  ui->comboBoxPMSystem->setCurrentIndex(index);
607  ui->comboBoxPMSystem->blockSignals(false);
608  }
609 
610  {
611  labelPatternUnit = new QLabel(tr("Pattern unit:"));
612 
613  if (comboBoxUnits != nullptr)
614  {
615  const qint32 index = comboBoxUnits->currentIndex();
616  comboBoxUnits->blockSignals(true);
617  comboBoxUnits->clear();
619  comboBoxUnits->setCurrentIndex(index);
620  comboBoxUnits->blockSignals(false);
621  }
622  }
623  }
624 
625  // remember to call base class implementation
626  QMainWindow::changeEvent(event);
627 }
628 
629 //---------------------------------------------------------------------------------------------------------------------
630 void TMainWindow::showEvent(QShowEvent *event)
631 {
632  QMainWindow::showEvent( event );
633  if ( event->spontaneous() )
634  {
635  return;
636  }
637 
638  if (isInitialized)
639  {
640  return;
641  }
642  // do your init stuff here
643 
644  dockDiagramVisible = ui->dockWidgetDiagram->isVisible();
645  ui->dockWidgetDiagram->setVisible(false);
646 
647  isInitialized = true;//first show windows are held
648 }
649 
650 //---------------------------------------------------------------------------------------------------------------------
651 bool TMainWindow::eventFilter(QObject *object, QEvent *event)
652 {
653  if (QPlainTextEdit *plainTextEdit = qobject_cast<QPlainTextEdit *>(object))
654  {
655  if (event->type() == QEvent::KeyPress)
656  {
657  QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
658  if ((keyEvent->key() == Qt::Key_Enter) || (keyEvent->key() == Qt::Key_Return))
659  {
660  // Ignore Enter key
661  return true;
662  }
663  else if ((keyEvent->key() == Qt::Key_Period) && (keyEvent->modifiers() & Qt::KeypadModifier))
664  {
665  if (qApp->Settings()->GetOsSeparator())
666  {
667  plainTextEdit->insertPlainText(QLocale().decimalPoint());
668  }
669  else
670  {
671  plainTextEdit->insertPlainText(QLocale::c().decimalPoint());
672  }
673  return true;
674  }
675  }
676  }
677  else if (QLineEdit *textEdit = qobject_cast<QLineEdit *>(object))
678  {
679  if (event->type() == QEvent::KeyPress)
680  {
681  QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
682  if ((keyEvent->key() == Qt::Key_Period) && (keyEvent->modifiers() & Qt::KeypadModifier))
683  {
684  if (qApp->Settings()->GetOsSeparator())
685  {
686  textEdit->insert(QLocale().decimalPoint());
687  }
688  else
689  {
690  textEdit->insert(QLocale::c().decimalPoint());
691  }
692  return true;
693  }
694  }
695  }
696  else
697  {
698  // pass the event on to the parent class
699  return QMainWindow::eventFilter(object, event);
700  }
701  return false;// pass the event to the widget
702 }
703 
704 //---------------------------------------------------------------------------------------------------------------------
705 void TMainWindow::exportToCSVData(const QString &fileName, const DialogExportToCSV &dialog)
706 {
707  QxtCsvModel csv;
708  int columns;
710  {
711  columns = ui->tableWidget->columnCount();
712  }
713  else
714  {
715  columns = 5;
716  }
717  {
718  int colCount = 0;
719  for (int column = 0; column < columns; ++column)
720  {
721  if (not ui->tableWidget->isColumnHidden(column))
722  {
723  csv.insertColumn(colCount++);
724  }
725  }
726  }
727 
728  if (dialog.WithHeader())
729  {
730  int colCount = 0;
731  for (int column = 0; column < columns; ++column)
732  {
733  if (not ui->tableWidget->isColumnHidden(column))
734  {
735  QTableWidgetItem *header = ui->tableWidget->horizontalHeaderItem(colCount);
736  csv.setHeaderText(colCount, header->text());
737  ++colCount;
738  }
739  }
740  }
741 
742  const int rows = ui->tableWidget->rowCount();
743  for (int row = 0; row < rows; ++row)
744  {
745  csv.insertRow(row);
746  int colCount = 0;
747  for (int column = 0; column < columns; ++column)
748  {
749  if (not ui->tableWidget->isColumnHidden(column))
750  {
751  QTableWidgetItem *item = ui->tableWidget->item(row, column);
752  csv.setText(row, colCount, item->text());
753  ++colCount;
754  }
755  }
756  }
757 
758  csv.toCSV(fileName, dialog.WithHeader(), dialog.Separator(), QTextCodec::codecForMib(dialog.SelectedMib()));
759 }
760 
762 {
763  QString file = tr("untitled");
764  if(!curFile.isEmpty())
765  {
766  file = QFileInfo(curFile).baseName();
767  }
768  exportToCSV(file);
769 }
770 
771 //---------------------------------------------------------------------------------------------------------------------
773 {
774  int width = 0;
775  int height = 0;
776  int columns;
778  {
779  columns = ui->tableWidget->columnCount();
780  }
781  else
782  {
783  columns = 5;
784  }
785  int rows = ui->tableWidget->rowCount();
786 
787  for( int i = 0; i < columns; ++i ) {
788  width += ui->tableWidget->columnWidth(i);
789  }
790 
791  for( int i = 0; i < rows; ++i ) {
792  height += ui->tableWidget->rowHeight(i);
793  }
794 
795  QPrintPreviewDialog *dialog = new QPrintPreviewDialog(this);
796  connect(dialog, &QPrintPreviewDialog::paintRequested, this, &TMainWindow::printPages);
797 
798  dialog->showMaximized();
799  dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);
800  dialog->exec();
801 }
802 
803 void TMainWindow::printPages(QPrinter *printer)
804 {
805  int columns;
807  {
808  columns = ui->tableWidget->columnCount();
809  }
810  else
811  {
812  columns = 5;
813  }
814 
815  QTextDocument doc;
816 
817  QString text("<h2>" + CurrentFile() + "</h2>");
818  text.append("<table>");
820  {
821  text.append("<tr><td align = left><b>Base Size:</b></td><td>" + ui->labelBaseSizeValue->text() + "</td></tr>");
822  text.append("<tr><td align = left><b>Base Height:</b></td><td>" + ui->labelBaseHeightValue->text() + "</td></tr>");
823  }
824  else
825  {
826  text.append("<tr><td align = left><b>Units:</b></td><td>" + UnitsToStr(mUnit) + "</td></tr>");
827  text.append("<tr><td align = left><b>First Name:</b></td><td>" + ui->lineEditGivenName->text() + "</td></tr>");
828  text.append("<tr><td align = left><b>Last Name:</b></td><td>" + ui->lineEditFamilyName->text() + "</td></tr>");
829  text.append("<tr><td align = left><b>Gender:</b></td><td>" + ui->comboBoxGender->currentText() + "</td></tr>");
830  text.append("<tr><td align = left><b>Email:</b></td><td>" + ui->lineEditEmail->text() + "</td></tr>");
831  }
832  text.append("<tr><td align = left><b>Notes:</b></td><td>" + ui->plainTextEditNotes->toPlainText() + "</td></tr></table>");
833  text.append("<p>");
834 
835  text.append("<table><thead>");
836  text.append("<tr>");
837  for (int i = 0; i < columns; i++)
838  {
839  text.append("<th>").append(ui->tableWidget->horizontalHeaderItem(i)->data(Qt::DisplayRole).toString()).append("</th>");
840  }
841  text.append("</tr></thead>");
842  text.append("<tbody>");
843  for (int i = 0; i < ui->tableWidget->rowCount(); i++)
844  {
845  text.append("<tr>");
846  for (int j = 0; j < columns; j++)
847  {
848  QTableWidgetItem *item = ui->tableWidget->item(i, j);
849  if (!item || item->text().isEmpty())
850  {
851 
852  if (j > 1)
853  {
854  ui->tableWidget->setItem(i, j, new QTableWidgetItem("0"));
855  }
856  else
857  {
858  ui->tableWidget->setItem(i, j, new QTableWidgetItem(""));
859  }
860  }
861  if (j == 1 || j > 2)
862  {
863  text.append("<td align = center>").append(ui->tableWidget->item(i, j)->text()).append("</td>");
864  }
865  else
866  {
867  text.append("<td align = left>").append(ui->tableWidget->item(i, j)->text()).append("</td>");
868  }
869  }
870  text.append("</tr>");
871  }
872  text.append("</tbody></table>");
873 
874  printer->setPageMargins(QMarginsF(10, 10, 10, 10), QPageLayout::Millimeter);
875  doc.setHtml(text);
876  doc.setPageSize(printer->pageLayout().paintRectPixels(static_cast<int>(PrintDPI)).size());
877  doc.print(printer);
878 }
879 
880 //---------------------------------------------------------------------------------------------------------------------
882 {
883  if (curFile.isEmpty() || mIsReadOnly)
884  {
885  return FileSaveAs();
886  }
887  else
888  {
892  {
893  return false;
894  }
898  {
899  return false;
900  }
901 
902 #ifdef Q_OS_WIN32
903  qt_ntfs_permission_lookup++; // turn checking on
904 #endif /*Q_OS_WIN32*/
905  const bool isFileWritable = QFileInfo(curFile).isWritable();
906 #ifdef Q_OS_WIN32
907  qt_ntfs_permission_lookup--; // turn it off again
908 #endif /*Q_OS_WIN32*/
909 
910  if (not isFileWritable)
911  {
912  QMessageBox messageBox(this);
913  messageBox.setIcon(QMessageBox::Question);
914  messageBox.setText(tr("The measurements document has no write permissions."));
915  messageBox.setInformativeText("Do you want to change the premissions?");
916  messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
917  messageBox.setDefaultButton(QMessageBox::Yes);
918 
919  if (messageBox.exec() == QMessageBox::Yes)
920  {
921 #ifdef Q_OS_WIN32
922  qt_ntfs_permission_lookup++; // turn checking on
923 #endif /*Q_OS_WIN32*/
924  bool changed = QFile::setPermissions(curFile,
925  QFileInfo(curFile).permissions() | QFileDevice::WriteUser);
926 #ifdef Q_OS_WIN32
927  qt_ntfs_permission_lookup--; // turn it off again
928 #endif /*Q_OS_WIN32*/
929 
930  if (not changed)
931  {
932  QMessageBox messageBox(this);
933  messageBox.setIcon(QMessageBox::Warning);
934  messageBox.setText(tr("Cannot set permissions for %1 to writable.").arg(curFile));
935  messageBox.setInformativeText(tr("Could not save the file."));
936  messageBox.setDefaultButton(QMessageBox::Ok);
937  messageBox.setStandardButtons(QMessageBox::Ok);
938  messageBox.exec();
939  return false;
940  }
941  }
942  else
943  {
944  return false;
945  }
946  }
947 
948  QString error;
949  if (not SaveMeasurements(curFile, error))
950  {
951  QMessageBox messageBox;
952  messageBox.setIcon(QMessageBox::Warning);
953  messageBox.setText(tr("Could not save the file"));
954  messageBox.setDefaultButton(QMessageBox::Ok);
955  messageBox.setDetailedText(error);
956  messageBox.setStandardButtons(QMessageBox::Ok);
957  messageBox.exec();
958  return false;
959  }
960  else
961  {
963  {
966  }
967  else
968  {
971  }
972  }
973  }
974  return true;
975 }
976 
977 //---------------------------------------------------------------------------------------------------------------------
979 {
980  QString dir;
981  QString filters;
982  QString suffix;
983  QString filePath = CurrentFile();
984  QString fileName = QLatin1String("measurements");
985  if (!filePath.isEmpty())
986  {
987  dir = QFileInfo(filePath).path();
988  fileName = QFileInfo(filePath).baseName();
990  {
991  filters = tr("Individual measurements") + QLatin1String(" (*.vit)");
992  suffix = QLatin1String("vit");
993  }
994  else
995  {
996  filters = tr("Multisize measurements") + QLatin1String(" (*.vst)");
997  suffix = QLatin1String("vst");
998  }
999  }
1000  else
1001  {
1003  {
1004  dir = qApp->SeamlyMeSettings()->GetDefPathIndividualMeasurements();
1005  filters = tr("Individual measurements") + QLatin1String(" (*.vit)");
1006  suffix = QLatin1String("vit");
1007  }
1008  else
1009  {
1010  dir = qApp->SeamlyMeSettings()->GetDefPathMultisizeMeasurements();
1011  filters = tr("Multisize measurements") + QLatin1String(" (*.vst)");
1012  suffix = QLatin1String("vst");
1013  }
1014  }
1015 
1017  {
1018  filters = tr("Individual measurements") + QLatin1String(" (*.vit)");
1019  suffix = QLatin1String("vit");
1020  }
1021  else
1022  {
1023  filters = tr("Multisize measurements") + QLatin1String(" (*.vst)");
1024  suffix = QLatin1String("vst");
1025  }
1026 
1027  fileName += QLatin1String(".") + suffix;
1028 
1029  if (curFile.isEmpty())
1030  {
1032  {
1033  dir = qApp->SeamlyMeSettings()->GetPathIndividualMeasurements();
1034  }
1035  else
1036  {
1037  dir = qApp->SeamlyMeSettings()->GetPathMultisizeMeasurements();
1039  }
1040  }
1041  else
1042  {
1043  dir = QFileInfo(curFile).absolutePath();
1044  }
1045 
1046  bool usedNotExistedDir = false;
1047  QDir directory(dir);
1048  if (not directory.exists())
1049  {
1050  usedNotExistedDir = directory.mkpath(".");
1051  }
1052 
1053  fileName = QFileDialog::getSaveFileName(this, tr("Save as"), dir + QLatin1String("/") + fileName,
1054  filters, nullptr, QFileDialog::DontUseNativeDialog);
1055 
1056  auto RemoveTempDir = [usedNotExistedDir, dir]()
1057  {
1058  if (usedNotExistedDir)
1059  {
1060  QDir directory(dir);
1061  directory.rmpath(".");
1062  }
1063  };
1064 
1065  if (fileName.isEmpty())
1066  {
1067  RemoveTempDir();
1068  return false;
1069  }
1070 
1071  QFileInfo fileInfo(fileName);
1072  if (fileInfo.suffix().isEmpty() && fileInfo.suffix() != suffix)
1073  {
1074  fileName += QLatin1String(".") + suffix;
1075  }
1076 
1077  if (fileInfo.exists() && fileName != filePath)
1078  {
1079  // Temporarily try to lock the file before saving
1080  VLockGuard<char> tmp(fileName);
1081  if (!tmp.IsLocked())
1082  {
1083  qCWarning(tMainWindow, "%s",
1084  qUtf8Printable(tr("Failed to lock. This file already opened in another window.")));
1085  RemoveTempDir();
1086  return false;
1087  }
1088  }
1089 
1090  // Need for restoring previous state in case of failure
1091  const bool readOnly = individualMeasurements->IsReadOnly();
1092 
1094  mIsReadOnly = false;
1095 
1096  QString error;
1097  bool result = SaveMeasurements(fileName, error);
1098  if (result == false)
1099  {
1100  QMessageBox messageBox;
1101  messageBox.setIcon(QMessageBox::Warning);
1102  messageBox.setInformativeText(tr("Could not save file"));
1103  messageBox.setDefaultButton(QMessageBox::Ok);
1104  messageBox.setDetailedText(error);
1105  messageBox.setStandardButtons(QMessageBox::Ok);
1106  messageBox.exec();
1107 
1108  // Restore previous state
1110  mIsReadOnly = readOnly;
1111  RemoveTempDir();
1112  return false;
1113  }
1114 
1115  UpdatePadlock(false);
1117 
1118  if (fileName != filePath)
1119  {
1120  VlpCreateLock(lock, fileName);
1121  if (!lock->IsLocked())
1122  {
1123  qCCritical(tMainWindow, "%s", qUtf8Printable(tr("Failed to lock. This file already opened in another window. "
1124  "Expect collisions when running 2 copies of the program.")));
1125  RemoveTempDir();
1126  return false;
1127  }
1128  }
1129 
1130  RemoveTempDir();
1131  return true;
1132 }
1133 
1134 //---------------------------------------------------------------------------------------------------------------------
1136 {
1137  ui->window_Menu->clear();
1138  CreateWindowMenu(ui->window_Menu);
1139 }
1140 
1141 //---------------------------------------------------------------------------------------------------------------------
1143 {
1144  if (QAction *action = qobject_cast<QAction*>(sender()))
1145  {
1146  const QVariant v = action->data();
1147  if (v.canConvert<int>())
1148  {
1149  const int offset = qvariant_cast<int>(v);
1150  const QList<TMainWindow*> windows = qApp->MainWindows();
1151  windows.at(offset)->raise();
1152  windows.at(offset)->activateWindow();
1153  }
1154  }
1155 }
1156 
1157 //---------------------------------------------------------------------------------------------------------------------
1158 #if defined(Q_OS_MAC)
1159 void TMainWindow::AboutToShowDockMenu()
1160 {
1161  if (QMenu *menu = qobject_cast<QMenu *>(sender()))
1162  {
1163  menu->clear();
1164  CreateWindowMenu(menu);
1165 
1166  menu->addSeparator();
1167 
1168  menu->addAction(ui->actionOpenIndividual);
1169  menu->addAction(ui->actionOpenMultisize);
1170  menu->addAction(ui->actionOpenTemplate);
1171 
1172  menu->addSeparator();
1173 
1174  QAction *actionPreferences = menu->addAction(tr("Preferences"));
1175  actionPreferences->setMenuRole(QAction::NoRole);
1176  connect(actionPreferences, &QAction::triggered, this, &TMainWindow::Preferences);
1177  }
1178 }
1179 
1180 //---------------------------------------------------------------------------------------------------------------------
1181 void TMainWindow::OpenAt(QAction *where)
1182 {
1183  const QString path = curFile.left(curFile.indexOf(where->text())) + where->text();
1184  if (path == curFile)
1185  {
1186  return;
1187  }
1188  QProcess process;
1189  process.start(QStringLiteral("/usr/bin/open"), QStringList() << path, QIODevice::ReadOnly);
1190  process.waitForFinished();
1191 }
1192 #endif //defined(Q_OS_MAC)
1193 
1194 //---------------------------------------------------------------------------------------------------------------------
1196 {
1197  if (individualMeasurements->GivenName() != ui->lineEditGivenName->text())
1198  {
1199  individualMeasurements->SetGivenName(ui->lineEditGivenName->text());
1200  MeasurementsWasSaved(false);
1201  }
1202 }
1203 
1204 //---------------------------------------------------------------------------------------------------------------------
1206 {
1207  if (individualMeasurements->FamilyName() != ui->lineEditFamilyName->text())
1208  {
1209  individualMeasurements->SetFamilyName(ui->lineEditFamilyName->text());
1210  MeasurementsWasSaved(false);
1211  }
1212 }
1213 
1214 //---------------------------------------------------------------------------------------------------------------------
1216 {
1217  if (individualMeasurements->Email() != ui->lineEditEmail->text())
1218  {
1219  individualMeasurements->SetEmail(ui->lineEditEmail->text());
1220  MeasurementsWasSaved(false);
1221  }
1222 }
1223 
1224 //---------------------------------------------------------------------------------------------------------------------
1226 {
1227  const GenderType type = static_cast<GenderType>(ui->comboBoxGender->itemData(index).toInt());
1228  if (individualMeasurements->Gender() != type)
1229  {
1231  MeasurementsWasSaved(false);
1232  }
1233 }
1234 
1235 //---------------------------------------------------------------------------------------------------------------------
1236 void TMainWindow::SaveBirthDate(const QDate &date)
1237 {
1238  if (individualMeasurements->BirthDate() != date)
1239  {
1241  MeasurementsWasSaved(false);
1242  }
1243 }
1244 
1245 //---------------------------------------------------------------------------------------------------------------------
1247 {
1248  if (individualMeasurements->Notes() != ui->plainTextEditNotes->toPlainText())
1249  {
1250  individualMeasurements->SetNotes(ui->plainTextEditNotes->toPlainText());
1251  MeasurementsWasSaved(false);
1252  }
1253 }
1254 
1255 //---------------------------------------------------------------------------------------------------------------------
1257 {
1258  QString system = ui->comboBoxPMSystem->itemData(index).toString();
1259  system.remove(0, 1);// clear p
1260 
1261  if (individualMeasurements->PMSystem() != system)
1262  {
1264  MeasurementsWasSaved(false);
1265  }
1266 }
1267 
1268 //---------------------------------------------------------------------------------------------------------------------
1270 {
1271  const int row = ui->tableWidget->currentRow();
1272 
1273  if (row == -1)
1274  {
1275  return;
1276  }
1277 
1278  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), 0);
1279  individualMeasurements->Remove(nameField->data(Qt::UserRole).toString());
1280 
1281  MeasurementsWasSaved(false);
1282 
1283  search->RemoveRow(row);
1284  RefreshData();
1285  search->RefreshList(ui->lineEditFind->text());
1286 
1287  if (ui->tableWidget->rowCount() > 0)
1288  {
1289  ui->tableWidget->selectRow(row);
1290  }
1291  else
1292  {
1293  MFields(false);
1294 
1295  ui->actionExportToCSV->setEnabled(false);
1296 
1297  ui->lineEditName->blockSignals(true);
1298  ui->lineEditName->setText("");
1299  ui->lineEditName->blockSignals(false);
1300 
1301  ui->plainTextEditDescription->blockSignals(true);
1302  ui->plainTextEditDescription->setPlainText("");
1303  ui->plainTextEditDescription->blockSignals(false);
1304 
1305  ui->lineEditFullName->blockSignals(true);
1306  ui->lineEditFullName->setText("");
1307  ui->lineEditFullName->blockSignals(false);
1308 
1310  {
1311  ui->labelCalculatedValue->blockSignals(true);
1312  ui->doubleSpinBoxBaseValue->blockSignals(true);
1313  ui->doubleSpinBoxInSizes->blockSignals(true);
1314  ui->doubleSpinBoxInHeights->blockSignals(true);
1315 
1316  ui->labelCalculatedValue->setText("");
1317  ui->doubleSpinBoxBaseValue->setValue(0);
1318  ui->doubleSpinBoxInSizes->setValue(0);
1319  ui->doubleSpinBoxInHeights->setValue(0);
1320 
1321  ui->labelCalculatedValue->blockSignals(false);
1322  ui->doubleSpinBoxBaseValue->blockSignals(false);
1323  ui->doubleSpinBoxInSizes->blockSignals(false);
1324  ui->doubleSpinBoxInHeights->blockSignals(false);
1325  }
1326  else
1327  {
1328  ui->labelCalculatedValue->blockSignals(true);
1329  ui->labelCalculatedValue->setText("");
1330  ui->labelCalculatedValue->blockSignals(false);
1331 
1332  ui->plainTextEditFormula->blockSignals(true);
1333  ui->plainTextEditFormula->setPlainText("");
1334  ui->plainTextEditFormula->blockSignals(false);
1335  }
1336  }
1337 }
1338 
1339 //---------------------------------------------------------------------------------------------------------------------
1341 {
1342  const int row = ui->tableWidget->currentRow();
1343 
1344  if (row == -1)
1345  {
1346  return;
1347  }
1348 
1349  const QTableWidgetItem *nameField = ui->tableWidget->item(row, ColumnName);
1350  individualMeasurements->MoveTop(nameField->data(Qt::UserRole).toString());
1351  MeasurementsWasSaved(false);
1352  RefreshData();
1353  search->RefreshList(ui->lineEditFind->text());
1354  ui->tableWidget->selectRow(0);
1355 }
1356 
1357 //---------------------------------------------------------------------------------------------------------------------
1359 {
1360  const int row = ui->tableWidget->currentRow();
1361 
1362  if (row == -1)
1363  {
1364  return;
1365  }
1366 
1367  const QTableWidgetItem *nameField = ui->tableWidget->item(row, ColumnName);
1368  individualMeasurements->MoveUp(nameField->data(Qt::UserRole).toString());
1369  MeasurementsWasSaved(false);
1370  RefreshData();
1371  search->RefreshList(ui->lineEditFind->text());
1372  ui->tableWidget->selectRow(row-1);
1373 }
1374 
1375 //---------------------------------------------------------------------------------------------------------------------
1377 {
1378  const int row = ui->tableWidget->currentRow();
1379 
1380  if (row == -1)
1381  {
1382  return;
1383  }
1384 
1385  const QTableWidgetItem *nameField = ui->tableWidget->item(row, ColumnName);
1386  individualMeasurements->MoveDown(nameField->data(Qt::UserRole).toString());
1387  MeasurementsWasSaved(false);
1388  RefreshData();
1389  search->RefreshList(ui->lineEditFind->text());
1390  ui->tableWidget->selectRow(row+1);
1391 }
1392 
1393 //---------------------------------------------------------------------------------------------------------------------
1395 {
1396  const int row = ui->tableWidget->currentRow();
1397 
1398  if (row == -1)
1399  {
1400  return;
1401  }
1402 
1403  const QTableWidgetItem *nameField = ui->tableWidget->item(row, ColumnName);
1404  individualMeasurements->MoveBottom(nameField->data(Qt::UserRole).toString());
1405  MeasurementsWasSaved(false);
1406  RefreshData();
1407  search->RefreshList(ui->lineEditFind->text());
1408  ui->tableWidget->selectRow(ui->tableWidget->rowCount()-1);
1409 }
1410 
1411 //---------------------------------------------------------------------------------------------------------------------
1413 {
1414  const int row = ui->tableWidget->currentRow();
1415 
1416  if (row == -1)
1417  {
1418  return;
1419  }
1420 
1421  const QTableWidgetItem *nameField = ui->tableWidget->item(row, ColumnName);
1422 
1424 
1425  try
1426  {
1427  // Translate to internal look.
1428  meash = data->GetVariable<VMeasurement>(nameField->data(Qt::UserRole).toString());
1429  }
1430  catch(const VExceptionBadId & e)
1431  {
1432  qCCritical(tMainWindow, "%s\n\n%s\n\n%s",
1433  qUtf8Printable(tr("Can't find measurement '%1'.").arg(nameField->text())),
1434  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
1435  return;
1436  }
1437 
1438  EditFormulaDialog *dialog = new EditFormulaDialog(meash->GetData(), NULL_ID, this);
1439  dialog->setWindowTitle(tr("Edit measurement"));
1440  dialog->SetFormula(qApp->TrVars()->TryFormulaFromUser(ui->plainTextEditFormula->toPlainText().replace("\n", " "),
1441  true));
1442  const QString postfix = UnitsToStr(mUnit, true);//Show unit in dialog label (cm, mm or inch)
1443  dialog->setPostfix(postfix);
1444 
1445  if (dialog->exec() == QDialog::Accepted)
1446  {
1447  // Because of the bug need to take QTableWidgetItem twice time. Previous update "killed" the pointer.
1448  const QTableWidgetItem *nameField = ui->tableWidget->item(row, ColumnName);
1449  individualMeasurements->SetMValue(nameField->data(Qt::UserRole).toString(), dialog->GetFormula());
1450 
1451  MeasurementsWasSaved(false);
1452 
1453  RefreshData();
1454 
1455  search->RefreshList(ui->lineEditFind->text());
1456 
1457  ui->tableWidget->selectRow(row);
1458  }
1459  delete dialog;
1460 }
1461 
1462 //---------------------------------------------------------------------------------------------------------------------
1464 {
1465  const QString name = GetCustomName();
1466  qint32 currentRow = -1;
1467 
1468  if (ui->tableWidget->currentRow() == -1)
1469  {
1470  currentRow = ui->tableWidget->rowCount();
1472  }
1473  else
1474  {
1475  currentRow = ui->tableWidget->currentRow()+1;
1476  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
1477  individualMeasurements->AddEmptyAfter(nameField->data(Qt::UserRole).toString(), name);
1478  }
1479 
1480  search->AddRow(currentRow);
1481  RefreshData();
1482  search->RefreshList(ui->lineEditFind->text());
1483 
1484  ui->tableWidget->selectRow(currentRow);
1485 
1486  ui->actionExportToCSV->setEnabled(true);
1487 
1488  MeasurementsWasSaved(false);
1489 }
1490 
1491 //---------------------------------------------------------------------------------------------------------------------
1493 {
1494  QScopedPointer<MeasurementDatabaseDialog> dialog (new MeasurementDatabaseDialog(individualMeasurements->listKnown(), this));
1495  if (dialog->exec() == QDialog::Accepted)
1496  {
1497  qint32 currentRow;
1498 
1499  const QStringList list = dialog->getNewMeasurementNames();
1500  if (ui->tableWidget->currentRow() == -1)
1501  {
1502  currentRow = ui->tableWidget->rowCount() + list.size() - 1;
1503  for (int i = 0; i < list.size(); ++i)
1504  {
1506  {
1507  individualMeasurements->addEmpty(list.at(i), qApp->TrVars()->MFormula(list.at(i)));
1508  }
1509  else
1510  {
1511  individualMeasurements->addEmpty(list.at(i));
1512  }
1513 
1514  search->AddRow(currentRow);
1515  }
1516  }
1517  else
1518  {
1519  currentRow = ui->tableWidget->currentRow() + list.size();
1520  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
1521  QString after = nameField->data(Qt::UserRole).toString();
1522  for (int i = 0; i < list.size(); ++i)
1523  {
1525  {
1526  individualMeasurements->AddEmptyAfter(after, list.at(i), qApp->TrVars()->MFormula(list.at(i)));
1527  }
1528  else
1529  {
1530  individualMeasurements->AddEmptyAfter(after, list.at(i));
1531  }
1532  search->AddRow(currentRow);
1533  after = list.at(i);
1534  }
1535  }
1536 
1537  RefreshData();
1538  search->RefreshList(ui->lineEditFind->text());
1539 
1540  ui->tableWidget->selectRow(currentRow);
1541 
1542  ui->actionExportToCSV->setEnabled(true);
1543 
1544  MeasurementsWasSaved(false);
1545  }
1546 }
1547 
1548 //---------------------------------------------------------------------------------------------------------------------
1550 {
1551  if (individualMeasurements == nullptr)
1552  {
1553  return;
1554  }
1555 
1556  const QString filter(tr("Pattern files (*.val)"));
1557  //Use standard path to individual measurements
1558  QString pathTo = qApp->SeamlyMeSettings()->GetPathTemplate();
1560 
1561  const QString mPath = QFileDialog::getOpenFileName(this, tr("Import from a pattern"), pathTo, filter);
1562  if (mPath.isEmpty())
1563  {
1564  return;
1565  }
1566 
1567  VLockGuard<char> tmp(mPath);
1568  if (not tmp.IsLocked())
1569  {
1570  qCCritical(tMainWindow, "%s", qUtf8Printable(tr("This file already opened in another window.")));
1571  return;
1572  }
1573 
1574  QStringList measurements;
1575  try
1576  {
1577  VPatternConverter converter(mPath);
1578  QScopedPointer<VLitePattern> doc(new VLitePattern());
1579  doc->setXMLContent(converter.Convert());
1580  measurements = doc->ListMeasurements();
1581  }
1582  catch (VException &e)
1583  {
1584  qCCritical(tMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
1585  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
1586  return;
1587  }
1588 
1589  measurements = FilterMeasurements(measurements, individualMeasurements->ListAll());
1590 
1591  qint32 currentRow;
1592 
1593  if (ui->tableWidget->currentRow() == -1)
1594  {
1595  currentRow = ui->tableWidget->rowCount() + measurements.size() - 1;
1596  for (int i = 0; i < measurements.size(); ++i)
1597  {
1598  individualMeasurements->addEmpty(measurements.at(i));
1599  }
1600  }
1601  else
1602  {
1603  currentRow = ui->tableWidget->currentRow() + measurements.size();
1604  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
1605  QString after = nameField->data(Qt::UserRole).toString();
1606  for (int i = 0; i < measurements.size(); ++i)
1607  {
1608  individualMeasurements->AddEmptyAfter(after, measurements.at(i));
1609  after = measurements.at(i);
1610  }
1611  }
1612 
1613  RefreshData();
1614 
1615  search->RefreshList(ui->lineEditFind->text());
1616 
1617  ui->tableWidget->selectRow(currentRow);
1618 
1619  MeasurementsWasSaved(false);
1620 }
1621 
1622 //---------------------------------------------------------------------------------------------------------------------
1624 {
1625  const int row = ui->tableWidget->currentRow();
1626  currentSize = gradationSizes->itemText(index).toInt();
1627  RefreshData();
1628  search->RefreshList(ui->lineEditFind->text());
1629  ui->tableWidget->selectRow(row);
1630 }
1631 
1632 //---------------------------------------------------------------------------------------------------------------------
1634 {
1635  const int row = ui->tableWidget->currentRow();
1636  currentHeight = gradationHeights->itemText(index).toInt();
1637  RefreshData();
1638  search->RefreshList(ui->lineEditFind->text());
1639  ui->tableWidget->selectRow(row);
1640 }
1641 
1642 //---------------------------------------------------------------------------------------------------------------------
1644 {
1645  ShowNewMData(true);
1646 }
1647 
1648 //---------------------------------------------------------------------------------------------------------------------
1650 {
1651  if (ui->tableWidget->rowCount() > 0)
1652  {
1653  MFields(true);
1654 
1655  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName); // name
1657 
1658  try
1659  {
1660  // Translate to internal look.
1661  meash = data->GetVariable<VMeasurement>(nameField->data(Qt::UserRole).toString());
1662  }
1663  catch(const VExceptionBadId &e)
1664  {
1665  Q_UNUSED(e)
1666  MFields(false);
1667  return;
1668  }
1669 
1670  ShowMDiagram(meash->GetName());
1671 
1672  // Don't block all signal for QLineEdit. Need for correct handle with clear button.
1673  disconnect(ui->lineEditName, &QLineEdit::textEdited, this, &TMainWindow::SaveMName);
1674  ui->plainTextEditDescription->blockSignals(true);
1675  if (meash->isCustom())
1676  {
1677  ui->plainTextEditDescription->setPlainText(meash->GetDescription());
1678  ui->lineEditFullName->setText(meash->getGuiText());
1679  ui->lineEditName->setText(ClearCustomName(meash->GetName()));
1680  }
1681  else
1682  {
1683  //Show known
1684  ui->plainTextEditDescription->setPlainText(qApp->TrVars()->Description(meash->GetName()));
1685  ui->lineEditFullName->setText(qApp->TrVars()->guiText(meash->GetName()));
1686  ui->lineEditName->setText(nameField->text());
1687  }
1688  connect(ui->lineEditName, &QLineEdit::textEdited, this, &TMainWindow::SaveMName);
1689  ui->plainTextEditDescription->blockSignals(false);
1690 
1692  {
1693  ui->labelCalculatedValue->blockSignals(true);
1694  ui->doubleSpinBoxBaseValue->blockSignals(true);
1695  ui->doubleSpinBoxInSizes->blockSignals(true);
1696  ui->doubleSpinBoxInHeights->blockSignals(true);
1697 
1698  const QString postfix = UnitsToStr(pUnit);//Show unit in dialog label (cm, mm or inch)
1699  const qreal value = UnitConvertor(*data->DataVariables()->value(meash->GetName())->GetValue(), mUnit,
1700  pUnit);
1701  ui->labelCalculatedValue->setText(qApp->LocaleToString(value) + " " +postfix);
1702 
1703  if (fresh)
1704  {
1705  ui->doubleSpinBoxBaseValue->setValue(meash->GetBase());
1706  ui->doubleSpinBoxInSizes->setValue(meash->GetKsize());
1707  ui->doubleSpinBoxInHeights->setValue(meash->GetKheight());
1708  }
1709 
1710  ui->labelCalculatedValue->blockSignals(false);
1711  ui->doubleSpinBoxBaseValue->blockSignals(false);
1712  ui->doubleSpinBoxInSizes->blockSignals(false);
1713  ui->doubleSpinBoxInHeights->blockSignals(false);
1714  }
1715  else
1716  {
1717  EvalFormula(meash->GetFormula(), false, meash->GetData(), ui->labelCalculatedValue);
1718 
1719  ui->plainTextEditFormula->blockSignals(true);
1720 
1721  QString formula;
1722  try
1723  {
1724  formula = qApp->TrVars()->FormulaToUser(meash->GetFormula(), qApp->Settings()->GetOsSeparator());
1725  }
1726  catch (qmu::QmuParserError &e)
1727  {
1728  Q_UNUSED(e)
1729  formula = meash->GetFormula();
1730  }
1731 
1732  ui->plainTextEditFormula->setPlainText(formula);
1733  ui->plainTextEditFormula->blockSignals(false);
1734  }
1735 
1736  MeasurementGUI();
1737  }
1738  else
1739  {
1740  MFields(false);
1741  }
1742 }
1743 
1744 //---------------------------------------------------------------------------------------------------------------------
1745 QString TMainWindow::getMeasurementNumber(const QString &name)
1746 {
1747  return qApp->TrVars()->MNumber(name);
1748 }
1749 
1750 //---------------------------------------------------------------------------------------------------------------------
1751 void TMainWindow::ShowMDiagram(const QString &name)
1752 {
1753  const VTranslateVars *trv = qApp->TrVars();
1754  const QString number = trv->MNumber(name);
1755 
1756  if (number.isEmpty())
1757  {
1758  ui->labelDiagram->setText(tr("<html><head/><body><p><span style=\" font-size:340pt;\">?</span></p>"
1759  "<p align=\"center\">Unknown measurement</p></body></html>"));
1760  }
1761  else
1762  {
1763  ui->labelDiagram->setText(QString("<html><head/><body><p align=\"center\">%1</p>"
1764  "<p align=\"center\"><b>%2</b>. <i>%3</i></p></body></html>")
1765  .arg(MeasurementDatabaseDialog::imageUrl(number), number, trv->guiText(name)));
1766  }
1767  // This part is very ugly, can't find better way to resize dockWidget.
1768  ui->labelDiagram->adjustSize();
1769  // And also those 50 px. DockWidget has some border. And i can't find how big it is.
1770  // Can lead to problem in future.
1771  ui->dockWidgetDiagram->setMaximumWidth(ui->labelDiagram->width()+50);
1772 }
1773 
1774 //---------------------------------------------------------------------------------------------------------------------
1776 {
1777  SCASSERT(ui->plainTextEditFormula != nullptr)
1778  SCASSERT(ui->pushButtonGrow != nullptr)
1779 
1780  const QTextCursor cursor = ui->plainTextEditFormula->textCursor();
1781 
1782  if (ui->plainTextEditFormula->height() < DIALOG_MAX_FORMULA_HEIGHT)
1783  {
1784  ui->plainTextEditFormula->setFixedHeight(DIALOG_MAX_FORMULA_HEIGHT);
1785  //Set icon from theme (internal for Windows system)
1786  ui->pushButtonGrow->setIcon(QIcon::fromTheme("go-next",
1787  QIcon(":/icons/win.icon.theme/16x16/actions/go-next.png")));
1788  }
1789  else
1790  {
1791  ui->plainTextEditFormula->setFixedHeight(formulaBaseHeight);
1792  //Set icon from theme (internal for Windows system)
1793  ui->pushButtonGrow->setIcon(QIcon::fromTheme("go-down",
1794  QIcon(":/icons/win.icon.theme/16x16/actions/go-down.png")));
1795  }
1796 
1797  // I found that after change size of formula field, it was filed for angle formula, field for formula became black.
1798  // This code prevent this.
1799  setUpdatesEnabled(false);
1800  repaint();
1801  setUpdatesEnabled(true);
1802 
1803  ui->plainTextEditFormula->setFocus();
1804  ui->plainTextEditFormula->setTextCursor(cursor);
1805 }
1806 
1807 //---------------------------------------------------------------------------------------------------------------------
1808 void TMainWindow::SaveMName(const QString &text)
1809 {
1810  const int row = ui->tableWidget->currentRow();
1811 
1812  if (row == -1)
1813  {
1814  return;
1815  }
1816 
1817  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
1818 
1820 
1821  try
1822  {
1823  // Translate to internal look.
1824  meash = data->GetVariable<VMeasurement>(nameField->data(Qt::UserRole).toString());
1825  }
1826  catch(const VExceptionBadId &e)
1827  {
1828  qCWarning(tMainWindow, "%s\n\n%s\n\n%s",
1829  qUtf8Printable(tr("Can't find measurement '%1'.").arg(nameField->text())),
1830  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
1831  return;
1832  }
1833 
1834  QString newName = text;
1835 
1836  if (meash->isCustom())
1837  {
1838  newName.isEmpty() ? newName = GetCustomName() : newName = CustomMSign + newName;
1839 
1840  if (not data->IsUnique(newName))
1841  {
1842  qint32 num = 2;
1843  QString name = newName;
1844  do
1845  {
1846  name = name + QLatin1String("_") + QString().number(num);
1847  num++;
1848  } while (not data->IsUnique(name));
1849  newName = name;
1850  }
1851 
1852  individualMeasurements->SetMName(nameField->text(), newName);
1853  MeasurementsWasSaved(false);
1854  RefreshData();
1855  search->RefreshList(ui->lineEditFind->text());
1856 
1857  ui->tableWidget->blockSignals(true);
1858  ui->tableWidget->selectRow(row);
1859  ui->tableWidget->blockSignals(false);
1860  }
1861  else
1862  {
1863  qCWarning(tMainWindow, "%s", qUtf8Printable(tr("The name of known measurement forbidden to change.")));
1864  }
1865 }
1866 
1867 //---------------------------------------------------------------------------------------------------------------------
1869 {
1870  const int row = ui->tableWidget->currentRow();
1871 
1872  if (row == -1)
1873  {
1874  return;
1875  }
1876 
1877  const QTableWidgetItem *nameField = ui->tableWidget->item(row, ColumnName);
1878 
1879  // Replace line return character with spaces for calc if exist
1880  QString text = ui->plainTextEditFormula->toPlainText();
1881  text.replace("\n", " ");
1882 
1883  QTableWidgetItem *formulaField = ui->tableWidget->item(row, ColumnFormula);
1884  if (formulaField->text() == text)
1885  {
1886  QTableWidgetItem *result = ui->tableWidget->item(row, ColumnCalcValue);
1887  const QString postfix = UnitsToStr(mUnit);//Show unit in dialog label (cm, mm or inch)
1888  ui->labelCalculatedValue->setText(result->text() + " " +postfix);
1889  return;
1890  }
1891 
1892  if (text.isEmpty())
1893  {
1894  const QString postfix = UnitsToStr(mUnit);//Show unit in dialog label (cm, mm or inch)
1895  ui->labelCalculatedValue->setText(tr("Error") + " (" + postfix + "). " + tr("Empty field."));
1896  return;
1897  }
1898 
1900  try
1901  {
1902  // Translate to internal look.
1903  meash = data->GetVariable<VMeasurement>(nameField->data(Qt::UserRole).toString());
1904  }
1905  catch(const VExceptionBadId & e)
1906  {
1907  qCWarning(tMainWindow, "%s\n\n%s\n\n%s",
1908  qUtf8Printable(tr("Can't find measurement '%1'.").arg(nameField->text())),
1909  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
1910  return;
1911  }
1912 
1913  if (not EvalFormula(text, true, meash->GetData(), ui->labelCalculatedValue))
1914  {
1915  return;
1916  }
1917 
1918  try
1919  {
1920  const QString formula = qApp->TrVars()->FormulaFromUser(text, qApp->Settings()->GetOsSeparator());
1921  individualMeasurements->SetMValue(nameField->data(Qt::UserRole).toString(), formula);
1922  }
1923  catch (qmu::QmuParserError &e) // Just in case something bad will happen
1924  {
1925  Q_UNUSED(e)
1926  return;
1927  }
1928 
1929  MeasurementsWasSaved(false);
1930 
1931  const QTextCursor cursor = ui->plainTextEditFormula->textCursor();
1932 
1933  RefreshData();
1934  search->RefreshList(ui->lineEditFind->text());
1935 
1936  ui->tableWidget->blockSignals(true);
1937  ui->tableWidget->selectRow(row);
1938  ui->tableWidget->blockSignals(false);
1939 
1940  ui->plainTextEditFormula->setTextCursor(cursor);
1941 }
1942 
1943 //---------------------------------------------------------------------------------------------------------------------
1945 {
1946  const int row = ui->tableWidget->currentRow();
1947 
1948  if (row == -1)
1949  {
1950  return;
1951  }
1952 
1953  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
1954  individualMeasurements->SetMBaseValue(nameField->data(Qt::UserRole).toString(), value);
1955 
1956  MeasurementsWasSaved(false);
1957 
1958  RefreshData();
1959  search->RefreshList(ui->lineEditFind->text());
1960 
1961  ui->tableWidget->blockSignals(true);
1962  ui->tableWidget->selectRow(row);
1963  ui->tableWidget->blockSignals(false);
1964 
1965  ShowNewMData(false);
1966 }
1967 
1968 //---------------------------------------------------------------------------------------------------------------------
1970 {
1971  const int row = ui->tableWidget->currentRow();
1972 
1973  if (row == -1)
1974  {
1975  return;
1976  }
1977 
1978  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
1979  individualMeasurements->SetMSizeIncrease(nameField->data(Qt::UserRole).toString(), value);
1980 
1981  MeasurementsWasSaved(false);
1982 
1983  RefreshData();
1984  search->RefreshList(ui->lineEditFind->text());
1985 
1986  ui->tableWidget->blockSignals(true);
1987  ui->tableWidget->selectRow(row);
1988  ui->tableWidget->blockSignals(false);
1989 
1990  ShowNewMData(false);
1991 }
1992 
1993 //---------------------------------------------------------------------------------------------------------------------
1995 {
1996  const int row = ui->tableWidget->currentRow();
1997 
1998  if (row == -1)
1999  {
2000  return;
2001  }
2002 
2003  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
2004  individualMeasurements->SetMHeightIncrease(nameField->data(Qt::UserRole).toString(), value);
2005 
2006  MeasurementsWasSaved(false);
2007 
2008  RefreshData();
2009  search->RefreshList(ui->lineEditFind->text());
2010 
2011  ui->tableWidget->blockSignals(true);
2012  ui->tableWidget->selectRow(row);
2013  ui->tableWidget->blockSignals(false);
2014 
2015  ShowNewMData(false);
2016 }
2017 
2018 //---------------------------------------------------------------------------------------------------------------------
2020 {
2021  const int row = ui->tableWidget->currentRow();
2022 
2023  if (row == -1)
2024  {
2025  return;
2026  }
2027 
2028  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
2029  individualMeasurements->SetMDescription(nameField->data(Qt::UserRole).toString(), ui->plainTextEditDescription->toPlainText());
2030 
2031  MeasurementsWasSaved(false);
2032 
2033  const QTextCursor cursor = ui->plainTextEditDescription->textCursor();
2034 
2035  RefreshData();
2036 
2037  ui->tableWidget->blockSignals(true);
2038  ui->tableWidget->selectRow(row);
2039  ui->tableWidget->blockSignals(false);
2040 
2041  ui->plainTextEditDescription->setTextCursor(cursor);
2042 }
2043 
2044 
2045 //---------------------------------------------------------------------------------------------------------------------
2047 {
2048  const int row = ui->tableWidget->currentRow();
2049 
2050  if (row == -1)
2051  {
2052  return;
2053  }
2054 
2055  const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName);
2056 
2058 
2059  try
2060  {
2061  // Translate to internal look.
2062  meash = data->GetVariable<VMeasurement>(nameField->data(Qt::UserRole).toString());
2063  }
2064  catch(const VExceptionBadId &e)
2065  {
2066  qCWarning(tMainWindow, "%s\n\n%s\n\n%s",
2067  qUtf8Printable(tr("Can't find measurement '%1'.").arg(nameField->text())),
2068  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
2069  return;
2070  }
2071 
2072  if (meash->isCustom())
2073  {
2074  individualMeasurements->SetMFullName(nameField->data(Qt::UserRole).toString(), ui->lineEditFullName->text());
2075 
2076  MeasurementsWasSaved(false);
2077 
2078  RefreshData();
2079 
2080  ui->tableWidget->blockSignals(true);
2081  ui->tableWidget->selectRow(row);
2082  ui->tableWidget->blockSignals(false);
2083  }
2084  else
2085  {
2086  qCWarning(tMainWindow, "%s", qUtf8Printable(tr("The full name of known measurement forbidden to change.")));
2087  }
2088 }
2089 
2090 //---------------------------------------------------------------------------------------------------------------------
2092 {
2093  pUnit = static_cast<Unit>(comboBoxUnits->itemData(index).toInt());
2094 
2096 }
2097 
2098 //---------------------------------------------------------------------------------------------------------------------
2100 {
2101  // File
2102  connect(ui->actionNew, &QAction::triggered, this, &TMainWindow::FileNew);
2103  connect(ui->actionOpenIndividual, &QAction::triggered, this, &TMainWindow::OpenIndividual);
2104  connect(ui->actionOpenMultisize, &QAction::triggered, this, &TMainWindow::OpenMultisize);
2105  connect(ui->actionOpenTemplate, &QAction::triggered, this, &TMainWindow::OpenTemplate);
2106  connect(ui->actionCreateFromExisting, &QAction::triggered, this, &TMainWindow::CreateFromExisting);
2107  connect(ui->print_Action, &QAction::triggered, this, &TMainWindow::print);
2108  connect(ui->actionSave, &QAction::triggered, this, &TMainWindow::FileSave);
2109  connect(ui->actionSaveAs, &QAction::triggered, this, &TMainWindow::FileSaveAs);
2110  connect(ui->actionExportToCSV, &QAction::triggered, this, &TMainWindow::handleExportToCSV);
2111  connect(ui->actionReadOnly, &QAction::triggered, this, [this](bool ro)
2112  {
2113  if (not mIsReadOnly)
2114  {
2115  individualMeasurements->SetReadOnly(ro);
2116  MeasurementsWasSaved(false);
2117  UpdatePadlock(ro);
2118  UpdateWindowTitle();
2119  }
2120  else
2121  {
2122  if (QAction *action = qobject_cast< QAction * >(this->sender()))
2123  {
2124  action->setChecked(true);
2125  }
2126  }
2127  });
2128  connect(ui->actionPreferences, &QAction::triggered, this, &TMainWindow::Preferences);
2129 
2130  for (int i = 0; i < MaxRecentFiles; ++i)
2131  {
2132  QAction *action = new QAction(this);
2133  recentFileActs[i] = action;
2134  connect(action, &QAction::triggered, this, [this]()
2135  {
2136  QAction *action = qobject_cast<QAction *>(sender());
2137  if (action)
2138  {
2139  const QString filePath = action->data().toString();
2140  if (not filePath.isEmpty())
2141  {
2142  LoadFile(filePath);
2143  }
2144  }
2145  });
2146  ui->menuFile->insertAction(ui->actionPreferences, recentFileActs[i]);
2147  recentFileActs[i]->setVisible(false);
2148  }
2149 
2150  separatorAct = new QAction(this);
2151  separatorAct->setSeparator(true);
2152  separatorAct->setVisible(false);
2153  ui->menuFile->insertAction(ui->actionPreferences, separatorAct );
2154 
2155 
2156  connect(ui->actionQuit, &QAction::triggered, this, &TMainWindow::close);
2157 
2158  // Measurements
2159  connect(ui->actionAddCustom, &QAction::triggered, this, &TMainWindow::AddCustom);
2160  connect(ui->actionAddKnown, &QAction::triggered, this, &TMainWindow::AddKnown);
2161  connect(ui->actionDatabase, &QAction::triggered, qApp, &MApplication::ShowDataBase);
2162  connect(ui->actionImportFromPattern, &QAction::triggered, this, &TMainWindow::ImportFromPattern);
2163  actionDockDiagram = ui->dockWidgetDiagram->toggleViewAction();
2164  actionDockDiagram->setMenuRole(QAction::NoRole);
2165  ui->measurements_Menu->addAction(actionDockDiagram);
2166  ui->mainToolBar->addAction(actionDockDiagram);
2167  actionDockDiagram->setEnabled(false);
2168  actionDockDiagram->setIcon(QIcon("://seamlymeicon/24x24/mannequin.png"));
2169 
2170  // Window
2171  connect(ui->window_Menu, &QMenu::aboutToShow, this, &TMainWindow::AboutToShowWindowMenu);
2172  AboutToShowWindowMenu();
2173 
2174  // Help
2175  connect(ui->shortcuts_Action, &QAction::triggered, this, [this]()
2176  {
2177  MeShortcutsDialog *shortcutsDialog = new MeShortcutsDialog(this);
2178  shortcutsDialog->setAttribute(Qt::WA_DeleteOnClose, true);
2179  shortcutsDialog->show();
2180  });
2181  connect(ui->actionAboutQt, &QAction::triggered, this, [this]()
2182  {
2183  QMessageBox::aboutQt(this, tr("About Qt"));
2184  });
2185  connect(ui->actionAboutSeamlyMe, &QAction::triggered, this, [this]()
2186  {
2187  DialogAboutSeamlyMe *aboutDialog = new DialogAboutSeamlyMe(this);
2188  aboutDialog->setAttribute(Qt::WA_DeleteOnClose, true);
2189  aboutDialog->show();
2190  });
2191 
2192  //Actions for recent files loaded by a seamlyme window application.
2193  UpdateRecentFileActions();
2194 
2195 }
2196 
2197 //---------------------------------------------------------------------------------------------------------------------
2199 {
2200  SCASSERT(individualMeasurements != nullptr)
2201  ui->labelToolTip->setVisible(false);
2202  ui->tabWidget->setVisible(true);
2203  ui->dockWidgetDiagram->setVisible(dockDiagramVisible);
2204  actionDockDiagram->setEnabled(true);
2205  ui->tabWidget->setCurrentIndex(0);
2206 
2207  ui->plainTextEditNotes->setEnabled(true);
2208  ui->toolBarGradation->setVisible(true);
2209 
2211  {
2212  ui->labelMType->setText(tr("Multisize measurements"));
2213  ui->labelBaseSizeValue->setText(QString().setNum(individualMeasurements->BaseSize()) + " " +
2215  ui->labelBaseHeightValue->setText(QString().setNum(individualMeasurements->BaseHeight()) + " " +
2217 
2218  // Because Qt Designer doesn't know about our deleting we will create empty objects for correct
2219  // working the retranslation UI
2220  // Tab Measurements
2221  HackWidget(&ui->horizontalLayoutValue);
2222  HackWidget(&ui->plainTextEditFormula);
2223  HackWidget(&ui->toolButtonExpr);
2224  HackWidget(&ui->labelFormula);
2225  HackWidget(&ui->pushButtonGrow);
2226 
2227  // Tab Information
2228  HackWidget(&ui->lineEditGivenName);
2229  HackWidget(&ui->lineEditFamilyName);
2230  HackWidget(&ui->comboBoxGender);
2231  HackWidget(&ui->lineEditEmail);
2232  HackWidget(&ui->labelGivenName);
2233  HackWidget(&ui->labelFamilyName);
2234  HackWidget(&ui->labelBirthDate);
2235  HackWidget(&ui->dateEditBirthDate);
2236  HackWidget(&ui->labelGender);
2237  HackWidget(&ui->labelEmail);
2238 
2239  const QStringList listHeights = VMeasurement::WholeListHeights(mUnit);
2240  const QStringList listSizes = VMeasurement::WholeListSizes(mUnit);
2241 
2242  labelGradationHeights = new QLabel(tr("Height:"));
2244  SetDefaultHeight(static_cast<int>(VContainer::height()));
2245  connect(gradationHeights, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
2247 
2248  labelGradationSizes = new QLabel(tr("Size:"));
2250  SetDefaultSize(static_cast<int>(VContainer::size()));
2251  connect(gradationSizes, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
2252  this, &TMainWindow::ChangedSize);
2253 
2254  connect(ui->doubleSpinBoxBaseValue,
2255  static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
2257  connect(ui->doubleSpinBoxInSizes,
2258  static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
2260  connect(ui->doubleSpinBoxInHeights,
2261  static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
2263 
2264  SetDecimals();
2265  }
2266  else
2267  {
2268  ui->labelMType->setText(tr("Individual measurements"));
2269 
2270  ui->lineEditGivenName->setEnabled(true);
2271  ui->lineEditFamilyName->setEnabled(true);
2272  ui->dateEditBirthDate->setEnabled(true);
2273  ui->comboBoxGender->setEnabled(true);
2274  ui->lineEditEmail->setEnabled(true);
2275 
2276  // Tab Measurements
2277  HackWidget(&ui->doubleSpinBoxBaseValue);
2278  HackWidget(&ui->doubleSpinBoxInSizes);
2279  HackWidget(&ui->doubleSpinBoxInHeights);
2280  HackWidget(&ui->labelBaseValue);
2281  HackWidget(&ui->labelInSizes);
2282  HackWidget(&ui->labelInHeights);
2283 
2284  // Tab Information
2285  HackWidget(&ui->labelBaseSize);
2286  HackWidget(&ui->labelBaseSizeValue);
2287  HackWidget(&ui->labelBaseHeight);
2288  HackWidget(&ui->labelBaseHeightValue);
2289 
2290  ui->lineEditGivenName->setText(individualMeasurements->GivenName());
2291  ui->lineEditFamilyName->setText(individualMeasurements->FamilyName());
2292 
2293  ui->comboBoxGender->clear();
2294  InitGender(ui->comboBoxGender);
2295  const qint32 index = ui->comboBoxGender->findData(static_cast<int>(individualMeasurements->Gender()));
2296  ui->comboBoxGender->setCurrentIndex(index);
2297 
2298  {
2299  const QLocale dateLocale = QLocale(qApp->Settings()->GetLocale());
2300  ui->dateEditBirthDate->setLocale(dateLocale);
2301  ui->dateEditBirthDate->setDisplayFormat(dateLocale.dateFormat());
2302  ui->dateEditBirthDate->setDate(individualMeasurements->BirthDate());
2303  }
2304 
2305  ui->lineEditEmail->setText(individualMeasurements->Email());
2306 
2307  connect(ui->lineEditGivenName, &QLineEdit::editingFinished, this, &TMainWindow::SaveGivenName);
2308  connect(ui->lineEditFamilyName, &QLineEdit::editingFinished, this, &TMainWindow::SaveFamilyName);
2309  connect(ui->lineEditEmail, &QLineEdit::editingFinished, this, &TMainWindow::SaveEmail);
2310  connect(ui->comboBoxGender, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
2312  connect(ui->dateEditBirthDate, &QDateEdit::dateChanged, this, &TMainWindow::SaveBirthDate);
2313  connect(ui->pushButtonGrow, &QPushButton::clicked, this, &TMainWindow::DeployFormula);
2314 
2315  this->formulaBaseHeight = ui->plainTextEditFormula->height();
2316  connect(ui->plainTextEditFormula, &QPlainTextEdit::textChanged, this, &TMainWindow::SaveMValue,
2317  Qt::UniqueConnection);
2318 
2319  connect(ui->toolButtonExpr, &QToolButton::clicked, this, &TMainWindow::Fx);
2320  }
2321 
2322  ui->comboBoxPMSystem->setEnabled(true);
2323  ui->comboBoxPMSystem->clear();
2324  InitPMSystems(ui->comboBoxPMSystem);
2325  const qint32 index = ui->comboBoxPMSystem->findData(QLatin1Char('p')+individualMeasurements->PMSystem());
2326  ui->comboBoxPMSystem->setCurrentIndex(index);
2327  connect(ui->comboBoxPMSystem, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
2329 
2330  connect(ui->lineEditFind, &QLineEdit::textChanged, [this] (const QString &term){search->Find(term);});
2331  connect(ui->toolButtonFindPrevious, &QToolButton::clicked, [this] (){search->FindPrevious();});
2332  connect(ui->toolButtonFindNext, &QToolButton::clicked, [this] (){search->FindNext();});
2333 
2334  connect(search.data(), &VTableSearch::HasResult, this, [this] (bool state)
2335  {
2336  ui->toolButtonFindPrevious->setEnabled(state);
2337  });
2338  connect(ui->clipboard_ToolButton, &QToolButton::clicked, this, &TMainWindow::copyToClipboard);
2339  connect(search.data(), &VTableSearch::HasResult, this, [this] (bool state)
2340  {
2341  ui->toolButtonFindNext->setEnabled(state);
2342  });
2343 
2344  ui->plainTextEditNotes->setPlainText(individualMeasurements->Notes());
2345  connect(ui->plainTextEditNotes, &QPlainTextEdit::textChanged, this, &TMainWindow::SaveNotes);
2346 
2347  ui->actionAddCustom->setEnabled(true);
2348  ui->actionAddKnown->setEnabled(true);
2349  ui->actionImportFromPattern->setEnabled(true);
2350  ui->actionSaveAs->setEnabled(true);
2351 
2352  ui->lineEditName->setValidator(new QRegularExpressionValidator(QRegularExpression(
2353  QLatin1String("^$|")+NameRegExp()),
2354  this));
2355 
2356  connect(ui->toolButtonRemove, &QToolButton::clicked, this, &TMainWindow::Remove);
2357  connect(ui->toolButtonTop, &QToolButton::clicked, this, &TMainWindow::MoveTop);
2358  connect(ui->toolButtonUp, &QToolButton::clicked, this, &TMainWindow::MoveUp);
2359  connect(ui->toolButtonDown, &QToolButton::clicked, this, &TMainWindow::MoveDown);
2360  connect(ui->toolButtonBottom, &QToolButton::clicked, this, &TMainWindow::MoveBottom);
2361 
2362  connect(ui->lineEditName, &QLineEdit::textEdited, this, &TMainWindow::SaveMName);
2363  connect(ui->plainTextEditDescription, &QPlainTextEdit::textChanged, this, &TMainWindow::SaveMDescription);
2364  connect(ui->lineEditFullName, &QLineEdit::textEdited, this, &TMainWindow::SaveMFullName);
2365 
2366  connect(ui->pushButtonShowInExplorer, &QPushButton::clicked, this, [this]()
2367  {
2368  ShowInGraphicalShell(curFile);
2369  });
2370 
2371  InitUnits();
2372 
2373  InitTable();
2374 }
2375 
2376 //---------------------------------------------------------------------------------------------------------------------
2378 {
2380  {
2381  ui->tableWidget->setColumnHidden( ColumnFormula, true );// formula
2382  }
2383  else
2384  {
2385  ui->tableWidget->setColumnHidden( ColumnBaseValue, true );// base value
2386  ui->tableWidget->setColumnHidden( ColumnInSizes, true );// in sizes
2387  ui->tableWidget->setColumnHidden( ColumnInHeights, true );// in heights
2388  }
2389 
2390  connect(ui->tableWidget, &QTableWidget::itemSelectionChanged, this, &TMainWindow::ShowMData);
2391 
2392  ShowUnits();
2393 
2394  ui->tableWidget->resizeColumnsToContents();
2395  ui->tableWidget->resizeRowsToContents();
2396  ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
2397 }
2398 
2399 //---------------------------------------------------------------------------------------------------------------------
2401 {
2402  const QString unit = UnitsToStr(mUnit);
2403 
2404  ShowHeaderUnits(ui->tableWidget, ColumnCalcValue, UnitsToStr(pUnit));// calculated value
2405  ShowHeaderUnits(ui->tableWidget, ColumnFormula, unit);// formula
2406  ShowHeaderUnits(ui->tableWidget, ColumnBaseValue, unit);// base value
2407  ShowHeaderUnits(ui->tableWidget, ColumnInSizes, unit);// in sizes
2408  ShowHeaderUnits(ui->tableWidget, ColumnInHeights, unit);// in heights
2409 }
2410 
2411 //---------------------------------------------------------------------------------------------------------------------
2412 void TMainWindow::ShowHeaderUnits(QTableWidget *table, int column, const QString &unit)
2413 {
2414  SCASSERT(table != nullptr)
2415 
2416  QString header = table->horizontalHeaderItem(column)->text();
2417  const int index = header.indexOf(QLatin1String("("));
2418  if (index != -1)
2419  {
2420  header.remove(index-1, 100);
2421  }
2422  const QString unitHeader = QString("%1 (%2)").arg(header, unit);
2423  table->horizontalHeaderItem(column)->setText(unitHeader);
2424 }
2425 
2426 //---------------------------------------------------------------------------------------------------------------------
2428 {
2429  setWindowModified(!saved);
2430  not mIsReadOnly ? ui->actionSave->setEnabled(!saved): ui->actionSave->setEnabled(false);
2431 }
2432 
2433 //---------------------------------------------------------------------------------------------------------------------
2434 void TMainWindow::SetCurrentFile(const QString &fileName)
2435 {
2436  curFile = fileName;
2437  if (curFile.isEmpty())
2438  {
2439  ui->lineEditPathToFile->setText(QLatin1String("<") + tr("Empty") + QLatin1String(">"));
2440  ui->lineEditPathToFile->setToolTip(tr("File was not saved yet."));
2441  ui->lineEditPathToFile->setCursorPosition(0);
2442  ui->pushButtonShowInExplorer->setEnabled(false);
2443  }
2444  else
2445  {
2446  ui->lineEditPathToFile->setText(QDir::toNativeSeparators(curFile));
2447  ui->lineEditPathToFile->setToolTip(QDir::toNativeSeparators(curFile));
2448  ui->lineEditPathToFile->setCursorPosition(0);
2449  ui->pushButtonShowInExplorer->setEnabled(true);
2450  auto settings = qApp->SeamlyMeSettings();
2451  QStringList files = settings->GetRecentFileList();
2452  files.removeAll(fileName);
2453  files.prepend(fileName);
2454  while (files.size() > MaxRecentFiles)
2455  {
2456  files.removeLast();
2457  }
2458  settings->SetRecentFileList(files);
2460  }
2461 
2463 }
2464 
2465 //---------------------------------------------------------------------------------------------------------------------
2466 bool TMainWindow::SaveMeasurements(const QString &fileName, QString &error)
2467 {
2468  const bool result = individualMeasurements->SaveDocument(fileName, error);
2469  if (result)
2470  {
2471  SetCurrentFile(fileName);
2472  MeasurementsWasSaved(result);
2473  }
2474  return result;
2475 }
2476 
2477 //---------------------------------------------------------------------------------------------------------------------
2479 {
2480  if (this->isWindowModified())
2481  {
2482  if (curFile.isEmpty() && ui->tableWidget->rowCount() == 0)
2483  {
2484  return true;// Don't ask if file was created without modifications.
2485  }
2486 
2487  QScopedPointer<QMessageBox> messageBox(new QMessageBox(tr("Unsaved changes"),
2488  tr("Measurements have been modified.\n"
2489  "Do you want to save your changes?"),
2490  QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No,
2491  QMessageBox::Cancel, this, Qt::Sheet));
2492 
2493  messageBox->setDefaultButton(QMessageBox::Yes);
2494  messageBox->setEscapeButton(QMessageBox::Cancel);
2495 
2496  messageBox->setButtonText(QMessageBox::Yes, curFile.isEmpty() || mIsReadOnly ? tr("Save...") : tr("Save"));
2497  messageBox->setButtonText(QMessageBox::No, tr("Don't Save"));
2498 
2499  messageBox->setWindowModality(Qt::ApplicationModal);
2500  const QMessageBox::StandardButton ret = static_cast<QMessageBox::StandardButton>(messageBox->exec());
2501 
2502  switch (ret)
2503  {
2504  case QMessageBox::Yes:
2505  if (mIsReadOnly)
2506  {
2507  return FileSaveAs();
2508  }
2509  else
2510  {
2511  return FileSave();
2512  }
2513  case QMessageBox::No:
2514  return true;
2515  case QMessageBox::Cancel:
2516  return false;
2517  default:
2518  break;
2519  }
2520  }
2521  return true;
2522 }
2523 
2524 //---------------------------------------------------------------------------------------------------------------------
2525 QTableWidgetItem *TMainWindow::AddCell(const QString &text, int row, int column, int aligment, bool ok)
2526 {
2527  QTableWidgetItem *item = new QTableWidgetItem(text);
2528  item->setTextAlignment(aligment);
2529  item->setToolTip(text);
2530 
2531  // set the item non-editable (view only), and non-selectable
2532  Qt::ItemFlags flags = item->flags();
2533  flags &= ~(Qt::ItemIsEditable); // reset/clear the flag
2534  item->setFlags(flags);
2535 
2536  if (not ok)
2537  {
2538  QBrush brush = item->foreground();
2539  brush.setColor(Qt::red);
2540  item->setForeground(brush);
2541  }
2542 
2543  ui->tableWidget->setItem(row, column, item);
2544 
2545  return item;
2546 }
2547 
2548 //---------------------------------------------------------------------------------------------------------------------
2549 QComboBox *TMainWindow::SetGradationList(QLabel *label, const QStringList &list)
2550 {
2551  ui->toolBarGradation->addWidget(label);
2552 
2553  QComboBox *comboBox = new QComboBox;
2554  comboBox->addItems(list);
2555  ui->toolBarGradation->addWidget(comboBox);
2556 
2557  return comboBox;
2558 }
2559 
2560 //---------------------------------------------------------------------------------------------------------------------
2562 {
2563  const qint32 index = gradationHeights->findText(QString("%1").arg(value));
2564  if (index != -1)
2565  {
2566  gradationHeights->setCurrentIndex(index);
2567  }
2568  else
2569  {
2570  currentHeight = gradationHeights->currentText().toInt();
2571  }
2572 }
2573 
2574 //---------------------------------------------------------------------------------------------------------------------
2576 {
2577  const qint32 index = gradationSizes->findText(QString("%1").arg(value));
2578  if (index != -1)
2579  {
2580  gradationSizes->setCurrentIndex(index);
2581  }
2582  else
2583  {
2584  currentSize = gradationSizes->currentText().toInt();
2585  }
2586 }
2587 
2588 //---------------------------------------------------------------------------------------------------------------------
2589 void TMainWindow::RefreshData(bool freshCall)
2590 {
2594 
2595  RefreshTable(freshCall);
2596 }
2597 
2598 //---------------------------------------------------------------------------------------------------------------------
2599 void TMainWindow::RefreshTable(bool freshCall)
2600 {
2601  ui->tableWidget->blockSignals(true);
2602  ui->tableWidget->clearContents();
2603 
2604  ShowUnits();
2605 
2608  QMap<QString, QSharedPointer<VMeasurement> >::const_iterator iterMap;
2609  for (iterMap = table.constBegin(); iterMap != table.constEnd(); ++iterMap)
2610  {
2611  QSharedPointer<VMeasurement> meash = iterMap.value();
2612  orderedTable.insert(meash->Index(), meash);
2613  }
2614 
2615  qint32 currentRow = -1;
2616  QMap<int, QSharedPointer<VMeasurement> >::const_iterator iMap;
2617  ui->tableWidget->setRowCount ( orderedTable.size() );
2618  for (iMap = orderedTable.constBegin(); iMap != orderedTable.constEnd(); ++iMap)
2619  {
2620  QSharedPointer<VMeasurement> meash = iMap.value();
2621  currentRow++;
2622 
2624  {
2625  QTableWidgetItem *item = AddCell(qApp->TrVars()->MToUser(meash->GetName()), currentRow, ColumnName,
2626  Qt::AlignVCenter); // name
2627  item->setData(Qt::UserRole, meash->GetName());
2628 
2629  if (meash->isCustom())
2630  {
2631  AddCell(QStringLiteral("na"), currentRow, ColumnNumber, Qt::AlignVCenter);
2632  AddCell(meash->getGuiText(), currentRow, ColumnFullName, Qt::AlignVCenter);
2633  }
2634  else
2635  {
2636 
2637  AddCell(getMeasurementNumber(meash->GetName()), currentRow, ColumnNumber, Qt::AlignVCenter);
2638  AddCell(qApp->TrVars()->guiText(meash->GetName()), currentRow, ColumnFullName, Qt::AlignVCenter);
2639  }
2640 
2641  const qreal value = UnitConvertor(*meash->GetValue(), mUnit, pUnit);
2642  AddCell(locale().toString(value), currentRow, ColumnCalcValue, Qt::AlignHCenter | Qt::AlignVCenter,
2643  meash->IsFormulaOk()); // calculated value
2644 
2645  QString formula;
2646  try
2647  {
2648  formula = qApp->TrVars()->FormulaToUser(meash->GetFormula(), qApp->Settings()->GetOsSeparator());
2649  }
2650  catch (qmu::QmuParserError &e)
2651  {
2652  Q_UNUSED(e)
2653  formula = meash->GetFormula();
2654  }
2655 
2656  AddCell(formula, currentRow, ColumnFormula, Qt::AlignVCenter); // formula
2657  }
2658  else
2659  {
2660  QTableWidgetItem *item = AddCell(qApp->TrVars()->MToUser(meash->GetName()), currentRow, 0,
2661  Qt::AlignVCenter); // name
2662  item->setData(Qt::UserRole, meash->GetName());
2663 
2664  if (meash->isCustom())
2665  {
2666  AddCell(QStringLiteral("na"), currentRow, ColumnNumber, Qt::AlignVCenter);
2667  AddCell(meash->getGuiText(), currentRow, ColumnFullName, Qt::AlignVCenter);
2668  }
2669  else
2670  {
2671  AddCell(getMeasurementNumber(meash->GetName()), currentRow, ColumnNumber, Qt::AlignVCenter);
2672  AddCell(qApp->TrVars()->guiText(meash->GetName()), currentRow, ColumnFullName, Qt::AlignVCenter);
2673  }
2674 
2675  const qreal value = UnitConvertor(*data->DataVariables()->value(meash->GetName())->GetValue(), mUnit,
2676  pUnit);
2677  AddCell(locale().toString(value), currentRow, ColumnCalcValue,
2678  Qt::AlignHCenter | Qt::AlignVCenter, meash->IsFormulaOk()); // calculated value
2679 
2680  AddCell(locale().toString(meash->GetBase()), currentRow, ColumnBaseValue,
2681  Qt::AlignHCenter | Qt::AlignVCenter); // base value
2682 
2683  AddCell(locale().toString(meash->GetKsize()), currentRow, ColumnInSizes,
2684  Qt::AlignHCenter | Qt::AlignVCenter); // in sizes
2685 
2686  AddCell(locale().toString(meash->GetKheight()), currentRow, ColumnInHeights,
2687  Qt::AlignHCenter | Qt::AlignVCenter); // in heights
2688  }
2689  }
2690 
2691  if (freshCall)
2692  {
2693  ui->tableWidget->resizeColumnsToContents();
2694  ui->tableWidget->resizeRowsToContents();
2695  }
2696  ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
2697  ui->tableWidget->blockSignals(false);
2698 
2699  if (ui->tableWidget->rowCount() > 0)
2700  {
2701  ui->actionExportToCSV->setEnabled(true);
2702  }
2703 }
2704 
2705 //---------------------------------------------------------------------------------------------------------------------
2707 {
2708  qint32 num = 1;
2709  QString name;
2710  do
2711  {
2712  name = CustomMSign + qApp->TrVars()->InternalVarToUser(measurement_) + QString().number(num);
2713  num++;
2714  } while (data->IsUnique(name) == false);
2715 
2716  return name;
2717 }
2718 
2719 //---------------------------------------------------------------------------------------------------------------------
2721 {
2722  if (ui->tableWidget->rowCount() > 0)
2723  {
2724  ui->toolButtonRemove->setEnabled(true);
2725  }
2726  else
2727  {
2728  ui->toolButtonRemove->setEnabled(false);
2729  }
2730 
2731  if (ui->tableWidget->rowCount() >= 2)
2732  {
2733  if (ui->tableWidget->currentRow() == 0)
2734  {
2735  ui->toolButtonTop->setEnabled(false);
2736  ui->toolButtonUp->setEnabled(false);
2737  ui->toolButtonDown->setEnabled(true);
2738  ui->toolButtonBottom->setEnabled(true);
2739  }
2740  else if (ui->tableWidget->currentRow() == ui->tableWidget->rowCount()-1)
2741  {
2742  ui->toolButtonTop->setEnabled(true);
2743  ui->toolButtonUp->setEnabled(true);
2744  ui->toolButtonDown->setEnabled(false);
2745  ui->toolButtonBottom->setEnabled(false);
2746  }
2747  else
2748  {
2749  ui->toolButtonTop->setEnabled(true);
2750  ui->toolButtonUp->setEnabled(true);
2751  ui->toolButtonDown->setEnabled(true);
2752  ui->toolButtonBottom->setEnabled(true);
2753  }
2754  }
2755  else
2756  {
2757  ui->toolButtonTop->setEnabled(false);
2758  ui->toolButtonUp->setEnabled(false);
2759  ui->toolButtonDown->setEnabled(false);
2760  ui->toolButtonBottom->setEnabled(false);
2761  }
2762 }
2763 
2764 //---------------------------------------------------------------------------------------------------------------------
2765 void TMainWindow::MFields(bool enabled)
2766 {
2767  ui->lineEditName->setEnabled(enabled);
2768  ui->plainTextEditDescription->setEnabled(enabled);
2769  ui->lineEditFullName->setEnabled(enabled);
2770 
2772  {
2773  ui->doubleSpinBoxBaseValue->setEnabled(enabled);
2774  ui->doubleSpinBoxInSizes->setEnabled(enabled);
2775  ui->doubleSpinBoxInHeights->setEnabled(enabled);
2776  }
2777  else
2778  {
2779  ui->plainTextEditFormula->setEnabled(enabled);
2780  ui->pushButtonGrow->setEnabled(enabled);
2781  ui->toolButtonExpr->setEnabled(enabled);
2782  }
2783 
2784  ui->lineEditFind->setEnabled(enabled);
2785  if (enabled && not ui->lineEditFind->text().isEmpty())
2786  {
2787  ui->toolButtonFindPrevious->setEnabled(enabled);
2788  ui->toolButtonFindNext->setEnabled(enabled);
2789  }
2790  else
2791  {
2792  ui->toolButtonFindPrevious->setEnabled(false);
2793  ui->toolButtonFindNext->setEnabled(false);
2794  }
2795 }
2796 
2797 //---------------------------------------------------------------------------------------------------------------------
2799 {
2800  QString fileName;
2801  bool isFileWritable = true;
2802  if (!curFile.isEmpty())
2803  {
2804 #ifdef Q_OS_WIN32
2805  qt_ntfs_permission_lookup++; // turn checking on
2806 #endif /*Q_OS_WIN32*/
2807  isFileWritable = QFileInfo(curFile).isWritable();
2808 #ifdef Q_OS_WIN32
2809  qt_ntfs_permission_lookup--; // turn it off again
2810 #endif /*Q_OS_WIN32*/
2811  fileName = curFile;
2812  }
2813  else
2814  {
2815  fileName = tr("untitled %1").arg(qApp->MainWindows().size() + 1);
2816  mType == MeasurementsType::Multisize ? fileName += QLatin1String(".vst") : fileName += QLatin1String(".vit");
2817  }
2818 
2819  fileName += QLatin1String("[*]");
2820 
2821  if (mIsReadOnly || not isFileWritable)
2822  {
2823  fileName += QLatin1String(" (") + tr("read only") + QLatin1String(")");
2824  }
2825 
2826  setWindowTitle( VER_INTERNALNAME_ME_STR + QString(" - ") + fileName);
2827  setWindowFilePath(curFile);
2828 
2829 #if defined(Q_OS_MAC)
2830  static QIcon fileIcon = QIcon(QCoreApplication::applicationDirPath() +
2831  QLatin1String("/../Resources/measurements.icns"));
2832  QIcon icon;
2833  if (!curFile.isEmpty())
2834  {
2835  if (not isWindowModified())
2836  {
2837  icon = fileIcon;
2838  }
2839  else
2840  {
2841  static QIcon darkIcon;
2842 
2843  if (darkIcon.isNull())
2844  {
2845  darkIcon = QIcon(darkenPixmap(fileIcon.pixmap(16, 16)));
2846  }
2847  icon = darkIcon;
2848  }
2849  }
2850  setWindowIcon(icon);
2851 #endif //defined(Q_OS_MAC)
2852 }
2853 
2854 //---------------------------------------------------------------------------------------------------------------------
2855 QString TMainWindow::ClearCustomName(const QString &name) const
2856 {
2857  QString clear = name;
2858  const int index = clear.indexOf(CustomMSign);
2859  if (index == 0)
2860  {
2861  clear.remove(0, 1);
2862  }
2863  return clear;
2864 }
2865 
2866 //---------------------------------------------------------------------------------------------------------------------
2867 bool TMainWindow::EvalFormula(const QString &formula, bool fromUser, VContainer *data, QLabel *label)
2868 {
2869  const QString postfix = UnitsToStr(pUnit);//Show unit in dialog label (cm, mm or inch)
2870  if (formula.isEmpty())
2871  {
2872  label->setText(tr("Error") + " (" + postfix + "). " + tr("Empty field."));
2873  label->setToolTip(tr("Empty field"));
2874  return false;
2875  }
2876  else
2877  {
2878  try
2879  {
2880  // Replace line return character with spaces for calc if exist
2881  QString f;
2882  if (fromUser)
2883  {
2884  f = qApp->TrVars()->FormulaFromUser(formula, qApp->Settings()->GetOsSeparator());
2885  }
2886  else
2887  {
2888  f = formula;
2889  }
2890  f.replace("\n", " ");
2891  QScopedPointer<Calculator> cal(new Calculator());
2892  qreal result = cal->EvalFormula(data->DataVariables(), f);
2893 
2894  if (qIsInf(result) || qIsNaN(result))
2895  {
2896  label->setText(tr("Error") + " (" + postfix + ").");
2897  label->setToolTip(tr("Invalid result. Value is infinite or NaN. Please, check your calculations."));
2898  return false;
2899  }
2900 
2901  result = UnitConvertor(result, mUnit, pUnit);
2902 
2903  label->setText(qApp->LocaleToString(result) + " " +postfix);
2904  label->setToolTip(tr("Value"));
2905  return true;
2906  }
2907  catch (qmu::QmuParserError &e)
2908  {
2909  label->setText(tr("Error") + " (" + postfix + "). " + tr("Parser error: %1").arg(e.GetMsg()));
2910  label->setToolTip(tr("Parser error: %1").arg(e.GetMsg()));
2911  return false;
2912  }
2913  }
2914 }
2915 
2916 //---------------------------------------------------------------------------------------------------------------------
2917 void TMainWindow::Open(const QString &pathTo, const QString &filter)
2918 {
2919  const QString mPath = QFileDialog::getOpenFileName(this, tr("Open file"), pathTo, filter);
2920 
2921  if (not mPath.isEmpty())
2922  {
2923  if (individualMeasurements == nullptr)
2924  {
2925  LoadFile(mPath);
2926  }
2927  else
2928  {
2929  qApp->NewMainWindow()->LoadFile(mPath);
2930  }
2931  }
2932 }
2933 
2934 //---------------------------------------------------------------------------------------------------------------------
2936 {
2937  ui->actionReadOnly->setChecked(ro);
2938  if (ro)
2939  {
2940  ui->actionReadOnly->setIcon(QIcon("://seamlymeicon/24x24/padlock_locked.png"));
2941  }
2942  else
2943  {
2944  ui->actionReadOnly->setIcon(QIcon("://seamlymeicon/24x24/padlock_opened.png"));
2945  }
2946 
2947  ui->actionReadOnly->setDisabled(mIsReadOnly);
2948 }
2949 
2950 //---------------------------------------------------------------------------------------------------------------------
2952 {
2953  if (const QTableWidgetItem *nameField = ui->tableWidget->item(ui->tableWidget->currentRow(), ColumnName))
2954  {
2955  const bool isCustom = not (nameField->text().indexOf(CustomMSign) == 0);
2956  ui->lineEditName->setReadOnly(isCustom);
2957  ui->plainTextEditDescription->setReadOnly(isCustom);
2958  ui->lineEditFullName->setReadOnly(isCustom);
2959 
2960  // Need to block signals for QLineEdit in readonly mode because it still emits
2961  // QLineEdit::editingFinished signal.
2962  ui->lineEditName->blockSignals(isCustom);
2963  ui->lineEditFullName->blockSignals(isCustom);
2964 
2965  Controls(); // Buttons remove, up, down
2966  }
2967 }
2968 
2969 //---------------------------------------------------------------------------------------------------------------------
2971 {
2972  const VSeamlyMeSettings *settings = qApp->SeamlyMeSettings();
2973  restoreGeometry(settings->GetGeometry());
2974  restoreState(settings->GetWindowState());
2975  restoreState(settings->GetToolbarsState(), APP_VERSION);
2976 
2977  // Text under tool button icon
2978  ToolBarStyles();
2979 
2980  // Stack limit
2981  //qApp->getUndoStack()->setUndoLimit(settings->GetUndoCount());
2982 }
2983 
2984 //---------------------------------------------------------------------------------------------------------------------
2986 {
2987  VSeamlyMeSettings *settings = qApp->SeamlyMeSettings();
2988  settings->SetGeometry(saveGeometry());
2989  settings->SetWindowState(saveState());
2990  settings->SetToolbarsState(saveState(APP_VERSION));
2991 }
2992 
2993 //---------------------------------------------------------------------------------------------------------------------
2994 QStringList TMainWindow::FilterMeasurements(const QStringList &mNew, const QStringList &mFilter)
2995 {
2996  return convertToList(convertToSet<QString>(mNew).subtract(convertToSet<QString>(mFilter)));
2997 }
2998 
2999 //---------------------------------------------------------------------------------------------------------------------
3001 {
3002  const int row = ui->tableWidget->currentRow();
3003 
3004  if (row == -1)
3005  {
3006  return;
3007  }
3008 
3009  RefreshTable();
3010 
3011  search->RefreshList(ui->lineEditFind->text());
3012 
3013  ui->tableWidget->selectRow(row);
3014 }
3015 
3016 //---------------------------------------------------------------------------------------------------------------------
3017 bool TMainWindow::LoadFromExistingFile(const QString &path)
3018 {
3019  if (individualMeasurements == nullptr)
3020  {
3021  if (not QFileInfo(path).exists())
3022  {
3023  qCCritical(tMainWindow, "%s", qUtf8Printable(tr("File '%1' doesn't exist!").arg(path)));
3024  if (qApp->IsTestMode())
3025  {
3026  qApp->exit(V_EX_NOINPUT);
3027  }
3028  return false;
3029  }
3030 
3031  // Check if file already opened
3032  QList<TMainWindow*>list = qApp->MainWindows();
3033  for (int i = 0; i < list.size(); ++i)
3034  {
3035  if (list.at(i)->CurrentFile() == path)
3036  {
3037  list.at(i)->activateWindow();
3038  close();
3039  return false;
3040  }
3041  }
3042 
3043  VlpCreateLock(lock, path);
3044 
3045  if (not lock->IsLocked())
3046  {
3047  if (not IgnoreLocking(lock->GetLockError(), path))
3048  {
3049  return false;
3050  }
3051  }
3052 
3053  try
3054  {
3055  data = new VContainer(qApp->TrVars(), &mUnit);
3056 
3061 
3063 
3065  {
3066  VException e(tr("File has unknown format."));
3067  throw e;
3068  }
3069 
3071  {
3072  VException e(tr("Export from multisize measurements is not supported."));
3073  throw e;
3074  }
3075  else
3076  {
3077  VVITConverter converter(path);
3080  individualMeasurements->setXMLContent(converter.Convert());// Read again after conversion
3081  }
3082 
3084  {
3085  VException e(tr("File contains invalid known measurement(s)."));
3086  throw e;
3087  }
3088 
3090  pUnit = mUnit;
3091 
3094 
3095  ui->labelToolTip->setVisible(false);
3096  ui->tabWidget->setVisible(true);
3097 
3098  InitWindow();
3099 
3101  const bool freshCall = true;
3102  RefreshData(freshCall);
3103 
3104  if (ui->tableWidget->rowCount() > 0)
3105  {
3106  ui->tableWidget->selectRow(0);
3107  }
3108 
3109  lock.reset();// Now we can unlock the file
3110 
3113  MeasurementGUI();
3114  }
3115  catch (VException &e)
3116  {
3117  qCCritical(tMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
3118  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
3119  ui->labelToolTip->setVisible(true);
3120  ui->tabWidget->setVisible(false);
3121  delete individualMeasurements;
3122  individualMeasurements = nullptr;
3123  delete data;
3124  data = nullptr;
3125  lock.reset();
3126 
3127  if (qApp->IsTestMode())
3128  {
3129  qApp->exit(V_EX_NOINPUT);
3130  }
3131  return false;
3132  }
3133  }
3134  else
3135  {
3136  qApp->NewMainWindow();
3137  return qApp->MainWindow()->LoadFile(path);
3138  }
3139 
3140  return true;
3141 }
3142 //---------------------------------------------------------------------------------------------------------------------
3144 {
3145  qCDebug(tMainWindow, "Updating recent file actions.");
3146  const QStringList files = qApp->SeamlyMeSettings()->GetRecentFileList();
3147  const int numRecentFiles = qMin(files.size(), static_cast<int>(MaxRecentFiles));
3148  qCDebug(tMainWindow, "Updating recent file actions = %i ",numRecentFiles);
3149 
3150  for (int i = 0; i < numRecentFiles; ++i)
3151  {
3152  const QString text = QString("&%1. %2").arg(i + 1).arg(strippedName(files.at(i)));
3153  qCDebug(tMainWindow, "file %i = %s", numRecentFiles, qUtf8Printable(text));
3154  recentFileActs[i]->setText(text);
3155  recentFileActs[i]->setData(files.at(i));
3156  recentFileActs[i]->setVisible(true);
3157  }
3158 
3159  for (int j = numRecentFiles; j < MaxRecentFiles; ++j)
3160  {
3161  recentFileActs[j]->setVisible(false);
3162  }
3163 
3164  separatorAct->setVisible(numRecentFiles>0);
3165 }
3166 
3167 //---------------------------------------------------------------------------------------------------------------------
3169 {
3170  SCASSERT(menu != nullptr)
3171 
3172  QAction *action = menu->addAction(tr("&New Window"));
3173  connect(action, &QAction::triggered, this, []()
3174  {
3175  qApp->NewMainWindow();
3176  qApp->MainWindow()->activateWindow();
3177  });
3178  action->setMenuRole(QAction::NoRole);
3179  menu->addSeparator();
3180 
3181  const QList<TMainWindow*> windows = qApp->MainWindows();
3182  for (int i = 0; i < windows.count(); ++i)
3183  {
3184  TMainWindow *window = windows.at(i);
3185 
3186  QString title = QString("%1. %2").arg(i+1).arg(window->windowTitle());
3187  const int index = title.lastIndexOf("[*]");
3188  if (index != -1)
3189  {
3190  window->isWindowModified() ? title.replace(index, 3, "*") : title.replace(index, 3, "");
3191  }
3192 
3193  QAction *action = menu->addAction(title, this, SLOT(ShowWindow()));
3194  action->setData(i);
3195  action->setCheckable(true);
3196  action->setMenuRole(QAction::NoRole);
3197  if (window->isActiveWindow())
3198  {
3199  action->setChecked(true);
3200  }
3201  }
3202 }
3203 
3204 //---------------------------------------------------------------------------------------------------------------------
3205 bool TMainWindow::IgnoreLocking(int error, const QString &path)
3206 {
3207  QMessageBox::StandardButton answer = QMessageBox::Abort;
3208  if (not qApp->IsTestMode())
3209  {
3210  switch(error)
3211  {
3212  case QLockFile::LockFailedError:
3213  answer = QMessageBox::warning(this, tr("Locking file"),
3214  tr("This file already opened in another window. Ignore if you want "
3215  "to continue (not recommended, can cause a data corruption)."),
3216  QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort);
3217  break;
3218  case QLockFile::PermissionError:
3219  answer = QMessageBox::question(this, tr("Locking file"),
3220  tr("The lock file could not be created, for lack of permissions. "
3221  "Ignore if you want to continue (not recommended, can cause "
3222  "a data corruption)."),
3223  QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort);
3224  break;
3225  case QLockFile::UnknownError:
3226  answer = QMessageBox::question(this, tr("Locking file"),
3227  tr("Unknown error happened, for instance a full partition "
3228  "prevented writing out the lock file. Ignore if you want to "
3229  "continue (not recommended, can cause a data corruption)."),
3230  QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort);
3231  break;
3232  default:
3233  answer = QMessageBox::Abort;
3234  break;
3235  }
3236  }
3237 
3238  if (answer == QMessageBox::Abort)
3239  {
3240  qCDebug(tMainWindow, "Failed to lock %s", qUtf8Printable(path));
3241  qCDebug(tMainWindow, "Error type: %d", error);
3242  if (qApp->IsTestMode())
3243  {
3244  switch(error)
3245  {
3246  case QLockFile::LockFailedError:
3247  qCCritical(tMainWindow, "%s",
3248  qUtf8Printable(tr("This file already opened in another window.")));
3249  break;
3250  case QLockFile::PermissionError:
3251  qCCritical(tMainWindow, "%s",
3252  qUtf8Printable(tr("The lock file could not be created, for lack of permissions.")));
3253  break;
3254  case QLockFile::UnknownError:
3255  qCCritical(tMainWindow, "%s",
3256  qUtf8Printable(tr("Unknown error happened, for instance a full partition "
3257  "prevented writing out the lock file.")));
3258  break;
3259  default:
3260  break;
3261  }
3262 
3263  qApp->exit(V_EX_NOINPUT);
3264  }
3265  return false;
3266  }
3267  return true;
3268 }
3269 
3270 //---------------------------------------------------------------------------------------------------------------------
3272 {
3273  switch (mUnit)
3274  {
3275  case Unit::Cm:
3276  ui->doubleSpinBoxBaseValue->setDecimals(2);
3277  ui->doubleSpinBoxBaseValue->setSingleStep(0.01);
3278 
3279  ui->doubleSpinBoxInSizes->setDecimals(2);
3280  ui->doubleSpinBoxInSizes->setSingleStep(0.01);
3281 
3282  ui->doubleSpinBoxInHeights->setDecimals(2);
3283  ui->doubleSpinBoxInHeights->setSingleStep(0.01);
3284  break;
3285  case Unit::Mm:
3286  ui->doubleSpinBoxBaseValue->setDecimals(1);
3287  ui->doubleSpinBoxBaseValue->setSingleStep(0.1);
3288 
3289  ui->doubleSpinBoxInSizes->setDecimals(1);
3290  ui->doubleSpinBoxInSizes->setSingleStep(0.1);
3291 
3292  ui->doubleSpinBoxInHeights->setDecimals(1);
3293  ui->doubleSpinBoxInHeights->setSingleStep(0.1);
3294  break;
3295  case Unit::Inch:
3296  ui->doubleSpinBoxBaseValue->setDecimals(5);
3297  ui->doubleSpinBoxBaseValue->setSingleStep(0.00001);
3298 
3299  ui->doubleSpinBoxInSizes->setDecimals(5);
3300  ui->doubleSpinBoxInSizes->setSingleStep(0.00001);
3301 
3302  ui->doubleSpinBoxInHeights->setDecimals(5);
3303  ui->doubleSpinBoxInHeights->setSingleStep(0.00001);
3304  break;
3305  default:
3306  break;
3307  }
3308 }
3309 
3310 //---------------------------------------------------------------------------------------------------------------------
3312 {
3313  labelPatternUnit = new QLabel(tr("Pattern unit:"));
3314  ui->toolBarGradation->addWidget(labelPatternUnit);
3315 
3316  comboBoxUnits = new QComboBox(this);
3318 
3319  // set default unit
3320  const qint32 indexUnit = comboBoxUnits->findData(static_cast<int>(pUnit));
3321  if (indexUnit != -1)
3322  {
3323  comboBoxUnits->setCurrentIndex(indexUnit);
3324  }
3325 
3326  connect(comboBoxUnits, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
3328 
3329  ui->toolBarGradation->addWidget(comboBoxUnits);
3330 }
3331 
3332 //---------------------------------------------------------------------------------------------------------------------
3334 {
3335  SCASSERT(comboBoxUnits != nullptr)
3336  comboBoxUnits->addItem(UnitsToStr(Unit::Cm, true), QVariant(static_cast<int>(Unit::Cm)));
3337  comboBoxUnits->addItem(UnitsToStr(Unit::Mm, true), QVariant(static_cast<int>(Unit::Mm)));
3338  comboBoxUnits->addItem(UnitsToStr(Unit::Inch, true), QVariant(static_cast<int>(Unit::Inch)));
3339 }
3340 
3341 //---------------------------------------------------------------------------------------------------------------------
3342 void TMainWindow::InitGender(QComboBox *gender)
3343 {
3344  SCASSERT(gender != nullptr)
3345  gender->addItem(tr("unknown", "gender"), QVariant(static_cast<int>(GenderType::Unknown)));
3346  gender->addItem(tr("male", "gender"), QVariant(static_cast<int>(GenderType::Male)));
3347  gender->addItem(tr("female", "gender"), QVariant(static_cast<int>(GenderType::Female)));
3348 }
3349 
3350 //---------------------------------------------------------------------------------------------------------------------
3351 template <class T>
3352 void TMainWindow::HackWidget(T **widget)
3353 {
3354  delete *widget;
3355  *widget = new T();
3356  hackedWidgets.append(*widget);
3357 }
3358 
3359 //---------------------------------------------------------------------------------------------------------------------
3361 {
3362  // do nothing
3363 }
3364 
3365 //---------------------------------------------------------------------------------------------------------------------
3366 /**
3367  * @brief copyToClipboard copy dialog selection to clipboard as comma separated values.
3368  */
3370 {
3371  QItemSelectionModel *model = ui->tableWidget->selectionModel();
3372  QModelIndexList selectedIndexes = model->selectedIndexes();
3373 
3374  QString clipboardString;
3375 
3376  for (int i = 0; i < selectedIndexes.count(); ++i)
3377  {
3378  QModelIndex current = selectedIndexes[i];
3379  QString displayText = current.data(Qt::DisplayRole).toString();
3380 
3381  // Check if another column exists beyond this one.
3382  if (i + 1 < selectedIndexes.count())
3383  {
3384  QModelIndex next = selectedIndexes[i+1];
3385 
3386  // If the column is on different row, the clipboard should take note.
3387  if (next.row() != current.row())
3388  {
3389  displayText.append("\n");
3390  }
3391  else
3392  {
3393  // Otherwise append a comma separator.
3394  displayText.append(" , ");
3395  }
3396  }
3397  clipboardString.append(displayText);
3398  }
3399 
3400  QClipboard *clipboard = QApplication::clipboard();
3401  clipboard->setText(clipboardString);
3402 }
The Calculator class for calculation formula.
Definition: calculator.h:84
MeasurementsType Type() const
The EditFormulaDialog class dialog for editing wrong formula.
QString GetFormula() const
void SetFormula(const QString &value)
void setPostfix(const QString &value)
void ShowDataBase()
static QString imageUrl(const QString &number)
The QxtCsvModel class provides a QAbstractTableModel for CSV Files.
Definition: qxtcsvmodel.h:54
void setText(int row, int column, const QString &value)
Sets the content of the cell at row row and column column to value.
bool insertColumn(int col, const QModelIndex &parent=QModelIndex())
\reimp
void setHeaderText(int column, const QString &value)
Sets the content of the header for column column to value.
bool insertRow(int row, const QModelIndex &parent=QModelIndex())
\reimp
void toCSV(QIODevice *file, bool withHeader=false, QChar separator=',', QTextCodec *codec=nullptr) const
Outputs the content of the model as a CSV file to the device dest using codec.
void SetBaseMSize(int size)
QString GetCustomName() const
bool FileSave()
void FileNew()
bool EvalFormula(const QString &formula, bool fromUser, VContainer *data, QLabel *label)
QString ClearCustomName(const QString &name) const
void SetDefaultHeight(int value)
void CreateWindowMenu(QMenu *menu)
QLabel * labelGradationSizes
Definition: tmainwindow.h:183
QString CurrentFile() const
QAction * actionDockDiagram
Definition: tmainwindow.h:185
QString curFile
Definition: tmainwindow.h:175
virtual void exportToCSVData(const QString &fileName, const DialogExportToCSV &dialog) Q_DECL_FINAL
void InitTable()
int formulaBaseHeight
Definition: tmainwindow.h:179
QComboBox * gradationSizes
Definition: tmainwindow.h:177
void UpdateRecentFileActions()
VContainer * data
Definition: tmainwindow.h:169
void ReadSettings()
void SetupMenu()
void SaveBirthDate(const QDate &date)
QStringList FilterMeasurements(const QStringList &mNew, const QStringList &mFilter)
qreal currentSize
Definition: tmainwindow.h:173
bool dockDiagramVisible
Definition: tmainwindow.h:186
void printPages(QPrinter *printer)
void ShowNewMData(bool fresh)
Ui::TMainWindow * ui
Definition: tmainwindow.h:167
void InitWindow()
void OpenMultisize()
QVector< QObject * > hackedWidgets
Definition: tmainwindow.h:192
virtual void zoomToSelected() Q_DECL_OVERRIDE
void PatternUnitChanged(int index)
void OpenIndividual()
void UpdateWindowTitle()
void RefreshTable(bool freshCall=false)
void SaveMFullName()
QAction * recentFileActs[MaxRecentFiles]
Definition: tmainwindow.h:190
void SavePMSystem(int index)
void ShowHeaderUnits(QTableWidget *table, int column, const QString &unit)
void SetDefaultSize(int value)
void SaveMValue()
void InitGender(QComboBox *gender)
VMeasurements * individualMeasurements
Definition: tmainwindow.h:168
void WriteSettings()
bool LoadFile(const QString &path)
void SaveMName(const QString &text)
void MFields(bool enabled)
void ShowUnits()
virtual void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE
virtual void changeEvent(QEvent *event) Q_DECL_OVERRIDE
void HackWidget(T **widget)
void InitComboBoxUnits()
virtual void ShowToolTip(const QString &toolTip) Q_DECL_OVERRIDE
bool isInitialized
Definition: tmainwindow.h:187
void MoveBottom()
void AddCustom()
void SaveEmail()
QTableWidgetItem * AddCell(const QString &text, int row, int column, int aligment, bool ok=true)
void SetDecimals()
void OpenTemplate()
QComboBox * gradationHeights
Definition: tmainwindow.h:176
void SetPUnit(Unit unit)
qreal currentHeight
Definition: tmainwindow.h:174
void handleExportToCSV()
void MeasurementsWasSaved(bool saved)
void SaveGivenName()
void SetBaseMHeight(int height)
MeasurementsType mType
Definition: tmainwindow.h:172
bool LoadFromExistingFile(const QString &path)
QAction * separatorAct
Definition: tmainwindow.h:191
void SaveMDescription()
void SetCurrentFile(const QString &fileName)
void RefreshData(bool freshCall=false)
void ImportFromPattern()
void SaveMBaseValue(double value)
QComboBox * comboBoxUnits
Definition: tmainwindow.h:178
void ShowMData()
TMainWindow(QWidget *parent=nullptr)
Q_REQUIRED_RESULT QComboBox * SetGradationList(QLabel *label, const QStringList &list)
void SaveFamilyName()
void SaveMSizeIncrease(double value)
void ChangedHeight(int index)
virtual void showEvent(QShowEvent *event) Q_DECL_OVERRIDE
void ShowMDiagram(const QString &name)
void UpdatePatternUnit()
virtual ~TMainWindow() Q_DECL_OVERRIDE
void copyToClipboard()
copyToClipboard copy dialog selection to clipboard as comma separated values.
void SaveGender(int index)
bool SaveMeasurements(const QString &fileName, QString &error)
void CreateFromExisting()
void AboutToShowWindowMenu()
void RetranslateTable()
void MeasurementGUI()
void SaveNotes()
void ShowWindow() const
bool mIsReadOnly
Definition: tmainwindow.h:188
virtual void updateGroups() Q_DECL_OVERRIDE
void Preferences()
void UpdatePadlock(bool ro)
void InitUnits()
QString getMeasurementNumber(const QString &name)
QLabel * labelPatternUnit
Definition: tmainwindow.h:184
std::shared_ptr< VLockGuard< char > > lock
Definition: tmainwindow.h:180
void SaveMHeightIncrease(double value)
bool MaybeSave()
bool FileSaveAs()
QLabel * labelGradationHeights
Definition: tmainwindow.h:182
virtual bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE
void DeployFormula()
void ChangedSize(int index)
QSharedPointer< VTableSearch > search
Definition: tmainwindow.h:181
bool IgnoreLocking(int error, const QString &path)
void ToolBarStyles()
void Open(const QString &pathTo, const QString &filter)
int GetCurrentFormatVarsion() const
QString GetVersionStr() const
void exportToCSV(QString &file)
void ToolBarStyle(QToolBar *bar)
bool ContinueFormatRewrite(const QString &currentFormatVersion, const QString &maxFormatVersion)
static QString PrepareStandardTemplates(const QString &currentPath)
static QString PrepareMultisizeTables(const QString &currentPath)
QByteArray GetGeometry() const
void SetToolbarsState(const QByteArray &value)
QByteArray GetToolbarsState() const
void SetWindowState(const QByteArray &value)
QByteArray GetWindowState() const
void SetGeometry(const QByteArray &value)
The VContainer class container of all variables.
Definition: vcontainer.h:141
static qreal height()
height return height
Definition: vcontainer.cpp:690
static void ClearUniqueNames()
Definition: vcontainer.cpp:629
static bool IsUnique(const QString &name)
Definition: vcontainer.cpp:585
void ClearVariables(const VarType &type=VarType::Unknown)
Definition: vcontainer.cpp:348
const QHash< QString, QSharedPointer< VInternalVariable > > * DataVariables() const
Definition: vcontainer.cpp:718
static qreal size()
size return size
Definition: vcontainer.cpp:674
QSharedPointer< T > GetVariable(QString name) const
GetVariable return varible by name.
Definition: vcontainer.h:303
const QMap< QString, QSharedPointer< VMeasurement > > DataMeasurements() const
Definition: vcontainer.cpp:537
Unit MUnit() const
The VExceptionBadId class for exception bad id.
virtual QString ErrorMessage() const Q_DECL_OVERRIDE
ErrorMessage return main error message.
The VException class parent for all exception. Could be use for abstract exception.
Definition: vexception.h:66
virtual QString ErrorMessage() const
ErrorMessage return main error message.
Definition: vexception.cpp:97
virtual QString DetailedInformation() const
DetailedInformation return detailed information about error.
Definition: vexception.cpp:134
bool IsLocked() const
Definition: vlockguard.h:155
The VMeasurement class keep data row of multisize table.
Definition: vmeasurement.h:74
static QStringList WholeListSizes(Unit patternUnit)
static QStringList WholeListHeights(Unit patternUnit)
void MoveUp(const QString &name)
void MoveTop(const QString &name)
void SetMDescription(const QString &name, const QString &text)
void MoveDown(const QString &name)
void addEmpty(const QString &name, const QString &formula=QString())
QString PMSystem() const
void SetGender(const GenderType &gender)
void SetNotes(const QString &text)
void SetMBaseValue(const QString &name, double value)
void SetEmail(const QString &text)
QStringList ListAll() const
QStringList listKnown() const
void SetFamilyName(const QString &text)
void ReadMeasurements() const
void SetSize(qreal *size)
void SetPMSystem(const QString &system)
void Remove(const QString &name)
void SetReadOnly(bool ro)
int BaseSize() const
void SetMFullName(const QString &name, const QString &text)
QDate BirthDate() const
void SetHeight(qreal *height)
void SetMValue(const QString &name, const QString &text)
MeasurementsType Type() const
void SetMSizeIncrease(const QString &name, double value)
void MoveBottom(const QString &name)
int BaseHeight() const
QString Email() const
void AddEmptyAfter(const QString &after, const QString &name, const QString &formula=QString())
bool IsReadOnly() const
void SetGivenName(const QString &text)
void SetMHeightIncrease(const QString &name, double value)
QString FamilyName() const
virtual void setXMLContent(const QString &fileName) Q_DECL_OVERRIDE
GenderType Gender() const
virtual bool SaveDocument(const QString &fileName, QString &error) Q_DECL_OVERRIDE
QString GivenName() const
QString Notes() const
bool IsDefinedKnownNamesValid() const
void SetMName(const QString &name, const QString &text)
void SetBirthDate(const QDate &date)
void HasResult(bool state)
QString guiText(const QString &measurement) const
QString MNumber(const QString &measurement) const
static const QString MeasurementMaxVerStr
Definition: vvitconverter.h:72
static Q_DECL_CONSTEXPR const int MeasurementMaxVer
Definition: vvitconverter.h:80
static const QString MeasurementMaxVerStr
Definition: vvstconverter.h:72
static Q_DECL_CONSTEXPR const int MeasurementMaxVer
Definition: vvstconverter.h:80
Error class of the parser.
const QString & GetMsg() const
Returns the message string for this error.
QPixmap darkenPixmap(const QPixmap &pixmap)
Definition: def.cpp:489
const qreal PrintDPI
Definition: def.cpp:228
QString strippedName(const QString &fullFileName)
strippedName the function call around curFile to exclude the path to the file.
Definition: def.cpp:391
QString UnitsToStr(const Unit &unit, const bool translate)
UnitsToStr translate unit to string.
Definition: def.cpp:702
qreal UnitConvertor(qreal value, const Unit &from, const Unit &to)
Definition: def.cpp:269
#define SCASSERT(cond)
Definition: def.h:317
QList< T > convertToList(const C< T > &set)
Definition: def.h:645
MeasurementsType
Definition: def.h:104
Unit
Definition: def.h:105
const QString CustomMSign
Definition: ifcdef.cpp:70
const QString measurement_
Definition: ifcdef.cpp:412
#define NULL_ID
Definition: ifcdef.h:76
void InitPMSystems(QComboBox *systemCombo)
Definition: pmsystems.cpp:181
#define APP_VERSION
QString NameRegExp()
Definition: qmudef.cpp:281
#define VER_INTERNALNAME_ME_STR
Definition: version.h:57
#define DIALOG_MAX_FORMULA_HEIGHT
Definition: tmainwindow.cpp:96
@ ColumnNumber
@ ColumnFullName
@ ColumnFormula
@ ColumnName
@ ColumnInSizes
@ ColumnInHeights
@ ColumnBaseValue
@ ColumnCalcValue
#define qApp
Definition: vapplication.h:67
QT_WARNING_PUSH void VlpCreateLock(std::shared_ptr< VLockGuard< Guarded >> &r, const QString &lockName, int stale=0, int timeout=0)
Definition: vlockguard.h:213
GenderType
Definition: vmeasurements.h:66
static const auto V_EX_NOINPUT
Definition: vsysexits.h:71