Seamly2D
Code documentation
export_layout_dialog.cpp
Go to the documentation of this file.
1 /************************************************************************
2  **
3  ** @file export_layout_dialog.cpp
4  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
5  ** @date 22 1, 2015
6  **
7  ** @author Douglas S Caskey
8  ** @date Nov 4, 2022
9  **
10  ** @brief
11  ** @copyright
12  ** This source code is part of the Seamly2D project, a pattern making
13  ** program, whose allow create and modeling patterns of clothing.
14  ** Copyright (C) 2013-2022 Seamly2D project
15  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
16  **
17  ** Seamly2D is free software: you can redistribute it and/or modify
18  ** it under the terms of the GNU General Public License as published by
19  ** the Free Software Foundation, either version 3 of the License, or
20  ** (at your option) any later version.
21  **
22  ** Seamly2D is distributed in the hope that it will be useful,
23  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
24  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  ** GNU General Public License for more details.
26  **
27  ** You should have received a copy of the GNU General Public License
28  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
29  **
30  *************************************************************************/
31 
32 #include "export_layout_dialog.h"
33 #include "ui_export_layout_dialog.h"
34 #include "../options.h"
35 #include "../core/vapplication.h"
36 #include "../vmisc/vsettings.h"
37 #include "../ifc/exception/vexception.h"
38 #include "../vwidgets/export_format_combobox.h"
39 
40 #include <QDir>
41 #include <QFileDialog>
42 #include <QMessageBox>
43 #include <QProcess>
44 #include <QtDebug>
45 #include <QRegularExpression>
46 #include <QSpinBox>
47 #include <QtDebug>
48 
49 const QString fileNameRegExp = QStringLiteral("^[\\p{L}\\p{Nd}\\-. _]+$");
50 
51 //---------------------------------------------------------------------------------------------------------------------
52 ExportLayoutDialog::ExportLayoutDialog(int count, Draw mode, const QString &fileName, QWidget *parent)
53  : VAbstractLayoutDialog(parent)
54  , ui(new Ui::ExportLayoutDialog)
55  , m_count(count)
56  , m_isInitialized(false)
57  , m_mode(mode)
58  , m_SaveButton(nullptr)
59 {
60  ui->setupUi(this);
61  setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
62 
63  ui->path_LineEdit->setClearButtonEnabled(true);
64  ui->filename_LineEdit->setClearButtonEnabled(true);
65 
66  qApp->Seamly2DSettings()->GetOsSeparator() ? setLocale(QLocale()) : setLocale(QLocale::c());
67 
68  m_SaveButton = ui->buttonBox->button(QDialogButtonBox::Save);
69  SCASSERT(m_SaveButton != nullptr)
70  m_SaveButton->setEnabled(false);
71 
72  ui->filename_LineEdit->setValidator( new QRegularExpressionValidator(QRegularExpression(fileNameRegExp), this));
73 
74  const QString mask = fileName + modeString();
76  {
77  ui->filename_LineEdit->setText(mask);
78  }
79  else
80  {
81  if (QRegularExpression(fileNameRegExp).match(mask).hasMatch())
82  {
83  ui->filename_LineEdit->setText(mask);
84  }
85  else
86  {
87  VException e(tr("The base filename does not match a regular expression."));
88  throw e;
89  }
90  }
91 
93  {
121  //removeFormatFromList(LayoutExportFormat::PS);
122  //removeFormatFromList(LayoutExportFormat::PDF);
123  //removeFormatFromList(LayoutExportFormat::EPS);
124  }
125 #ifdef V_NO_ASSERT // Temporarily unavailable
127 #endif
128 
129  if (m_mode != Draw::Layout)
130  {
132  }
133  else
134  {
135  ui->textAsPaths_Checkbox->setVisible(false);
136  }
137 
138  connect(m_SaveButton, &QPushButton::clicked, this, &ExportLayoutDialog::save);
139  connect(ui->filename_LineEdit, &QLineEdit::textChanged, this, &ExportLayoutDialog::showExportFiles);
140  connect(ui->format_ComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
142  connect(ui->browse_PushButton, &QPushButton::clicked, this, [this]()
143  {
144  const QString dirPath = qApp->Seamly2DSettings()->getLayoutPath();
145  bool usedNotExistedDir = false;
146  QDir directory(dirPath);
147  if (!directory.exists())
148  {
149  usedNotExistedDir = directory.mkpath(".");
150  }
151 
152  const QString dir = QFileDialog::getExistingDirectory(this, tr("Select folder"), dirPath,
153  QFileDialog::ShowDirsOnly
154  | QFileDialog::DontResolveSymlinks
155  | QFileDialog::DontUseNativeDialog);
156  if (!dir.isEmpty())
157  {// If the paths are equal the slot will not be called, we will do this manually
158  dir == ui->path_LineEdit->text() ? pathChanged(dir) : ui->path_LineEdit->setText(dir);
159  }
160 
161  if (usedNotExistedDir)
162  {
163  QDir directory(dirPath);
164  directory.rmpath(".");
165  }
166  });
167  connect(ui->path_LineEdit, &QLineEdit::textChanged, this, &ExportLayoutDialog::pathChanged);
168  connect(ui->quality_Slider, &QSlider::valueChanged, this, [this]()
169  {
170  ui->percent_SpinBox->setValue(ui->quality_Slider->value());
171  });
172  connect(ui->percent_SpinBox, QOverload<int>::of(&QSpinBox::valueChanged), [=](int i)
173  {
174  ui->quality_Slider->setValue(i);
175  });
176 
177  ui->path_LineEdit->setText(qApp->Seamly2DSettings()->getLayoutPath());
178 
179  initTemplates(ui->templates_ComboBox);
180 
181  readSettings();
182  showExportFiles();//Show example for current format.
183 }
184 
185 //---------------------------------------------------------------------------------------------------------------------
186 void ExportLayoutDialog::initTemplates(QComboBox *templates_ComboBox)
187 {
188  VAbstractLayoutDialog::initTemplates(templates_ComboBox);
189 
190  // remove the custom format,
191  int indexCustom = templates_ComboBox->count() -1;
192  templates_ComboBox->removeItem(indexCustom);
193 }
194 
195 
196 //---------------------------------------------------------------------------------------------------------------------
197 
199 {
200  if (static_cast<int>(format) < 0 || format >= LayoutExportFormat::COUNT)
201  {
202  VException e(tr("Tried to use out of range format number."));
203  throw e;
204  }
205 
206  const int i = ui->format_ComboBox->findData(static_cast<int>(format));
207  if (i < 0)
208  {
209  VException e(tr("Selected not present format."));
210  throw e;
211  }
212  ui->format_ComboBox->setCurrentIndex(i);
213 }
214 
215 //---------------------------------------------------------------------------------------------------------------------
217 {
218  switch(format())
219  {
247  ui->binaryDXF_CheckBox->setChecked(binary);
248  break;
260  default:
261  ui->binaryDXF_CheckBox->setChecked(false);
262  break;
263  }
264 }
265 
266 //---------------------------------------------------------------------------------------------------------------------
268 {
269  switch(format())
270  {
298  return ui->binaryDXF_CheckBox->isChecked();
310  default:
311  return false;
312  }
313 }
314 
315 //---------------------------------------------------------------------------------------------------------------------
316 void ExportLayoutDialog::setDestinationPath(const QString &cmdDestinationPath)
317 {
318  QString path;
319  if (cmdDestinationPath.isEmpty())
320  {
321  path = QDir::currentPath();
322  }
323  else if (QDir(cmdDestinationPath).isAbsolute())
324  {
325  path = cmdDestinationPath;
326  }
327  else
328  {
329  QDir dir;
330  if (!dir.cd(cmdDestinationPath))
331  {
332  VException e(tr("The destination directory doesn't exist or is not readable."));
333  throw e;
334  }
335  path = dir.absolutePath();
336  }
337 
338  qDebug() << "Full output path: " << path << "\n";
339  ui->path_LineEdit->setText(path);
340 }
341 
342 //---------------------------------------------------------------------------------------------------------------------
344 {
345  return m_mode;
346 }
347 
348 //---------------------------------------------------------------------------------------------------------------------
350 {
351  switch(format)
352  {
354  return ".svg";
357  return ".pdf";
359  return ".png";
361  return ".jpg";
363  return ".bmp";
365  return ".ppm";
367  return ".obj";
369  return ".ps";
371  return ".eps";
373  return ".tif";
401  return ".dxf";
402  default:
403  return QString();
404  }
405 }
406 
407 //---------------------------------------------------------------------------------------------------------------------
409 {
410  delete ui;
411 }
412 
413 //---------------------------------------------------------------------------------------------------------------------
415 {
416  return ui->path_LineEdit->text();
417 }
418 
419 //---------------------------------------------------------------------------------------------------------------------
421 {
422  return ui->filename_LineEdit->text();
423 }
424 
425 //---------------------------------------------------------------------------------------------------------------------
427 {
428  return static_cast<LayoutExportFormat>(ui->format_ComboBox->currentData().toInt());
429 }
430 
431 //---------------------------------------------------------------------------------------------------------------------
433 {
434  return ui->format_ComboBox->currentText();
435 }
436 
437 //---------------------------------------------------------------------------------------------------------------------
439 {
440  QString text = tr("%1 already exists.").arg(fileName() + exportFormatSuffix(format()));
441  QString infoText = QStringLiteral("Do you want to replace it?");
442 
443  if (ui->exportFiles_ListWidget->count() > 1)
444  {
445  text = tr("%1 files with basename %2 already exist.")
446  .arg(ui->exportFiles_ListWidget->count())
447  .arg(fileName());
448  infoText = tr("Do you want to replace them?");
449  }
450 
451  QString increment;
452 
453  for (int i=0; i < m_count; ++i)
454  {
455  if (m_mode == Draw::Layout)
456  {
457  increment = QStringLiteral("_0") + QString::number(i+1);
458  }
459 
460  const QString name = QString("%1/%2%3%4")
461  .arg(path()) //1
462  .arg(fileName()) //2
463  .arg(increment) //3
464  .arg(exportFormatSuffix(format())); //4
465 
466  if (QFile::exists(name))
467  {
468  QMessageBox messageBox(this);
469  messageBox.setWindowTitle(tr("Confirm Export"));
470  messageBox.setIcon(QMessageBox::Question);
471  messageBox.setText(text);
472  messageBox.setInformativeText(infoText);
473  messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
474  messageBox.setDefaultButton(QMessageBox::Yes);
475  int result = messageBox.exec();
476 
477  if (result == QMessageBox::No)
478  {
479  reject();
480  return;
481  }
482  else
483  {
484  break;
485  }
486  }
487  }
488  writeSettings();
489  accept();
490 }
491 
492 //---------------------------------------------------------------------------------------------------------------------
493 void ExportLayoutDialog::pathChanged(const QString &text)
494 {
495  QPalette palette = ui->path_LineEdit->palette();
496 
497  QDir dir(text);
498  dir.setPath(text);
499  if (dir.exists(text))
500  {
501  m_SaveButton->setEnabled(true);
502  palette.setColor(ui->path_LineEdit->foregroundRole(), Qt::black);
503  }
504  else
505  {
506  m_SaveButton->setEnabled(false);
507  palette.setColor(ui->path_LineEdit->foregroundRole(), Qt::red);
508  }
509 
510  ui->path_LineEdit->setPalette(palette);
511 }
512 
513 //---------------------------------------------------------------------------------------------------------------------
515 {
516  ui->exportFiles_ListWidget->clear();
517 
518  if (m_mode != Draw::Layout)
519  {
520 
521  ui->export_GroupBox->hide();
522  adjustSize();
523  return;
524  }
525 
526  const LayoutExportFormat currentFormat = format();
527  ui->textAsPaths_Checkbox->setEnabled(true);
528  ui->quality_Slider->setEnabled(false);
529  ui->paperFormat_GroupBox->setEnabled(false);
530  ui->margins_GroupBox->setEnabled(false);
531  ui->export_GroupBox->show();
532  adjustSize();
533 
534  if (currentFormat == LayoutExportFormat::PDFTiled)
535  {
536  const QString name = QString("%1%2")
537  .arg(fileName()) //1
538  .arg(exportFormatSuffix(format())); //2
539 
540  QListWidgetItem *item = new QListWidgetItem(name);
541  SCASSERT(item != nullptr)
542  ui->exportFiles_ListWidget->addItem(item);
543  }
544  else
545  {
546  for (int i=0; i < m_count; ++i)
547  {
548  const QString name = QString("%1_0%2%3")
549  .arg(fileName()) //1
550  .arg(QString::number(i+1)) //2
551  .arg(exportFormatSuffix(format())); //3
552 
553  QListWidgetItem *item = new QListWidgetItem(name);
554  SCASSERT(item != nullptr)
555  ui->exportFiles_ListWidget->addItem(item);
556  }
557  }
558 
559  switch(currentFormat)
560  {
588  ui->binaryDXF_CheckBox->setEnabled(true);
589  break;
591  ui->paperFormat_GroupBox->setEnabled(true);
592  ui->margins_GroupBox->setEnabled(true);
593  break;
595  ui->quality_Slider->setEnabled(true);
596  break;
598  ui->quality_Slider->setEnabled(true);
599  break;
608  default:
609  ui->binaryDXF_CheckBox->setEnabled(false);
610  break;
611  }
612 }
613 
614 //---------------------------------------------------------------------------------------------------------------------
616 {
617  return ui->textAsPaths_Checkbox->isChecked();
618 }
619 
620 //---------------------------------------------------------------------------------------------------------------------
622 {
623  if (m_mode != Draw::Layout)
624  {
625  ui->textAsPaths_Checkbox->setChecked(textAsPaths);
626  }
627  else
628  {
629  ui->textAsPaths_Checkbox->setChecked(false);
630  }
631 }
632 
633 //---------------------------------------------------------------------------------------------------------------------
634 void ExportLayoutDialog::showEvent(QShowEvent *event)
635 {
636  QDialog::showEvent( event );
637  if ( event->spontaneous() )
638  {
639  return;
640  }
641 
642  if (m_isInitialized)
643  {
644  return;
645  }
646 
647  setFixedHeight(size().height());
648 
649  m_isInitialized = true;//first show windows are held
650 }
651 
652 //---------------------------------------------------------------------------------------------------------------------
654 {
655  const int index = ui->format_ComboBox->findData(static_cast<int>(format));
656  if (index != -1)
657  {
658  ui->format_ComboBox->removeItem(index);
659  ui->format_ComboBox->setCurrentToDefault();
660  }
661 }
662 
663 //---------------------------------------------------------------------------------------------------------------------
664 /**
665  * Reads the values of the variables needed for the save layout dialog, for instance
666  * the margins, teamplte and orientation of tiled pdf. Then sets the corresponding
667  * elements of the dialog to these values.
668  *
669  * @brief ExportLayoutDialog::readSettings
670  */
672 {
673  VSettings *settings = qApp->Seamly2DSettings();
674  const Unit unit = qApp->patternUnit();
675 
676  // read Margins top, right, bottom, left
677  QMarginsF margins = settings->GetTiledPDFMargins(unit);
678 
679  ui->leftField_DoubleSpinBox->setValue(margins.left());
680  ui->topField_DoubleSpinBox->setValue(margins.top());
681  ui->rightField_DoubleSpinBox->setValue(margins.right());
682  ui->bottomField_DoubleSpinBox->setValue(margins.bottom());
683  ui->quality_Slider->setValue(settings->getExportQuality());
684  ui->percent_SpinBox->setValue(ui->quality_Slider->value());
685 
686  // read Template
687  QSizeF size = QSizeF(settings->getTiledPDFPaperWidth(Unit::Mm), settings->getTiledPDFPaperHeight(Unit::Mm));
688 
689  const int max = static_cast<int>(PaperSizeTemplate::Custom);
690  for (int i=0; i < max; ++i)
691  {
692 
693  const QSizeF tmplSize = getTemplateSize(static_cast<PaperSizeTemplate>(i), Unit::Mm);
694  if (size == tmplSize)
695  {
696  ui->templates_ComboBox->setCurrentIndex(i);
697  break;
698  }
699  }
700 
701  // read Orientation
703  {
704  ui->portrait_ToolButton->setChecked(true);
705  }
706  else
707  {
708  ui->landscape_ToolButton->setChecked(true);
709  }
710 
711 }
712 
713 //---------------------------------------------------------------------------------------------------------------------
714 /**
715  * Writes the values of some variables (like the margins, template and orientation of tiled pdf).
716  * of the save layout dialog into the settings.
717  *
718  * @brief ExportLayoutDialog::writeSettings
719  */
721 {
722  VSettings *settings = qApp->Seamly2DSettings();
723  const Unit unit = qApp->patternUnit();
724 
725  // Margins: left, top, right, bottom
726  QMarginsF margins = QMarginsF(ui->leftField_DoubleSpinBox->value(),
727  ui->topField_DoubleSpinBox->value(),
728  ui->rightField_DoubleSpinBox->value(),
729  ui->bottomField_DoubleSpinBox->value());
730 
731  settings->setTiledPDFMargins(margins,unit);
732  settings->setExportQuality(ui->quality_Slider->value());
733 
734  // write Template
735  PaperSizeTemplate temp;
736  temp = static_cast<PaperSizeTemplate>(ui->templates_ComboBox->currentData().toInt());
737  const QSizeF size = getTemplateSize(temp, Unit::Mm);
738 
739  settings->setTiledPDFPaperHeight(size.height(),Unit::Mm);
740  settings->setTiledPDFPaperWidth(size.width(),Unit::Mm);
741 
742  // write Orientation
743  if(ui->portrait_ToolButton->isChecked())
744  {
746  }
747  else
748  {
750  }
751 
752  //Export Format
753  if (qApp->Settings()->useLastExportFormat())
754  {
755  qApp->Settings()->setExportFormat(formatText());
756  }
757 }
758 
759 //---------------------------------------------------------------------------------------------------------------------
760 /**
761  * @brief modeString()
762  * @return Returns a string that is the mode type
763  */
765 {
766  QString modeStr = QStringLiteral();
767  if (qApp->Seamly2DSettings()->useModeType())
768  {
769  switch (m_mode)
770  {
771  case Draw::Calculation:
772  {
773  modeStr = QStringLiteral("_block");
774  break;
775  }
776  case Draw::Modeling:
777  {
778  modeStr = QStringLiteral("_pieces");
779  break;
780  }
781  case Draw::Layout:
782  default:
783  {
784  modeStr = QStringLiteral("_layout");
785  break;
786  }
787  }
788  }
789  return modeStr;
790 }
virtual void showEvent(QShowEvent *event) Q_DECL_OVERRIDE
void setDestinationPath(const QString &cmdDestinationPath)
LayoutExportFormat format() const
void readSettings()
ExportLayoutDialog::readSettings.
void initTemplates(QComboBox *templates)
QString modeString() const
modeString()
void pathChanged(const QString &text)
static QString exportFormatSuffix(LayoutExportFormat format)
QPushButton * m_SaveButton
ExportLayoutDialog(int count, Draw mode=Draw::Layout, const QString &fileName=QString(), QWidget *parent=nullptr)
void setTextAsPaths(bool textAsPaths)
void removeFormatFromList(LayoutExportFormat format)
void setBinaryDXFFormat(bool binary)
Ui::ExportLayoutDialog * ui
void writeSettings() const
ExportLayoutDialog::writeSettings.
void selectFormat(LayoutExportFormat format)
void initTemplates(QComboBox *comboBoxTemplates)
QSizeF getTemplateSize(const PaperSizeTemplate &tmpl, const Unit &unit) const
DialogLayoutSettings::TemplateSize.
static bool IsGUIMode()
int getExportQuality() const
void setExportQuality(const int &value)
The VException class parent for all exception. Could be use for abstract exception.
Definition: vexception.h:66
void setTiledPDFOrientation(PageOrientation value)
Definition: vsettings.cpp:752
void setTiledPDFMargins(const QMarginsF &value, const Unit &unit)
VSettings::setTiledPDFMargins sets the setting tiled pdf margins to the given value.
Definition: vsettings.cpp:667
void setTiledPDFPaperHeight(qreal value, const Unit &unit)
VSettings::setTiledPDFPaperHeight sets the tiled pdf paper height.
Definition: vsettings.cpp:702
qreal getTiledPDFPaperWidth(const Unit &unit) const
VSettings::getTiledPDFPaperWidth returns the paper height of tiled pdf in the desired unit.
Definition: vsettings.cpp:713
QMarginsF GetTiledPDFMargins(const Unit &unit) const
VSettings::GetTiledPDFMargins returns the tiled pdf margins in the given unit. When the setting is ca...
Definition: vsettings.cpp:646
qreal getTiledPDFPaperHeight(const Unit &unit) const
VSettings::getTiledPDFPaperHeight returns the paper height of tiled pdf in the desired unit.
Definition: vsettings.cpp:681
PageOrientation getTiledPDFOrientation() const
Definition: vsettings.cpp:742
void setTiledPDFPaperWidth(qreal value, const Unit &unit)
VSettings::setTiledPDFPaperWidth sets the tiled pdf paper width.
Definition: vsettings.cpp:736
#define SCASSERT(cond)
Definition: def.h:317
LayoutExportFormat
Definition: def.h:60
Unit
Definition: def.h:105
const QString fileNameRegExp
#define qApp
Definition: vapplication.h:67
Draw
Definition: vgeometrydef.h:55
@ Modeling
@ Calculation
@ Layout