Seamly2D
Code documentation
mainwindowsnogui.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  ** @file mainwindowsnogui.cpp
3  ** @author Douglas S Caskey
4  ** @date Dec 31, 2022
5  **
6  ** @copyright
7  ** Copyright (C) 2017 - 2022 Seamly, LLC
8  ** https://github.com/fashionfreedom/seamly2d
9  **
10  ** @brief
11  ** Seamly2D is free software: you can redistribute it and/or modify
12  ** it under the terms of the GNU General Public License as published by
13  ** the Free Software Foundation, either version 3 of the License, or
14  ** (at your option) any later version.
15  **
16  ** Seamly2D is distributed in the hope that it will be useful,
17  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  ** GNU General Public License for more details.
20  **
21  ** You should have received a copy of the GNU General Public License
22  ** along with Seamly2D. if not, see <http://www.gnu.org/licenses/>.
23  **************************************************************************/
24 
25 /************************************************************************
26  **
27  ** @file mainwindowsnogui.cpp
28  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
29  ** @date 12 5, 2015
30  **
31  ** @brief
32  ** @copyright
33  ** This source code is part of the Valentina project, a pattern making
34  ** program, whose allow create and modeling patterns of clothing.
35  ** Copyright (C) 2015 Valentina project
36  ** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
37  **
38  ** Valentina is free software: you can redistribute it and/or modify
39  ** it under the terms of the GNU General Public License as published by
40  ** the Free Software Foundation, either version 3 of the License, or
41  ** (at your option) any later version.
42  **
43  ** Valentina is distributed in the hope that it will be useful,
44  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
45  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46  ** GNU General Public License for more details.
47  **
48  ** You should have received a copy of the GNU General Public License
49  ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
50  **
51  *************************************************************************/
52 
53 #include "mainwindowsnogui.h"
54 #include "core/vapplication.h"
55 #include "../vpatterndb/vcontainer.h"
56 #include "../vobj/vobjpaintdevice.h"
57 #include "../vdxf/vdxfpaintdevice.h"
59 #include "../vwidgets/vmaingraphicsscene.h"
60 #include "../vlayout/vlayoutgenerator.h"
63 #include "../vlayout/vposter.h"
64 #include "../vpatterndb/floatItemData/vpiecelabeldata.h"
65 #include "../vpatterndb/floatItemData/vpatternlabeldata.h"
66 #include "../vpatterndb/floatItemData/vgrainlinedata.h"
67 #include "../vpatterndb/measurements.h"
68 #include "../vtools/tools/vabstracttool.h"
69 #include "../vtools/tools/pattern_piece_tool.h"
70 
71 #include <QFileDialog>
72 #include <QFileInfo>
73 #include <QGraphicsScene>
74 #include <QMessageBox>
75 #include <QProcess>
76 #include <QToolButton>
77 #include <QtSvg>
78 #include <QPrintPreviewDialog>
79 #include <QPrintDialog>
80 #include <QPrinterInfo>
81 #include <QImageWriter>
82 
83 #ifdef Q_OS_WIN
84 # define PDFTOPS "pdftops.exe"
85 #else
86 # define PDFTOPS "pdftops"
87 #endif
88 
89 namespace
90 {
91 bool CreateLayoutPath(const QString &path)
92 {
93  bool usedNotExistedDir = true;
94  QDir dir(path);
95  dir.setPath(path);
96  if (not dir.exists(path))
97  {
98  usedNotExistedDir = dir.mkpath(".");
99  }
100  return usedNotExistedDir;
101 }
102 
103 void RemoveLayoutPath(const QString &path, bool usedNotExistedDir)
104 {
105  if (usedNotExistedDir)
106  {
107  QDir dir(path);
108  dir.rmpath(".");
109  }
110 }
111 }
112 
113 //---------------------------------------------------------------------------------------------------------------------
115  : VAbstractMainWindow(parent),
116  pieceList(),
117  currentScene(nullptr),
118  tempSceneLayout(nullptr),
119  pattern(new VContainer(qApp->TrVars(), qApp->patternUnitP())),
120  doc(nullptr),
121  papers(),
122  shadows(),
123  scenes(),
124  pieces(),
125  piecesOnLayout(),
126  undoAction(nullptr),
127  redoAction(nullptr),
128  actionDockWidgetToolOptions(nullptr),
129  actionDockWidgetGroups(nullptr),
130  actionDockWidgetLayouts(nullptr),
131  actionDockWidgetToolbox(nullptr),
132  isNoScaling(false),
133  isLayoutStale(true),
134  ignoreMargins(false),
135  margins(),
136  paperSize(),
137  isTiled(false),
138  isAutoCrop(false),
139  isUnitePages(false),
140  layoutPrinterName()
141 
142 {
144 }
145 
146 //---------------------------------------------------------------------------------------------------------------------
148 {
149  delete tempSceneLayout;
150  delete pattern;
151 }
152 
153 //---------------------------------------------------------------------------------------------------------------------
154 void MainWindowsNoGUI::toolLayoutSettings(QToolButton *tButton, bool checked)
155 {
156  //QToolButton *tButton = qobject_cast< QToolButton * >(this->sender());
157  SCASSERT(tButton != nullptr)
158 
159  if (checked)
160  {
161  VLayoutGenerator lGenerator;
162 
163  DialogLayoutSettings layout(&lGenerator, this);
164  if (layout.exec() == QDialog::Rejected)
165  {
166  tButton->setChecked(false);
167  return;
168  }
170  LayoutSettings(lGenerator);
171  tButton->setChecked(false);
172  }
173  else
174  {
175  tButton->setChecked(true);
176  }
177 }
178 
179 //---------------------------------------------------------------------------------------------------------------------
181 {
182  lGenerator.setPieces(pieceList);
183  DialogLayoutProgress progress(pieceList.count(), this);
185  {
186  connect(&lGenerator, &VLayoutGenerator::Start, &progress, &DialogLayoutProgress::Start);
187  connect(&lGenerator, &VLayoutGenerator::Arranged, &progress, &DialogLayoutProgress::Arranged);
188  connect(&lGenerator, &VLayoutGenerator::Error, &progress, &DialogLayoutProgress::Error);
189  connect(&lGenerator, &VLayoutGenerator::Finished, &progress, &DialogLayoutProgress::Finished);
190  connect(&progress, &DialogLayoutProgress::Abort, &lGenerator, &VLayoutGenerator::Abort);
191  }
192  else
193  {
194  connect(&lGenerator, &VLayoutGenerator::Error, this, &MainWindowsNoGUI::ErrorConsoleMode);
195  }
196  lGenerator.Generate();
197 
198  switch (lGenerator.State())
199  {
201  CleanLayout();
202  papers = lGenerator.GetPapersItems();// Blank sheets
203  pieces = lGenerator.getAllPieceItems();// All pieces items
204  piecesOnLayout = lGenerator.getAllPieces();// All pieces items
208  ignoreMargins = not lGenerator.IsUsePrinterFields();
209  margins = lGenerator.GetPrinterFields();
210  paperSize = QSizeF(lGenerator.GetPaperWidth(), lGenerator.GetPaperHeight());
211  isAutoCrop = lGenerator.GetAutoCrop();
212  isUnitePages = lGenerator.IsUnitePages();
213  isLayoutStale = false;
215  {
216  QApplication::alert(this);
217  }
218  break;
223  {
224  QApplication::alert(this);
225  }
226  return false;
227  default:
228  break;
229 
230  }
231  return true;
232 }
233 //---------------------------------------------------------------------------------------------------------------------
235 {
236  switch (state)
237  {
239  return;
241  qCritical() << tr("Couldn't prepare data for creation layout");
242  break;
244  qCritical() << tr("One or more pattern pieces are bigger than the paper format you selected. Please select a bigger paper format.");
245  break;
247  default:
248  break;
249  }
250 
251  qApp->exit(V_EX_DATAERR);
252 }
253 
254 //---------------------------------------------------------------------------------------------------------------------
256 {
257  const LayoutExportFormat format = dialog.format();
258 
259  if (format == LayoutExportFormat::DXF_AC1006_AAMA ||
268  {
269  if (dialog.mode() == Draw::Layout)
270  {
271  for (int i = 0; i < piecesOnLayout.size(); ++i)
272  {
273  const QString name = QString("%1/%2_0%3%4")
274  .arg(dialog.path()) //1
275  .arg(dialog.fileName()) //2
276  .arg(QString::number(i+1)) //3
278 
279  QGraphicsRectItem *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(i));
280  SCASSERT(paper != nullptr)
281 
282  ExportApparelLayout(dialog, piecesOnLayout.at(i), name, paper->rect().size().toSize());
283  }
284  }
285  else
286  {
288  }
289  }
290  else
291  {
292  if (dialog.mode() == Draw::Layout)
293  {
295  }
296  else
297  {
299  }
300  }
301 }
302 
303 //---------------------------------------------------------------------------------------------------------------------
305  const QList<QGraphicsItem *> &papers, const QList<QGraphicsItem *> &shadows,
306  const QList<QList<QGraphicsItem *> > &pieces, bool ignoreMargins,
307  const QMarginsF &margins)
308 {
309  const QString path = dialog.path();
310  bool usedNotExistedDir = CreateLayoutPath(path);
311  if (not usedNotExistedDir)
312  {
313  qCritical() << tr("Can't create a path");
314  return;
315  }
316 
317  qApp->Seamly2DSettings()->SetPathLayout(path);
318  const LayoutExportFormat format = dialog.format();
319 
320  if (format == LayoutExportFormat::PDFTiled && dialog.mode() == Draw::Layout)
321  {
322  const QString name = QString("%1/%2%3")
323  .arg(path) //1
324  .arg(dialog.fileName()) //2
326 
327  PdfTiledFile(name);
328  }
329  else
330  {
332  }
333 
334  RemoveLayoutPath(path, usedNotExistedDir);
335 }
336 
337 //---------------------------------------------------------------------------------------------------------------------
339  const QVector<VLayoutPiece> &pieceList)
340 {
341  if (pieceList.isEmpty())
342  {
343  return;
344  }
345 
346  QScopedPointer<QGraphicsScene> scene(new QGraphicsScene());
347 
349  for (int i=0; i < pieceList.count(); ++i)
350  {
351  QGraphicsItem *item = pieceList.at(i).GetItem(dialog.isTextAsPaths());
352  item->setPos(pieceList.at(i).GetMx(), pieceList.at(i).GetMy());
353  list.append(item);
354  }
355 
356  for (int i=0; i < list.size(); ++i)
357  {
358  scene->addItem(list.at(i));
359  }
360 
361  QList<QGraphicsItem *> papers;// Blank sheets
362  QRect rect = scene->itemsBoundingRect().toRect();
363 
364  const int mx = rect.x();
365  const int my = rect.y();
366 
367  QTransform transform;
368  transform = transform.translate(-mx, -my);
369 
370  for (int i=0; i < list.size(); ++i)
371  {
372  list.at(i)->setTransform(transform);
373  }
374 
375  rect = scene->itemsBoundingRect().toRect();
376 
377  QGraphicsRectItem *paper = new QGraphicsRectItem(rect);
378  paper->setPen(QPen(Qt::black, 1));
379  paper->setBrush(QBrush(Qt::white));
380  papers.append(paper);
381 
382  QList<QList<QGraphicsItem *> > pieces;// All pieces
383  pieces.append(list);
384 
387 
388  const bool ignoreMargins = false;
389  const qreal margin = ToPixel(1, Unit::Cm);
391  QMarginsF(margin, margin, margin, margin));
392 
393  qDeleteAll(scenes);//Scene will clear all other items
394 }
395 
396 //---------------------------------------------------------------------------------------------------------------------
398  const QString &name, const QSize &size) const
399 {
400  const QString path = dialog.path();
401  bool usedNotExistedDir = CreateLayoutPath(path);
402  if (not usedNotExistedDir)
403  {
404  qCritical() << tr("Can't create a path");
405  return;
406  }
407 
408  qApp->Seamly2DSettings()->SetPathLayout(path);
409  const LayoutExportFormat format = dialog.format();
410 
411  switch (format)
412  {
422  Q_UNREACHABLE(); // For now not supported
423  break;
425  AAMADxfFile(name, DRW::AC1006, dialog.isBinaryDXFFormat(), size, pieces);
426  break;
428  AAMADxfFile(name, DRW::AC1009, dialog.isBinaryDXFFormat(), size, pieces);
429  break;
431  AAMADxfFile(name, DRW::AC1012, dialog.isBinaryDXFFormat(), size, pieces);
432  break;
434  AAMADxfFile(name, DRW::AC1014, dialog.isBinaryDXFFormat(), size, pieces);
435  break;
437  AAMADxfFile(name, DRW::AC1015, dialog.isBinaryDXFFormat(), size, pieces);
438  break;
440  AAMADxfFile(name, DRW::AC1018, dialog.isBinaryDXFFormat(), size, pieces);
441  break;
443  AAMADxfFile(name, DRW::AC1021, dialog.isBinaryDXFFormat(), size, pieces);
444  break;
446  AAMADxfFile(name, DRW::AC1024, dialog.isBinaryDXFFormat(), size, pieces);
447  break;
449  AAMADxfFile(name, DRW::AC1027, dialog.isBinaryDXFFormat(), size, pieces);
450  break;
451  default:
452  qDebug() << "Can't recognize file type." << Q_FUNC_INFO;
453  break;
454  }
455 
456  RemoveLayoutPath(path, usedNotExistedDir);
457 }
458 
459 //---------------------------------------------------------------------------------------------------------------------
461  QVector<VLayoutPiece> pieceList)
462 {
463  if (pieceList.isEmpty())
464  {
465  return;
466  }
467 
468  QScopedPointer<QGraphicsScene> scene(new QGraphicsScene());
469 
471  for (int i=0; i < pieceList.count(); ++i)
472  {
473  QGraphicsItem *item = pieceList.at(i).GetItem(dialog.isTextAsPaths());
474  item->setPos(pieceList.at(i).GetMx(), pieceList.at(i).GetMy());
475  list.append(item);
476  }
477 
478  for (int i=0; i < list.size(); ++i)
479  {
480  scene->addItem(list.at(i));
481  }
482 
483  QRect rect = scene->itemsBoundingRect().toRect();
484 
485  const int mx = rect.x();
486  const int my = rect.y();
487 
488  QTransform transform;
489  transform = transform.translate(-mx, -my);
490 
491  for (int i=0; i < list.size(); ++i)
492  {
493  list.at(i)->setTransform(transform);
494  }
495 
496  rect = scene->itemsBoundingRect().toRect();
497 
498  for (int i=0; i < pieceList.count(); ++i)
499  {
500  QTransform moveTransform = pieceList[i].getTransform();
501  moveTransform = moveTransform.translate(pieceList.at(i).GetMx(), pieceList.at(i).GetMy());
502  moveTransform = moveTransform.translate(-mx, -my);
503  pieceList[i].setTransform(moveTransform);
504  }
505 
506  QString increment = QStringLiteral("");
507  if (dialog.mode() == Draw::Layout)
508  {
509  increment = QStringLiteral("_01");
510  }
511 
512  const QString name = QString("%1/%2%3%4")
513  .arg(dialog.path()) //1
514  .arg(dialog.fileName()) //2
515  .arg(increment) //3
517 
518  ExportApparelLayout(dialog, pieceList, name, rect.size());
519 }
520 
521 //---------------------------------------------------------------------------------------------------------------------
522 void MainWindowsNoGUI::PrintPages(QPrinter *printer)
523 {
524  VSettings *settings = qApp->Seamly2DSettings();
525 
526  // Here we try to understand the difference between the printer's dpi and scene dpi.
527  // Get printer rect according to our dpi.
528  const QRectF printerPageRect(0, 0, ToPixel(printer->pageRect(QPrinter::Millimeter).width(), Unit::Mm),
529  ToPixel(printer->pageRect(QPrinter::Millimeter).height(), Unit::Mm));
530  QRect pageRect = printer->pageLayout().paintRectPixels(printer->resolution());
531  const double xscale = pageRect.width() / printerPageRect.width();
532  const double yscale = pageRect.height() / printerPageRect.height();
533  const double scale = qMin(xscale, yscale);
534 
535  QPainter painter;
536  if (not painter.begin(printer))
537  { // failed to open file
538  qWarning("failed to open file, is it writable?");
539  return;
540  }
541 
542  painter.setFont( QFont( "Arial", 8, QFont::Normal ) );
543  painter.setRenderHint(QPainter::Antialiasing, true);
544  painter.setPen(QPen(Qt::black, widthMainLine, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
545  painter.setBrush ( QBrush ( Qt::NoBrush ) );
546 
547  int count = 0;
549  QSharedPointer<VPoster> posterazor;
550 
551  if (isTiled)
552  {
553  // when isTiled, the landscape tiles have to be rotated, because the pages
554  // stay portrait in the pdf
556  {
557  painter.rotate(-90);
558  painter.translate(-ToPixel(printer->pageRect(QPrinter::Millimeter).height(),Unit::Mm), 0);
559  }
560 
562  posterazor = QSharedPointer<VPoster>(new VPoster(printer));
563 
564  for (int i=0; i < scenes.size(); ++i)
565  {
566 
567  auto *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(i));
568 
569  if (paper)
570  {
571  *poster += posterazor->Calc(paper->rect().toRect(), i, settings->getTiledPDFOrientation());
572  }
573  }
574 
575  count = poster->size();
576  }
577  else
578  {
579  count = scenes.size();
580  }
581 
582  // Handle the fromPage(), toPage(), supportsMultipleCopies(), and numCopies() values from QPrinter.
583  int firstPage = printer->fromPage() - 1;
584  if (firstPage >= count)
585  {
586  return;
587  }
588  if (firstPage == -1)
589  {
590  firstPage = 0;
591  }
592 
593  int lastPage = printer->toPage() - 1;
594  if (lastPage == -1 || lastPage >= count)
595  {
596  lastPage = count - 1;
597  }
598 
599  const int numPages = lastPage - firstPage + 1;
600  int copyCount = 1;
601  if (not printer->supportsMultipleCopies())
602  {
603  copyCount = printer->copyCount();
604  }
605 
606  for (int i = 0; i < copyCount; ++i)
607  {
608  for (int j = 0; j < numPages; ++j)
609  {
610  if (i != 0 || j != 0)
611  {
612  if (not printer->newPage())
613  {
614  qWarning("failed in flushing page to disk, disk full?");
615  return;
616  }
617  }
618  int index;
619  if (printer->pageOrder() == QPrinter::FirstPageFirst)
620  {
621  index = firstPage + j;
622  }
623  else
624  {
625  index = lastPage - j;
626  }
627 
628  int paperIndex = -1;
629  isTiled ? paperIndex = static_cast<int>(poster->at(index).index) : paperIndex = index;
630 
631  auto *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(paperIndex));
632  if (paper)
633  {
634  QVector<QGraphicsItem *> posterData;
635  if (isTiled)
636  {
637  // Draw borders
638  posterData = posterazor->Borders(paper, poster->at(index), scenes.size());
639  }
640 
641  PreparePaper(paperIndex);
642 
643  // Render
644  QRectF source;
645  isTiled ? source = poster->at(index).rect : source = paper->rect();
646 
647  qreal x,y;
648  if(printer->fullPage())
649  {
650  QMarginsF printerMargins = printer->pageLayout().margins();
651  x = qFloor(ToPixel(printerMargins.left(),Unit::Mm));
652  y = qFloor(ToPixel(printerMargins.top(),Unit::Mm));
653  }
654  else
655  {
656  x = 0; y = 0;
657  }
658 
659  QRectF target(x * scale, y * scale, source.width() * scale, source.height() * scale);
660 
661  scenes.at(paperIndex)->render(&painter, target, source, Qt::IgnoreAspectRatio);
662 
663  if (isTiled)
664  {
665  // Remove borders
666  qDeleteAll(posterData);
667  }
668 
669  // Restore
670  RestorePaper(paperIndex);
671  }
672  }
673  }
674 
675  painter.end();
676 }
677 
678 //---------------------------------------------------------------------------------------------------------------------
680 {
681  if (not isPagesUniform())
682  {
683  qCritical()<<tr("For previewing multipage document all sheet should have the same size.");
684  return;
685  }
686 
687  isTiled = false;
688  PrintPreview();
689 }
690 
691 //---------------------------------------------------------------------------------------------------------------------
693 {
694  isTiled = true;
695  PrintPreview();
696 }
697 
698 //---------------------------------------------------------------------------------------------------------------------
700 {
701  if (not isPagesUniform())
702  {
703  qCritical()<<tr("For printing multipages document all sheet should have the same size.");
704  return;
705  }
706 
707  isTiled = false;
708  LayoutPrint();
709 }
710 
711 //---------------------------------------------------------------------------------------------------------------------
713 {
714  isTiled = true;
715  LayoutPrint();
716 }
717 
718 //---------------------------------------------------------------------------------------------------------------------
719 /**
720  * @brief refreshLabels call to recalculate piece labels. For example after changing a font.
721  */
723 {
724  const QHash<quint32, VPiece> *list = pattern->DataPieces();
725  QHash<quint32, VPiece>::const_iterator i = list->constBegin();
726  while (i != list->constEnd())
727  {
728  if (PatternPieceTool *tool = qobject_cast<PatternPieceTool*>(VAbstractPattern::getTool(i.key())))
729  {
730  tool->UpdatePatternLabel();
731  tool->UpdatePieceLabel();
732  }
733  ++i;
734  }
735 }
736 
737 //---------------------------------------------------------------------------------------------------------------------
738 /**
739  * @brief refreshGrainLines call to recalculate piece grainlines. For example after show / hide grainlines.
740  */
742 {
743  const QHash<quint32, VPiece> *list = pattern->DataPieces();
744  QHash<quint32, VPiece>::const_iterator i = list->constBegin();
745  while (i != list->constEnd())
746  {
747  if (PatternPieceTool *tool = qobject_cast<PatternPieceTool*>(VAbstractPattern::getTool(i.key())))
748  {
749  tool->UpdateGrainline();
750  }
751  ++i;
752  }
753 }
754 
755 //---------------------------------------------------------------------------------------------------------------------
756 /**
757  * @brief refreshSeamAllowances call to show / hide seam allowances.
758  */
760 {
761  const QHash<quint32, VPiece> *list = pattern->DataPieces();
762  QHash<quint32, VPiece>::const_iterator i = list->constBegin();
763  while (i != list->constEnd())
764  {
765  if (PatternPieceTool *tool = qobject_cast<PatternPieceTool*>(VAbstractPattern::getTool(i.key())))
766  {
767  tool->RefreshGeometry();
768  }
769  ++i;
770  }
771 }
772 
773 //---------------------------------------------------------------------------------------------------------------------
775 {
777  if (not pieces.isEmpty())
778  {
780  while (i != pieces.constEnd())
781  {
782  VAbstractTool *tool = qobject_cast<VAbstractTool*>(VAbstractPattern::getTool(i.key()));
783  SCASSERT(tool != nullptr)
784  pieceList.append(VLayoutPiece::Create(i.value(), tool->getData()));
785  ++i;
786  }
787  }
788 
789  return pieceList;
790 }
791 
792 //---------------------------------------------------------------------------------------------------------------------
794 {
796  tempSceneLayout->setBackgroundBrush( QBrush(QColor(Qt::gray), Qt::SolidPattern) );
797 }
798 
799 //---------------------------------------------------------------------------------------------------------------------
801 {
802  QImage image;
803  QGraphicsRectItem *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(i));
804  if (paper)
805  {
806  const QRectF r = paper->rect();
807  // Create the image with the exact size of the shrunk scene
808  image = QImage(QSize(static_cast<qint32>(r.width()), static_cast<qint32>(r.height())), QImage::Format_RGB32);
809 
810  if (not image.isNull())
811  {
812  image.fill(Qt::white);
813  QPainter painter(&image);
814  painter.setFont( QFont( "Arial", 8, QFont::Normal ) );
815  painter.setRenderHint(QPainter::Antialiasing, true);
816  painter.setPen(QPen(Qt::black, widthMainLine, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
817  painter.setBrush ( QBrush ( Qt::NoBrush ) );
818  scenes.at(i)->render(&painter, r, r, Qt::IgnoreAspectRatio);
819  painter.end();
820  }
821  else
822  {
823  qWarning()<<"Cannot create image. Size too big";
824  }
825  }
826  else
827  {
828  image = QImage(QSize(101, 146), QImage::Format_RGB32);
829  image.fill(Qt::white);
830  }
831  return QIcon(QBitmap::fromImage(image));
832 }
833 
834 //---------------------------------------------------------------------------------------------------------------------
836 {
838 
839  for (int i=0; i< papers.size(); ++i)
840  {
841  qreal x1=0, y1=0, x2=0, y2=0;
842  QGraphicsRectItem *item = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(i));
843  if (item)
844  {
845  item->rect().getCoords(&x1, &y1, &x2, &y2);
846  QGraphicsRectItem *shadowPaper = new QGraphicsRectItem(QRectF(x1+4, y1+4, x2+4, y2+4));
847  shadowPaper->setBrush(QBrush(Qt::black));
848  shadows.append(shadowPaper);
849  }
850  else
851  {
852  shadows.append(nullptr);
853  }
854  }
855 
856  return shadows;
857 }
858 
859 //---------------------------------------------------------------------------------------------------------------------
861  const QList<QGraphicsItem *> &shadows,
862  const QList<QList<QGraphicsItem *> > &pieces)
863 {
865  for (int i=0; i<papers.size(); ++i)
866  {
867  QGraphicsScene *scene = new VMainGraphicsScene();
868  scene->setBackgroundBrush(QBrush(QColor(Qt::gray), Qt::SolidPattern));
869  scene->addItem(shadows.at(i));
870  scene->addItem(papers.at(i));
871 
872  QList<QGraphicsItem *> item = pieces.at(i);
873  for (int i=0; i < item.size(); ++i)
874  {
875  scene->addItem(item.at(i));
876  }
877 
878  scenes.append(scene);
879  }
880 
881  return scenes;
882 }
883 
884 //---------------------------------------------------------------------------------------------------------------------
885 /**
886  * @brief exportSVG save layout to svg file.
887  * @param fileName name layout file.
888  */
889 void MainWindowsNoGUI::exportSVG(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene) const
890 {
891  QSvgGenerator generator;
892  generator.setFileName(name);
893  generator.setSize(paper->rect().size().toSize());
894  generator.setViewBox(paper->rect());
895  generator.setTitle(tr("Pattern"));
896  generator.setDescription(doc->GetDescription());
897  generator.setResolution(static_cast<int>(PrintDPI));
898  QPainter painter;
899  painter.begin(&generator);
900  painter.setFont( QFont( "Arial", 8, QFont::Normal ) );
901  painter.setRenderHint(QPainter::Antialiasing, true);
902  //painter.setPen(QPen(Qt::black, widthHairLine, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
903  painter.setBrush ( QBrush ( Qt::NoBrush ) );
904  scene->render(&painter, paper->rect(), paper->rect(), Qt::IgnoreAspectRatio);
905  painter.end();
906 }
907 
908 //---------------------------------------------------------------------------------------------------------------------
909 /**
910  * @brief exportPNG save layout to png file.
911  * @param fileName name layout file.
912  */
913 void MainWindowsNoGUI::exportPNG(const QString &fileName, QGraphicsScene *scene) const
914 {
915  QImage image(scene->sceneRect().size().toSize(), QImage::Format_ARGB32);
916  image.fill(Qt::transparent); // Start all pixels transparent
917  QPainter painter(&image);
918  painter.setFont(qApp->Seamly2DSettings()->getLabelFont());
919  painter.setRenderHint(QPainter::Antialiasing, true);
920  painter.setBrush ( QBrush ( Qt::NoBrush ) );
921  scene->render(&painter);
922  image.save(fileName, "PNG", qApp->Seamly2DSettings()->getExportQuality());
923 }
924 
925 //---------------------------------------------------------------------------------------------------------------------
926 /**
927  * @brief exportTIF save layout to tif file.
928  * @param fileName name layout file.
929  */
930 void MainWindowsNoGUI::exportTIF(const QString &fileName, QGraphicsScene *scene) const
931 {
932  QImage image(scene->sceneRect().size().toSize(), QImage::Format_ARGB32);
933  image.fill(Qt::transparent); // Start all pixels transparent
934  QPainter painter(&image);
935  painter.setFont(qApp->Seamly2DSettings()->getLabelFont());
936  painter.setRenderHint(QPainter::Antialiasing, true);
937  painter.setBrush ( QBrush ( Qt::NoBrush ) );
938  scene->render(&painter);
939 
940  QImageWriter writer;
941  writer.setFormat("TIF");
942  writer.setCompression(1);
943  writer.setFileName(fileName);
944  writer.write(image);
945 }
946 
947 //---------------------------------------------------------------------------------------------------------------------
948 /**
949  * @brief exportJPG save layout to jpg file.
950  * @param fileName name layout file.
951  */
952 void MainWindowsNoGUI::exportJPG(const QString &fileName, QGraphicsScene *scene) const
953 {
954  QImage image(scene->sceneRect().size().toSize(), QImage::Format_ARGB32);
955  image.fill(Qt::white); // Start all pixels transparent
956  QPainter painter(&image);
957  painter.setFont(qApp->Seamly2DSettings()->getLabelFont());
958  painter.setRenderHint(QPainter::Antialiasing, true);
959  painter.setBrush ( QBrush ( Qt::NoBrush ) );
960  scene->render(&painter);
961  image.save(fileName, "JPG", qApp->Seamly2DSettings()->getExportQuality());
962 }
963 
964 //---------------------------------------------------------------------------------------------------------------------
965 /**
966  * @brief exportBMP save layout to bmp file.
967  * @param fileName name layout file.
968  */
969 void MainWindowsNoGUI::exportBMP(const QString &fileName, QGraphicsScene *scene) const
970 {
971  QImage image(scene->sceneRect().size().toSize(), QImage::Format_ARGB32);
972  image.fill(Qt::white); // Start all pixels transparent
973  QPainter painter(&image);
974  painter.setFont(qApp->Seamly2DSettings()->getLabelFont());
975  painter.setRenderHint(QPainter::Antialiasing, true);
976  painter.setBrush ( QBrush ( Qt::NoBrush ) );
977  scene->render(&painter);
978  image.save(fileName, "BMP", qApp->Seamly2DSettings()->getExportQuality());
979 }
980 
981 //---------------------------------------------------------------------------------------------------------------------
982 /**
983  * @brief exportPPM save layout to gif file.
984  * @param fileName name layout file.
985  */
986 void MainWindowsNoGUI::exportPPM(const QString &fileName, QGraphicsScene *scene) const
987 {
988  QImage image(scene->sceneRect().size().toSize(), QImage::Format_ARGB32);
989  image.fill(Qt::transparent); // Start all pixels transparent
990  QPainter painter(&image);
991  painter.setFont(qApp->Seamly2DSettings()->getLabelFont());
992  painter.setRenderHint(QPainter::Antialiasing, true);
993  painter.setBrush ( QBrush ( Qt::NoBrush ) );
994  scene->render(&painter);
995  image.save(fileName, "PPM", qApp->Seamly2DSettings()->getExportQuality());
996 }
997 
998 //---------------------------------------------------------------------------------------------------------------------
999 /**
1000  * @brief exportPDF save layout to pdf file.
1001  * @param fileName name layout file.
1002  */
1003 void MainWindowsNoGUI::exportPDF(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene,
1004  bool ignoreMargins, const QMarginsF &margins) const
1005 {
1006  QPrinter printer;
1007  printer.setCreator(QGuiApplication::applicationDisplayName()+QLatin1String(" ")+
1008  QCoreApplication::applicationVersion());
1009  printer.setOutputFormat(QPrinter::PdfFormat);
1010  printer.setOutputFileName(name);
1011  printer.setDocName(FileName());
1012  printer.setResolution(static_cast<int>(PrintDPI));
1013  printer.setPageOrientation(QPageLayout::Portrait);
1014  printer.setFullPage(ignoreMargins);
1015 
1016  const QRectF sourceRect = paper->rect();
1017  const QRectF targetRect = QRectF(QPoint(0,0), QPoint(sourceRect.width(),sourceRect.height()));
1018  QSizeF size(FromPixel(sourceRect.width() + margins.left() + margins.right(), Unit::Mm),
1019  FromPixel(sourceRect.height() + margins.top() + margins.bottom(), Unit::Mm));
1020  QPageSize pageSize(size, QPageSize::Unit::Millimeter);
1021  printer.setPageSize(pageSize);
1022 
1023  if (!ignoreMargins)
1024  {
1025  const qreal left = FromPixel(margins.left(), Unit::Mm);
1026  const qreal top = FromPixel(margins.top(), Unit::Mm);
1027  const qreal right = FromPixel(margins.right(), Unit::Mm);
1028  const qreal bottom = FromPixel(margins.bottom(), Unit::Mm);
1029 
1030  const bool success = printer.setPageMargins(QMarginsF(left, top, right, bottom), QPageLayout::Millimeter);
1031  if (!success)
1032  {
1033  qWarning() << tr("Cannot set printer margins");
1034  }
1035  }
1036 
1037  QPainter painter;
1038  if (painter.begin(&printer) == false)
1039  {
1040  qCritical("%s", qUtf8Printable(tr("Can't open printer %1").arg(name))); // failed to open file
1041  return;
1042  }
1043  painter.setFont(QFont( "Arial", 8, QFont::Normal));
1044  painter.setRenderHint(QPainter::Antialiasing, true);
1045  painter.setPen(QPen(Qt::black, widthMainLine, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
1046  painter.setBrush(QBrush(Qt::NoBrush));
1047  scene->render(&painter, targetRect, sourceRect, Qt::KeepAspectRatio);
1048  painter.end();
1049 }
1050 
1051 //---------------------------------------------------------------------------------------------------------------------
1052 void MainWindowsNoGUI::PdfTiledFile(const QString &name)
1053 {
1054  isTiled = true;
1055 
1056  if (isLayoutStale)
1057  {
1058  if (ContinueIfLayoutStale() == QMessageBox::No)
1059  {
1060  return;
1061  }
1062  }
1063  QPrinter printer;
1065 
1066  // Call IsPagesFit after setting a printer settings and check if pages is not bigger than printer's paper size
1067  if (not isTiled && not IsPagesFit(printer.pageLayout().fullRectPixels(printer.resolution()).size()))
1068  {
1069  qWarning()<<tr("Pages will be cropped because they do not fit printer paper size.");
1070  }
1071 
1072  printer.setOutputFileName(name);
1073  printer.setResolution(static_cast<int>(PrintDPI));
1074  PrintPages( &printer );
1075 }
1076 
1077 //---------------------------------------------------------------------------------------------------------------------
1078 /**
1079  * @brief exportEPS( save layout to eps file.
1080  * @param fileName name layout file.
1081  */
1082 void MainWindowsNoGUI::exportEPS(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene,
1083  bool ignoreMargins, const QMarginsF &margins) const
1084 {
1085  QTemporaryFile tmp;
1086  if (tmp.open())
1087  {
1088  exportPDF(tmp.fileName(), paper, scene, ignoreMargins, margins);
1089  QStringList params = QStringList() << "-eps" << tmp.fileName() << name;
1090  convertPdfToPs(params);
1091  }
1092 }
1093 
1094 //---------------------------------------------------------------------------------------------------------------------
1095 /**
1096  * @brief exportPS save layout to ps file.
1097  * @param fileName name layout file.
1098  */
1099 void MainWindowsNoGUI::exportPS(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene, bool
1100  ignoreMargins, const QMarginsF &margins) const
1101 {
1102  QTemporaryFile tmp;
1103  if (tmp.open())
1104  {
1105  exportPDF(tmp.fileName(), paper, scene, ignoreMargins, margins);
1106  QStringList params = QStringList() << tmp.fileName() << name;
1107  convertPdfToPs(params);
1108  }
1109 }
1110 
1111 //---------------------------------------------------------------------------------------------------------------------
1112 /**
1113  * @brief convertPdfToPs use external tool "pdftops" for converting pdf to eps or ps format.
1114  * @param params string with parameter for tool. Parameters have format: "-eps input_file out_file". Use -eps when
1115  * need create eps file.
1116  */
1117 void MainWindowsNoGUI::convertPdfToPs(const QStringList &params) const
1118 {
1119 #ifndef QT_NO_CURSOR
1120  QGuiApplication::setOverrideCursor(Qt::WaitCursor);
1121 #endif
1122  QProcess proc;
1123 #if defined(Q_OS_MAC)
1124  // Fix issue #594. Broken export on Mac.
1125  proc.setWorkingDirectory(qApp->applicationDirPath());
1126  proc.start(QLatin1String("./") + PDFTOPS, params);
1127 #else
1128  proc.start(PDFTOPS, params);
1129 #endif
1130  if (proc.waitForStarted(15000))
1131  {
1132  proc.waitForFinished(15000);
1133  }
1134 #ifndef QT_NO_CURSOR
1135  QGuiApplication::restoreOverrideCursor();
1136 #endif
1137 
1138  QFile f(params.last());
1139  if (f.exists() == false)
1140  {
1141  const QString msg = tr("Creating file '%1' failed! %2").arg(params.last()).arg(proc.errorString());
1142  QMessageBox msgBox(QMessageBox::Critical, tr("Critical error!"), msg, QMessageBox::Ok | QMessageBox::Default);
1143  msgBox.exec();
1144  }
1145 }
1146 
1147 //---------------------------------------------------------------------------------------------------------------------
1148 void MainWindowsNoGUI::ObjFile(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene) const
1149 {
1150  VObjPaintDevice generator;
1151  generator.setFileName(name);
1152  generator.setSize(paper->rect().size().toSize());
1153  generator.setResolution(static_cast<int>(PrintDPI));
1154  QPainter painter;
1155  painter.begin(&generator);
1156  scene->render(&painter, paper->rect(), paper->rect(), Qt::IgnoreAspectRatio);
1157  painter.end();
1158 }
1159 
1160 //---------------------------------------------------------------------------------------------------------------------
1161 QT_WARNING_PUSH
1162 QT_WARNING_DISABLE_GCC("-Wswitch-default")
1163 
1164 void MainWindowsNoGUI::FlatDxfFile(const QString &name, int version, bool binary, QGraphicsRectItem *paper,
1165  QGraphicsScene *scene, const QList<QList<QGraphicsItem *> > &pieces) const
1166 {
1167  PrepareTextForDXF(endStringPlaceholder, pieces);
1168  VDxfPaintDevice generator;
1169  generator.setFileName(name);
1170  generator.setSize(paper->rect().size().toSize());
1171  generator.setResolution(PrintDPI);
1172  generator.SetVersion(static_cast<DRW::Version>(version));
1173  generator.SetBinaryFormat(binary);
1174  generator.setInsunits(VarInsunits::Millimeters);// Decided to always use mm. See issue #745
1175 
1176  QPainter painter;
1177  if (painter.begin(&generator))
1178  {
1179  scene->render(&painter, paper->rect(), paper->rect(), Qt::IgnoreAspectRatio);
1180  painter.end();
1181  }
1182  RestoreTextAfterDXF(endStringPlaceholder, pieces);
1183 }
1184 
1185 //---------------------------------------------------------------------------------------------------------------------
1186 void MainWindowsNoGUI::AAMADxfFile(const QString &name, int version, bool binary, const QSize &size,
1187  const QVector<VLayoutPiece> &pieces) const
1188 {
1189  VDxfPaintDevice generator;
1190  generator.setFileName(name);
1191  generator.setSize(size);
1192  generator.setResolution(PrintDPI);
1193  generator.SetVersion(static_cast<DRW::Version>(version));
1194  generator.SetBinaryFormat(binary);
1195  generator.setInsunits(VarInsunits::Millimeters);// Decided to always use mm. See issue #745
1196  generator.ExportToAAMA(pieces);
1197 }
1198 
1200 
1201 //---------------------------------------------------------------------------------------------------------------------
1202 void MainWindowsNoGUI::PreparePaper(int index) const
1203 {
1204  auto *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(index));
1205  if (paper)
1206  {
1207  QBrush brush(Qt::white);
1208  scenes.at(index)->setBackgroundBrush(brush);
1209  shadows.at(index)->setVisible(false);
1210  paper->setPen(QPen(Qt::white, 0.1, Qt::NoPen));// border
1211  }
1212 
1213 }
1214 
1215 //---------------------------------------------------------------------------------------------------------------------
1216 void MainWindowsNoGUI::RestorePaper(int index) const
1217 {
1218  auto *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(index));
1219  if (paper)
1220  {
1221  // Restore
1222  paper->setPen(QPen(Qt::black, widthMainLine));
1223  QBrush brush(Qt::gray);
1224  scenes.at(index)->setBackgroundBrush(brush);
1225  shadows.at(index)->setVisible(true);
1226  }
1227 }
1228 
1229 //---------------------------------------------------------------------------------------------------------------------
1230 /**
1231  * @brief PrepareTextForDXF prepare QGraphicsSimpleTextItem items for export to flat dxf.
1232  *
1233  * Because QPaintEngine::drawTextItem doesn't pass whole string per time we mark end of each string by adding special
1234  * placeholder. This method append it.
1235  *
1236  * @param placeholder placeholder that will be appended to each QGraphicsSimpleTextItem item's text string.
1237  */
1238 void MainWindowsNoGUI::PrepareTextForDXF(const QString &placeholder,
1239  const QList<QList<QGraphicsItem *> > &pieces) const
1240 {
1241  for (int i = 0; i < pieces.size(); ++i)
1242  {
1243  const QList<QGraphicsItem *> &paperItems = pieces.at(i);
1244  for (int j = 0; j < paperItems.size(); ++j)
1245  {
1246  QList<QGraphicsItem *> pieceChildren = paperItems.at(j)->childItems();
1247  for (int k = 0; k < pieceChildren.size(); ++k)
1248  {
1249  QGraphicsItem *item = pieceChildren.at(k);
1250  if (item->type() == QGraphicsSimpleTextItem::Type)
1251  {
1252  if(QGraphicsSimpleTextItem *textItem = qgraphicsitem_cast<QGraphicsSimpleTextItem *>(item))
1253  {
1254  textItem->setText(textItem->text() + placeholder);
1255  }
1256  }
1257  }
1258  }
1259  }
1260 }
1261 
1262 //---------------------------------------------------------------------------------------------------------------------
1263 /**
1264  * @brief MainWindowsNoGUI::RestoreTextAfterDXF restore QGraphicsSimpleTextItem items after export to flat dxf.
1265  *
1266  * Because QPaintEngine::drawTextItem doesn't pass whole string per time we mark end of each string by adding special
1267  * placeholder. This method remove it.
1268  *
1269  * @param placeholder placeholder that will be removed from each QGraphicsSimpleTextItem item's text string.
1270  */
1271 void MainWindowsNoGUI::RestoreTextAfterDXF(const QString &placeholder,
1272  const QList<QList<QGraphicsItem *> > &pieces) const
1273 {
1274  for (int i = 0; i < pieces.size(); ++i)
1275  {
1276  const QList<QGraphicsItem *> &paperItems = pieces.at(i);
1277  for (int j = 0; j < paperItems.size(); ++j)
1278  {
1279  QList<QGraphicsItem *> pieceChildren = paperItems.at(i)->childItems();
1280  for (int k = 0; k < pieceChildren.size(); ++k)
1281  {
1282  QGraphicsItem *item = pieceChildren.at(k);
1283  if (item->type() == QGraphicsSimpleTextItem::Type)
1284  {
1285  if(QGraphicsSimpleTextItem *textItem = qgraphicsitem_cast<QGraphicsSimpleTextItem *>(item))
1286  {
1287  QString text = textItem->text();
1288  text.replace(placeholder, "");
1289  textItem->setText(text);
1290  }
1291  }
1292  }
1293  }
1294  }
1295 }
1296 
1297 //---------------------------------------------------------------------------------------------------------------------
1299 {
1300  if (isLayoutStale)
1301  {
1302  if (ContinueIfLayoutStale() == QMessageBox::No)
1303  {
1304  return;
1305  }
1306  }
1307 
1308  QPrinterInfo info = QPrinterInfo::printerInfo(layoutPrinterName);
1309  if(info.isNull() || info.printerName().isEmpty())
1310  {
1311  info = QPrinterInfo::defaultPrinter();
1312  }
1313  QSharedPointer<QPrinter> printer = PreparePrinter(info);
1314  if (printer.isNull())
1315  {
1316  qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
1317  qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
1318  return;
1319  }
1320 
1322  printer->setResolution(static_cast<int>(PrintDPI));
1323  // display print preview dialog
1324  QPrintPreviewDialog preview(printer.data());
1325  connect(&preview, &QPrintPreviewDialog::paintRequested, this, &MainWindowsNoGUI::PrintPages);
1326  preview.exec();
1327 }
1328 
1329 //---------------------------------------------------------------------------------------------------------------------
1331 {
1332  if (isLayoutStale)
1333  {
1334  if (ContinueIfLayoutStale() == QMessageBox::No)
1335  {
1336  return;
1337  }
1338  }
1339  // display print dialog and if accepted print
1340  QPrinterInfo info = QPrinterInfo::printerInfo(layoutPrinterName);
1341  if(info.isNull() || info.printerName().isEmpty())
1342  {
1343  info = QPrinterInfo::defaultPrinter();
1344  }
1345  QSharedPointer<QPrinter> printer = PreparePrinter(info, QPrinter::HighResolution);
1346  if (printer.isNull())
1347  {
1348  qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
1349  qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
1350  return;
1351  }
1352 
1353  SetPrinterSettings(printer.data(), PrintType::PrintNative);
1354  QPrintDialog dialog(printer.data(), this );
1355  // If only user couldn't change page margins we could use method setMinMax();
1356  dialog.setOption(QPrintDialog::PrintCurrentPage, false);
1357  if ( dialog.exec() == QDialog::Accepted )
1358  {
1359  printer->setResolution(static_cast<int>(PrintDPI));
1360  PrintPages(printer.data());
1361  }
1362 }
1363 
1364 //---------------------------------------------------------------------------------------------------------------------
1365 void MainWindowsNoGUI::SetPrinterSettings(QPrinter *printer, const PrintType &printType)
1366 {
1367  SCASSERT(printer != nullptr)
1368  printer->setCreator(QGuiApplication::applicationDisplayName()+" "+QCoreApplication::applicationVersion());
1369  printer->setPageOrientation(QPageLayout::Orientation::Portrait);
1370 
1371  if (not isTiled)
1372  {
1373  QSizeF size = QSizeF(FromPixel(paperSize.width(), Unit::Mm), FromPixel(paperSize.height(), Unit::Mm));
1374  if (isAutoCrop || isUnitePages)
1375  {
1376  auto *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(0));
1377  if (paper)
1378  {
1379  size = QSizeF(FromPixel(paperSize.width(), Unit::Mm),
1380  FromPixel(paper->rect().height() + margins.top() + margins.bottom(), Unit::Mm));
1381  }
1382  }
1383 
1384  const QPageSize pSZ = FindQPrinterPageSize(size);
1385  if (pSZ.id() == QPageSize::Custom)
1386  {
1387  QPageSize pageSize(size, QPageSize::Unit::Millimeter);
1388  printer->setPageSize (pageSize);
1389  }
1390  else
1391  {
1392  printer->setPageSize (pSZ);
1393  }
1394  }
1395  else
1396  {
1397  VSettings *settings = qApp->Seamly2DSettings();
1398  QSizeF size = QSizeF(
1399  settings->getTiledPDFPaperWidth(Unit::Mm),
1400  settings->getTiledPDFPaperHeight(Unit::Mm)
1401 
1402  );
1403  const QPageSize pSZ = FindQPrinterPageSize(size);
1404  printer->setPageSize(pSZ);
1405  // no need to take custom into account, because custom isn't a format option for tiled pdf.
1406  }
1407 
1408 
1409  printer->setFullPage(true);
1410  //printer->setFullPage(ignoreMargins);
1411 
1412  qreal left, top, right, bottom;
1413 
1414  if (not isTiled)
1415  {
1416  QMarginsF pageMargin = QMarginsF(UnitConvertor(margins, Unit::Px, Unit::Mm));
1417  left = pageMargin.left();
1418  top = pageMargin.top();
1419  right = pageMargin.right();
1420  bottom = pageMargin.bottom();
1421  }
1422  else
1423  {
1424  VSettings *settings = qApp->Seamly2DSettings();
1425  QMarginsF pageMargin = QMarginsF(settings->GetTiledPDFMargins(Unit::Mm));
1427  {
1428  // because when painting we have a -90rotation in landscape modus,
1429  // see function PrintPages.
1430  left = pageMargin.bottom();
1431  top = pageMargin.left();
1432  right = pageMargin.top();
1433  bottom = pageMargin.right();
1434  }
1435  else
1436  {
1437  left = pageMargin.left();
1438  top = pageMargin.top();
1439  right = pageMargin.right();
1440  bottom = pageMargin.bottom();
1441  }
1442  }
1443 
1444  const bool success = printer->setPageMargins(QMarginsF(left, top, right, bottom), QPageLayout::Millimeter);
1445  if (not success)
1446  {
1447  qWarning() << tr("Cannot set printer margins");
1448  }
1449 
1450  switch(printType)
1451  {
1452  case PrintType::PrintPDF:
1453  {
1454  const QString outputFileName = QDir::homePath() + QDir::separator() + FileName();
1455  #ifdef Q_OS_WIN
1456  printer->setOutputFileName(outputFileName);
1457  #else
1458  printer->setOutputFileName(outputFileName + QLatin1String(".pdf"));
1459  #endif
1460 
1461  #ifdef Q_OS_MAC
1462  printer->setOutputFormat(QPrinter::NativeFormat);
1463  #else
1464  printer->setOutputFormat(QPrinter::PdfFormat);
1465  #endif
1466  break;
1467  }
1469  printer->setOutputFileName("");//Disable printing to file if was enabled.
1470  printer->setOutputFormat(QPrinter::NativeFormat);
1471  break;
1472  case PrintType::PrintPreview: /*do nothing*/
1473  default:
1474  break;
1475  }
1476 
1477  printer->setDocName(FileName());
1478 
1479  IsLayoutGrayscale() ? printer->setColorMode(QPrinter::GrayScale) : printer->setColorMode(QPrinter::Color);
1480 }
1481 
1482 //---------------------------------------------------------------------------------------------------------------------
1484 {
1485  const QRect target = QRect(0, 0, 100, 100);//Small image less memory need
1486 
1487  for (int i=0; i < scenes.size(); ++i)
1488  {
1489  auto *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(i));
1490  if (paper)
1491  {
1492  // Hide shadow and paper border
1493  PreparePaper(i);
1494 
1495  // Render png
1496  QImage image(target.size(), QImage::Format_RGB32);
1497  image.fill(Qt::white);
1498  QPainter painter(&image);
1499  painter.setPen(QPen(Qt::black, widthMainLine, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
1500  painter.setBrush ( QBrush ( Qt::NoBrush ) );
1501  scenes.at(i)->render(&painter, target, paper->rect(), Qt::KeepAspectRatio);
1502  painter.end();
1503 
1504  // Restore
1505  RestorePaper(i);
1506 
1507  if (not image.isGrayscale())
1508  {
1509  return false;
1510  }
1511  }
1512  }
1513 
1514  return true;
1515 }
1516 
1517 //---------------------------------------------------------------------------------------------------------------------
1518 /**
1519  * @brief MainWindowsNoGUI::FindTemplate
1520  * @param size has to be in Mm
1521  * @return
1522  */
1523 QPageSize MainWindowsNoGUI::FindQPrinterPageSize(const QSizeF &size) const
1524 {
1525  if (size == QSizeF(841, 1189))
1526  {
1527  return QPageSize(QPageSize::A0);
1528  }
1529 
1530  if (size == QSizeF(594, 841))
1531  {
1532  return QPageSize(QPageSize::A1);
1533  }
1534 
1535  if (size == QSizeF(420, 594))
1536  {
1537  return QPageSize(QPageSize::A2);
1538  }
1539 
1540  if (size == QSizeF(297, 420))
1541  {
1542  return QPageSize(QPageSize::A3);
1543  }
1544 
1545  if (size == QSizeF(210, 297))
1546  {
1547  return QPageSize(QPageSize::A4);
1548  }
1549 
1550  if (size == QSizeF(215.9, 355.6))
1551  {
1552  return QPageSize(QPageSize::Legal);
1553  }
1554 
1555  if (size == QSizeF(215.9, 279.4))
1556  {
1557  return QPageSize(QPageSize::Letter);
1558  }
1559 
1560  return QPageSize(QPageSize::Custom);
1561 }
1562 
1563 //---------------------------------------------------------------------------------------------------------------------
1565 {
1566  if (papers.size() < 2)
1567  {
1568  return true;
1569  }
1570  else
1571  {
1572  auto *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(0));
1573  SCASSERT(paper != nullptr)
1574  for (int i=1; i < papers.size(); ++i)
1575  {
1576  auto *p = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(i));
1577  SCASSERT(p != nullptr)
1578  if (paper->rect() != p->rect())
1579  {
1580  return false;
1581  }
1582  }
1583  }
1584  return true;
1585 }
1586 
1587 //---------------------------------------------------------------------------------------------------------------------
1588 bool MainWindowsNoGUI::IsPagesFit(const QSizeF &printPaper) const
1589 {
1590  // On previous stage already was checked if pages have uniform size
1591  // Enough will be to check only one page
1592  QGraphicsRectItem *p = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(0));
1593  SCASSERT(p != nullptr)
1594  const QSizeF pSize = p->rect().size();
1595  if (pSize.height() <= printPaper.height() && pSize.width() <= printPaper.width())
1596  {
1597  return true;
1598  }
1599 
1600  return false;
1601 }
1602 
1603 //---------------------------------------------------------------------------------------------------------------------
1605  const QList<QGraphicsItem *> &papers, const QList<QGraphicsItem *> &shadows,
1606  const QList<QList<QGraphicsItem *> > &pieces, bool ignoreMargins,
1607  const QMarginsF &margins) const
1608 {
1609  for (int i=0; i < scenes.size(); ++i)
1610  {
1611  QString increment = QStringLiteral("");
1612  QGraphicsRectItem *paper = qgraphicsitem_cast<QGraphicsRectItem *>(papers.at(i));
1613  if (paper)
1614  {
1615  if (dialog.mode() == Draw::Layout)
1616  {
1617  increment = QStringLiteral("_0") + QString::number(i+1);
1618  }
1619  const QString name = QString("%1/%2%3%4")
1620  .arg(dialog.path()) //1
1621  .arg(dialog.fileName()) //2
1622  .arg(increment) //3
1623  .arg(ExportLayoutDialog::exportFormatSuffix(dialog.format())); //4
1624 
1625  QBrush *brush = new QBrush();
1626  brush->setColor( QColor( Qt::white ) );
1627  QGraphicsScene *scene = scenes.at(i);
1628  scene->setBackgroundBrush( *brush );
1629  shadows[i]->setVisible(false);
1630  paper->setPen(QPen(QBrush(Qt::white, Qt::NoBrush), 0.1, Qt::NoPen));
1631 
1632  switch (dialog.format())
1633  {
1635  paper->setVisible(false);
1636  exportSVG(name, paper, scene);
1637  paper->setVisible(true);
1638  break;
1640  exportPDF(name, paper, scene, ignoreMargins, margins);
1641  break;
1643  exportPNG(name, scene);
1644  break;
1646  exportJPG(name, scene);
1647  break;
1649  exportBMP(name, scene);
1650  break;
1652  exportTIF(name, scene);
1653  break;
1655  exportPPM(name, scene);
1656  break;
1658  paper->setVisible(false);
1659  ObjFile(name, paper, scene);
1660  paper->setVisible(true);
1661  break;
1663  exportPS(name, paper, scene, ignoreMargins, margins);
1664  break;
1666  exportEPS(name, paper, scene, ignoreMargins, margins);
1667  break;
1669  paper->setVisible(false);
1670  FlatDxfFile(name, DRW::AC1006, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1671  paper->setVisible(true);
1672  break;
1674  paper->setVisible(false);
1675  FlatDxfFile(name, DRW::AC1009, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1676  paper->setVisible(true);
1677  break;
1679  paper->setVisible(false);
1680  FlatDxfFile(name, DRW::AC1012, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1681  paper->setVisible(true);
1682  break;
1684  paper->setVisible(false);
1685  FlatDxfFile(name, DRW::AC1014, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1686  paper->setVisible(true);
1687  break;
1689  paper->setVisible(false);
1690  FlatDxfFile(name, DRW::AC1015, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1691  paper->setVisible(true);
1692  break;
1694  paper->setVisible(false);
1695  FlatDxfFile(name, DRW::AC1018, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1696  paper->setVisible(true);
1697  break;
1699  paper->setVisible(false);
1700  FlatDxfFile(name, DRW::AC1021, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1701  paper->setVisible(true);
1702  break;
1704  paper->setVisible(false);
1705  FlatDxfFile(name, DRW::AC1024, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1706  paper->setVisible(true);
1707  break;
1709  paper->setVisible(false);
1710  FlatDxfFile(name, DRW::AC1027, dialog.isBinaryDXFFormat(), paper, scene, pieces);
1711  paper->setVisible(true);
1712  break;
1713  default:
1714  qDebug() << "Can't recognize file type." << Q_FUNC_INFO;
1715  break;
1716  }
1717  paper->setPen(QPen(Qt::black, 1));
1718  brush->setColor( QColor( Qt::gray ) );
1719  brush->setStyle( Qt::SolidPattern );
1720  scenes[i]->setBackgroundBrush( *brush );
1721  shadows[i]->setVisible(true);
1722  delete brush;
1723  }
1724  }
1725 }
1726 
1727 //---------------------------------------------------------------------------------------------------------------------
1729 {
1730  QString fileName;
1731  qApp->getFilePath().isEmpty() ? fileName = tr("unnamed") : fileName = qApp->getFilePath();
1732  return QFileInfo(fileName).baseName();
1733 }
1734 
1735 //---------------------------------------------------------------------------------------------------------------------
1737 {
1739 
1740  if (vars->contains(size_M))
1741  {
1742  VContainer::SetSize(*vars->value(size_M)->GetValue());
1743  }
1744  else
1745  {
1747  }
1748 
1749  if (vars->contains(height_M))
1750  {
1751  VContainer::SetHeight(*vars->value(height_M)->GetValue());
1752  }
1753  else
1754  {
1756  }
1757 
1758  doc->SetPatternWasChanged(true);
1759  emit doc->UpdatePatternLabel();
1760 }
1761 
1762 //---------------------------------------------------------------------------------------------------------------------
1764 {
1765  QMessageBox msgBox(this);
1766  msgBox.setIcon(QMessageBox::Question);
1767  msgBox.setWindowTitle(tr("The layout is stale."));
1768  msgBox.setText(tr("The layout was not updated since last pattern modification. Do you want to continue?"));
1769  msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
1770  msgBox.setDefaultButton(QMessageBox::No);
1771  QSpacerItem* horizontalSpacer = new QSpacerItem(500, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
1772  QGridLayout* layout = static_cast<QGridLayout*>(msgBox.layout());
1773  SCASSERT(layout != nullptr)
1774  layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
1775  return msgBox.exec();
1776 }
void Error(const LayoutErrors &state)
LayoutExportFormat format() const
static QString exportFormatSuffix(LayoutExportFormat format)
void ExportApparelLayout(const ExportLayoutDialog &dialog, const QVector< VLayoutPiece > &pieces, const QString &name, const QSize &size) const
QGraphicsScene * tempSceneLayout
currentScene pointer to current scene.
virtual ~MainWindowsNoGUI() Q_DECL_OVERRIDE
void exportPPM(const QString &name, QGraphicsScene *scene) const
exportPPM save layout to gif file.
void PrepareTextForDXF(const QString &placeholder, const QList< QList< QGraphicsItem * > > &pieces) const
PrepareTextForDXF prepare QGraphicsSimpleTextItem items for export to flat dxf.
void exportSVG(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene) const
exportSVG save layout to svg file.
VContainer * pattern
pattern container with data (points, arcs, splines, spline paths, variables)
bool IsPagesFit(const QSizeF &printPaper) const
void ExportData(const QVector< VLayoutPiece > &pieceList, const ExportLayoutDialog &dialog)
void refreshLabels()
refreshLabels call to recalculate piece labels. For example after changing a font.
QVector< QVector< VLayoutPiece > > piecesOnLayout
void convertPdfToPs(const QStringList &params) const
convertPdfToPs use external tool "pdftops" for converting pdf to eps or ps format.
MainWindowsNoGUI(QWidget *parent=nullptr)
void AAMADxfFile(const QString &name, int version, bool binary, const QSize &size, const QVector< VLayoutPiece > &pieces) const
void exportTIF(const QString &name, QGraphicsScene *scene) const
exportTIF save layout to tif file.
void exportJPG(const QString &name, QGraphicsScene *scene) const
exportJPG save layout to jpg file.
void FlatDxfFile(const QString &name, int version, bool binary, QGraphicsRectItem *paper, QGraphicsScene *scene, const QList< QList< QGraphicsItem * > > &pieces) const
void PreparePaper(int index) const
void ObjFile(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene) const
void exportEPS(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene, bool ignoreMargins, const QMarginsF &margins) const
exportEPS( save layout to eps file.
QList< QList< QGraphicsItem * > > pieces
QList< QGraphicsItem * > shadows
bool isPagesUniform() const
virtual void PrepareSceneList()=0
QPageSize FindQPrinterPageSize(const QSizeF &size) const
MainWindowsNoGUI::FindTemplate.
static QVector< VLayoutPiece > preparePiecesForLayout(const QHash< quint32, VPiece > &pieces)
void ExportFlatLayout(const ExportLayoutDialog &dialog, const QList< QGraphicsScene * > &scenes, const QList< QGraphicsItem * > &papers, const QList< QGraphicsItem * > &shadows, const QList< QList< QGraphicsItem * > > &pieces, bool ignoreMargins, const QMarginsF &margins)
QList< QGraphicsItem * > papers
doc dom document container
QIcon ScenePreview(int i) const
void exportBMP(const QString &name, QGraphicsScene *scene) const
exportBMP save layout to bmp file.
bool IsLayoutGrayscale() const
void exportPNG(const QString &name, QGraphicsScene *scene) const
exportPNG save layout to png file.
virtual void CleanLayout()=0
void exportPDF(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene, bool ignoreMargins, const QMarginsF &margins) const
exportPDF save layout to pdf file.
QVector< VLayoutPiece > pieceList
void SetSizeHeightForIndividualM() const
void exportPiecesAsApparelLayout(const ExportLayoutDialog &dialog, QVector< VLayoutPiece > pieceList)
void RestorePaper(int index) const
void exportPS(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene, bool ignoreMargins, const QMarginsF &margins) const
exportPS save layout to ps file.
void ErrorConsoleMode(const LayoutErrors &state)
void PrintPages(QPrinter *printer)
static QList< QGraphicsScene * > CreateScenes(const QList< QGraphicsItem * > &papers, const QList< QGraphicsItem * > &shadows, const QList< QList< QGraphicsItem * > > &pieces)
void exportPiecesAsFlatLayout(const ExportLayoutDialog &dialog, const QVector< VLayoutPiece > &pieceList)
bool LayoutSettings(VLayoutGenerator &lGenerator)
void toolLayoutSettings(QToolButton *tButton, bool checked)
void SetPrinterSettings(QPrinter *printer, const PrintType &printType)
QList< QGraphicsScene * > scenes
VPattern * doc
pattern container with data (points, arcs, splines, spline paths, variables)
void refreshSeamAllowances()
refreshSeamAllowances call to show / hide seam allowances.
static QList< QGraphicsItem * > CreateShadows(const QList< QGraphicsItem * > &papers)
void refreshGrainLines()
refreshGrainLines call to recalculate piece grainlines. For example after show / hide grainlines.
void ExportScene(const ExportLayoutDialog &dialog, const QList< QGraphicsScene * > &scenes, const QList< QGraphicsItem * > &papers, const QList< QGraphicsItem * > &shadows, const QList< QList< QGraphicsItem * > > &pieces, bool ignoreMargins, const QMarginsF &margins) const
void PdfTiledFile(const QString &name)
QString FileName() const
void RestoreTextAfterDXF(const QString &placeholder, const QList< QList< QGraphicsItem * > > &pieces) const
MainWindowsNoGUI::RestoreTextAfterDXF restore QGraphicsSimpleTextItem items after export to flat dxf.
void SetPatternWasChanged(bool changed)
QString GetDescription() const
void UpdatePatternLabel()
static VDataTool * getTool(quint32 id)
getTool return tool from tool list.
The VAbstractTool abstract class for all tools.
Definition: vabstracttool.h:80
const VContainer * getData() const
getData return pointer to data container.
static bool IsGUIMode()
The VContainer class container of all variables.
Definition: vcontainer.h:141
static void SetSize(qreal size)
SetSize set value of size.
Definition: vcontainer.cpp:654
const QHash< quint32, VPiece > * DataPieces() const
Definition: vcontainer.cpp:712
const QHash< QString, QSharedPointer< VInternalVariable > > * DataVariables() const
Definition: vcontainer.cpp:718
static void SetHeight(qreal height)
SetGrowth set value of growth.
Definition: vcontainer.cpp:664
void setInsunits(const VarInsunits &var)
bool ExportToAAMA(const QVector< VLayoutPiece > &details) const
void setFileName(const QString &value)
void SetBinaryFormat(bool binary)
void setResolution(double dpi)
void SetVersion(DRW::Version version)
void setSize(const QSize &size)
qreal GetPaperHeight() const
Q_REQUIRED_RESULT QList< QGraphicsItem * > GetPapersItems() const
void Arranged(int count)
void setPieces(const QVector< VLayoutPiece > &details)
Q_REQUIRED_RESULT QList< QList< QGraphicsItem * > > getAllPieceItems() const
bool IsUnitePages() const
bool GetAutoCrop() const
qreal GetPaperWidth() const
QMarginsF GetPrinterFields() const
LayoutErrors State() const
void Error(const LayoutErrors &state)
QVector< QVector< VLayoutPiece > > getAllPieces() const
bool IsUsePrinterFields() const
static VLayoutPiece Create(const VPiece &piece, const VContainer *pattern)
The VMainGraphicsScene class main scene.
void setResolution(int dpi)
void setSize(const QSize &size)
void setFileName(const QString &value)
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
double ToPixel(double val, const Unit &unit)
Definition: def.cpp:231
QSharedPointer< QPrinter > PreparePrinter(const QPrinterInfo &info, QPrinter::PrinterMode mode)
Definition: def.cpp:440
const qreal PrintDPI
Definition: def.cpp:228
double FromPixel(double pix, const Unit &unit)
Definition: def.cpp:250
qreal UnitConvertor(qreal value, const Unit &from, const Unit &to)
Definition: def.cpp:269
#define SCASSERT(cond)
Definition: def.h:317
LayoutExportFormat
Definition: def.h:60
const QString endStringPlaceholder
Definition: dxfdef.cpp:56
@ Custom
const qreal widthMainLine
Definition: global.cpp:60
#define PDFTOPS
const QString size_M
const QString height_M
void RemoveLayoutPath(const QString &path, bool usedNotExistedDir)
#define qApp
Definition: vapplication.h:67
@ Layout
LayoutErrors
Definition: vlayoutdef.h:60
static const auto V_EX_DATAERR
Definition: vsysexits.h:68