Seamly2D
Code documentation
mainwindow.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  * @file mainwindow.cpp
3  ** @author Douglas S Caskey
4  ** @date 29 Mar, 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  ** You should have received a copy of the GNU General Public License
15  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
16  **
17  *****************************************************************************/
18 
19 /************************************************************************
20  **
21  ** @file mainwindow.cpp
22  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
23  ** @date November 15, 2013
24  **
25  ** @brief
26  ** @copyright
27  ** This source code is part of the Valentine project, a pattern making
28  ** program, whose allow create and modeling patterns of clothing.
29  ** Copyright (C) 2013 Seamly2D project
30  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
31  **
32  ** Seamly2D is free software: you can redistribute it and/or modify
33  ** it under the terms of the GNU General Public License as published by
34  ** the Free Software Foundation, either version 3 of the License, or
35  ** (at your option) any later version.
36  **
37  ** Seamly2D is distributed in the hope that it will be useful,
38  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
39  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40  ** GNU General Public License for more details.
41  **
42  ** You should have received a copy of the GNU General Public License
43  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
44  **
45  *************************************************************************/
46 
47 #include "mainwindow.h"
48 #include "ui_mainwindow.h"
49 #include "../vgeometry/vspline.h"
50 #include "../ifc/exception/vexceptionobjecterror.h"
51 #include "../ifc/exception/vexceptionconversionerror.h"
52 #include "../ifc/exception/vexceptionemptyparameter.h"
53 #include "../ifc/exception/vexceptionwrongid.h"
54 #include "../ifc/exception/vexceptionundo.h"
55 #include "version.h"
56 #include "core/vapplication.h"
57 #include "../vmisc/customevents.h"
58 #include "../vmisc/vsettings.h"
59 #include "../vmisc/def.h"
60 #include "../vmisc/qxtcsvmodel.h"
61 #include "../vmisc/dialogs/dialogexporttocsv.h"
64 #include "options.h"
65 #include "../ifc/xml/vpatternconverter.h"
66 #include "../vmisc/logging.h"
67 #include "../vformat/vmeasurements.h"
68 #include "../ifc/xml/vvstconverter.h"
69 #include "../ifc/xml/vvitconverter.h"
70 #include "../vwidgets/vwidgetpopup.h"
71 #include "../vwidgets/vmaingraphicsscene.h"
72 #include "../vwidgets/mouse_coordinates.h"
73 #include "../vtools/tools/drawTools/drawtools.h"
74 #include "../vtools/dialogs/tooldialogs.h"
78 #include "tools/union_tool.h"
79 #include "dialogs/dialogs.h"
80 
81 #include "../vtools/undocommands/addgroup.h"
82 #include "../vtools/undocommands/label/showpointname.h"
83 #include "../vpatterndb/vpiecepath.h"
84 #include "../qmuparser/qmuparsererror.h"
85 #include "../vtools/dialogs/support/editlabeltemplate_dialog.h"
86 
87 #include <QInputDialog>
88 #include <QtDebug>
89 #include <QMessageBox>
90 #include <QShowEvent>
91 #include <QScrollBar>
92 #include <QFileDialog>
93 #include <QSourceLocation>
94 #include <QUndoStack>
95 #include <QAction>
96 #include <QProcess>
97 #include <QSettings>
98 #include <QTimer>
99 #include <QtGlobal>
100 #include <QDesktopWidget>
101 #include <QDesktopServices>
102 #include <chrono>
103 #include <thread>
104 #include <QFileSystemWatcher>
105 #include <QComboBox>
106 #include <QFontComboBox>
107 #include <QTextCodec>
108 #include <QDoubleSpinBox>
109 
110 #if defined(Q_OS_MAC)
111 #include <QMimeData>
112 #include <QDrag>
113 #endif //defined(Q_OS_MAC)
114 
115 QT_WARNING_PUSH
116 QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes")
117 QT_WARNING_DISABLE_INTEL(1418)
118 
119 Q_LOGGING_CATEGORY(vMainWindow, "v.mainwindow")
120 
122 
123 const QString autosavePrefix = QStringLiteral(".autosave");
124 
125 // String below need for getting translation for key Ctrl
126 const QString strQShortcut = QStringLiteral("QShortcut"); // Context
127 const QString strCtrl = QStringLiteral("Ctrl"); // String
128 
129 //---------------------------------------------------------------------------------------------------------------------
130 /**
131  * @brief MainWindow constructor.
132  * @param parent parent widget.
133  */
134 MainWindow::MainWindow(QWidget *parent)
135  : MainWindowsNoGUI(parent)
136  , ui(new Ui::MainWindow)
137  , watcher(new QFileSystemWatcher(this))
138  , currentTool(Tool::Arrow)
139  , lastUsedTool(Tool::Arrow)
140  , draftScene(nullptr)
141  , pieceScene(nullptr)
142  , mouseCoordinates(nullptr)
143  , infoToolButton(nullptr)
144  , helpLabel(nullptr)
145  , isInitialized(false)
146  , mChanges(false)
147  , mChangesAsked(true)
148  , patternReadOnly(false)
149  , dialogTable(nullptr)
150  , dialogTool()
151  , historyDialog(nullptr)
152  , fontComboBox(nullptr)
153  , fontSizeComboBox(nullptr)
154  , draftBlockComboBox(nullptr)
155  , draftBlockLabel(nullptr)
156  , mode(Draw::Calculation)
157  , currentBlockIndex(0)
158  , currentToolBoxIndex(0)
159  , isToolOptionsDockVisible(true)
160  , isGroupsDockVisible(true)
161  , isLayoutsDockVisible(false)
162  , isToolboxDockVisible(true)
163  , drawMode(true)
164  , recentFileActs()
165  , separatorAct(nullptr)
166  , leftGoToStage(nullptr)
167  , rightGoToStage(nullptr)
168  , autoSaveTimer(nullptr)
169  , guiEnabled(true)
170  , gradationHeights(nullptr)
171  , gradationSizes(nullptr)
172  , gradationHeightsLabel(nullptr)
173  , gradationSizesLabel(nullptr)
174  , toolProperties(nullptr)
175  , groupsWidget(nullptr)
176  , patternPiecesWidget(nullptr)
177  , lock(nullptr)
178  , zoomScaleSpinBox(nullptr)
179  , m_penToolBar(nullptr)
180  , m_penReset(nullptr)
181  , m_zoomToPointComboBox(nullptr)
182 {
183  for (int i = 0; i < MaxRecentFiles; ++i)
184  {
185  recentFileActs[i] = nullptr;
186  }
187 
188  CreateActions();
189  InitScenes();
190  doc = new VPattern(pattern, &mode, draftScene, pieceScene);
191  connect(doc, &VPattern::ClearMainWindow, this, &MainWindow::Clear);
193  connect(doc, &VPattern::UndoCommand, this, &MainWindow::FullParseFile);
194  connect(doc, &VPattern::SetEnabledGUI, this, &MainWindow::SetEnabledGUI);
195  connect(doc, &VPattern::CheckLayout, this, [this]()
196  {
197  if (pattern->DataPieces()->count() == 0)
198  {
199  if(not ui->showDraftMode->isChecked())
200  {
201  showDraftMode(true);
202  }
203  }
204  });
206  connect(doc, &VPattern::CheckLayout, this, [&](){
207  this->updateZoomToPointComboBox(draftPointNamesList());
208  });
209  qApp->setCurrentDocument(doc);
210  qApp->setCurrentData(pattern);
211 
212  InitDocksContain();
213  CreateMenus();
214  initDraftToolBar();
215  initPointNameToolBar();
216  initModesToolBar();
217  InitToolButtons();
218  initPenToolBar();
219 
220  helpLabel = new QLabel(QObject::tr("Create new pattern piece to start working."));
221  ui->statusBar->addWidget(helpLabel);
222 
223  initToolsToolBar();
224 
225  connect(qApp->getUndoStack(), &QUndoStack::cleanChanged, this, &MainWindow::PatternChangesWereSaved);
226 
227  InitAutoSave();
228 
229  ui->draft_ToolBox->setCurrentIndex(0);
230 
231  ReadSettings();
232  initToolBarVisibility();
233 
234  setCurrentFile("");
235  WindowsLocale();
236 
237  connect(ui->listWidget, &QListWidget::currentRowChanged, this, &MainWindow::showLayoutPages);
238 
239  connect(watcher, &QFileSystemWatcher::fileChanged, this, &MainWindow::MeasurementsChanged);
240  connect(qApp, &QApplication::focusChanged, this, [this](QWidget *old, QWidget *now)
241  {
242  if (old == nullptr && isAncestorOf(now) == true)
243  {// focus IN
244  static bool asking = false;
245  if (not asking && mChanges && not mChangesAsked)
246  {
247  asking = true;
248  mChangesAsked = true;
249  const auto answer = QMessageBox::question(this, tr("Measurements"),
250  tr("Measurements were changed. Do you want to sync measurements now?"),
251  QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
252  if (answer == QMessageBox::Yes)
253  {
254  SyncMeasurements();
255  }
256  asking = false;
257  }
258  }
259 
260  // In case we will need it
261  // else if (isAncestorOf(old) == true && now == nullptr)
262  // focus OUT
263  });
264 
265 #if defined(Q_OS_MAC)
266  // On Mac default icon size is 32x32.
267  ui->draft_ToolBar->setIconSize(QSize(24, 24));
268  ui->mode_ToolBar->setIconSize(QSize(24, 24));
269  ui->edit_Toolbar->setIconSize(QSize(24, 24));
270  ui->zoom_ToolBar->setIconSize(QSize(24, 24));
271 
272  setUnifiedTitleAndToolBarOnMac(true);
273 
274  // Mac OS Dock Menu
275  QMenu *menu = new QMenu(this);
276 
277  QAction *newPattern_Action = menu->addAction(tr("New pattern"));
278  newPattern_Action->setMenuRole(QAction::NoRole);
279  connect(newPattern_Action, &QAction::triggered, this, &MainWindow::New);
280 
281  QAction *openPattern_Action = menu->addAction(tr("Open pattern"));
282  openPattern_Action->setMenuRole(QAction::NoRole);
283  connect(openPattern_Action, &QAction::triggered, this, &MainWindow::Open);
284 
285  QAction *openSeamlyMe_Action = menu->addAction(tr("Create/Edit measurements"));
286  openSeamlyMe_Action->setMenuRole(QAction::NoRole);
287  connect(openSeamlyMe_Action, &QAction::triggered, this, &MainWindow::CreateMeasurements);
288 
289  QAction *appPreferences_Action = menu->addAction(tr("Preferences"));
290  appPreferences_Action->setMenuRole(QAction::NoRole);
291  connect(appPreferences_Action, &QAction::triggered, this, &MainWindow::Preferences);
292 
293  menu->setAsDockMenu();
294 #endif //defined(Q_OS_MAC)
295 }
296 
297 //---------------------------------------------------------------------------------------------------------------------
298 void MainWindow::addDraftBlock(const QString &blockName)
299 {
300  if (doc->appendDraftBlock(blockName) == false)
301  {
302  qCDebug(vMainWindow, "Error creating draft block with the name %s.", qUtf8Printable(blockName));
303  return;
304  }
305 
306  if (draftBlockComboBox->count() == 0)
307  {
309  draftScene->enablePiecesMode(qApp->Seamly2DSettings()->getShowControlPoints());
311  }
312 
313  draftBlockComboBox->blockSignals(true);
314  draftBlockComboBox->addItem(blockName);
315 
317  //Create single point
318  ui->view->itemClicked(nullptr);//hide options previous tool
319  const QString label = doc->GenerateLabel(LabelType::NewPatternPiece);
320  const QPointF startPosition = draftBlockStartPosition();
321  VPointF *point = new VPointF(startPosition.x(), startPosition.y(), label, 5, 10);
322  auto spoint = VToolBasePoint::Create(0, blockName, point, draftScene, doc, pattern, Document::FullParse,
324  ui->view->itemClicked(spoint);
325 
326  setEnableTools(true);
327  SetEnableWidgets(true);
328 
329  const qint32 index = draftBlockComboBox->findText(blockName);
330  if ( index != -1 )
331  { // -1 for not found
332  draftBlockComboBox->setCurrentIndex(index);
333  }
334  else
335  {
336  draftBlockComboBox->setCurrentIndex(0);
337  }
338  draftBlockComboBox->blockSignals(false);
339 
340  // Show best for new PP
341  VMainGraphicsView::NewSceneRect(ui->view->scene(), ui->view, spoint);
342  ui->view->zoom100Percent();
343 
344  ui->newDraft_Action->setEnabled(true);
345  helpLabel->setText("");
347 }
348 
349 //---------------------------------------------------------------------------------------------------------------------
351 {
352  const qreal originX = 30.0;
353  const qreal originY = 40.0;
354  const qreal margin = 40.0;
355  if (draftBlockComboBox->count() > 1)
356  {
357  const QRectF rect = draftScene->visibleItemsBoundingRect();
358  if (rect.width() <= rect.height())
359  {
360  return QPointF(rect.width()+margin, originY);
361  }
362  else
363  {
364  return QPointF(originX, rect.height()+margin);
365  }
366  }
367  else
368  {
369  return QPointF(originX, originY);
370  }
371 }
372 
373 //---------------------------------------------------------------------------------------------------------------------
375 {
376  draftScene = new VMainGraphicsScene(this);
378  qApp->setCurrentScene(&currentScene);
381 
389 
397 
399 
400  pieceScene = new VMainGraphicsScene(this);
402 
406 
410 
412 
413  ui->view->setScene(currentScene);
414 
415  draftScene->setCurrentTransform(ui->view->transform());
416  pieceScene->setCurrentTransform(ui->view->transform());
417 
418  connect(ui->view, &VMainGraphicsView::mouseRelease, this, [this](){EndVisualization(true);});
420 
421  QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Expanding);
422  policy.setHorizontalStretch(12);
423  ui->view->setSizePolicy(policy);
424  qApp->setSceneView(ui->view);
425 }
426 
427 //---------------------------------------------------------------------------------------------------------------------
429 {
430  QSharedPointer<VMeasurements> measurements;
431  if (path.isEmpty())
432  {
433  return measurements;
434  }
435 
436  try
437  {
439  measurements->SetSize(VContainer::rsize());
440  measurements->SetHeight(VContainer::rheight());
441  measurements->setXMLContent(path);
442 
443  if (measurements->Type() == MeasurementsType::Unknown)
444  {
445  VException e(tr("Measurement file has unknown format."));
446  throw e;
447  }
448 
449  if (measurements->Type() == MeasurementsType::Multisize)
450  {
451  VVSTConverter converter(path);
452  measurements->setXMLContent(converter.Convert());// Read again after conversion
453  }
454  else
455  {
456  VVITConverter converter(path);
457  measurements->setXMLContent(converter.Convert());// Read again after conversion
458  }
459 
460  if (not measurements->IsDefinedKnownNamesValid())
461  {
462  VException e(tr("Measurement file contains invalid known measurement(s)."));
463  throw e;
464  }
465 
466  CheckRequiredMeasurements(measurements.data());
467 
468  if (measurements->Type() == MeasurementsType::Multisize)
469  {
470  if (measurements->MUnit() == Unit::Inch)
471  {
472  qCCritical(vMainWindow, "%s\n\n%s", qUtf8Printable(tr("Wrong units.")),
473  qUtf8Printable(tr("Application doesn't support multisize table with inches.")));
474  measurements->clear();
475  if (not VApplication::IsGUIMode())
476  {
477  qApp->exit(V_EX_DATAERR);
478  }
479  return measurements;
480  }
481  }
482  }
483  catch (VException &e)
484  {
485  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
486  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
487  measurements->clear();
488  if (not VApplication::IsGUIMode())
489  {
490  qApp->exit(V_EX_NOINPUT);
491  }
492  return measurements;
493  }
494  return measurements;
495 }
496 
497 //---------------------------------------------------------------------------------------------------------------------
498 bool MainWindow::LoadMeasurements(const QString &path)
499 {
501 
502  if (measurements->isNull())
503  {
504  return false;
505  }
506 
507  if (qApp->patternUnit() == Unit::Inch && measurements->Type() == MeasurementsType::Multisize)
508  {
509  qWarning()<<tr("Gradation doesn't support inches");
510  return false;
511  }
512 
513  try
514  {
515  qApp->setPatternType(measurements->Type());
516  initStatusBar();
518  measurements->ReadMeasurements();
519  }
520  catch (VExceptionEmptyParameter &e)
521  {
522  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
523  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
524  if (not VApplication::IsGUIMode())
525  {
526  qApp->exit(V_EX_NOINPUT);
527  }
528  return false;
529  }
530 
531  if (measurements->Type() == MeasurementsType::Multisize)
532  {
533  VContainer::SetSize(UnitConvertor(measurements->BaseSize(), measurements->MUnit(),
534  *measurements->GetData()->GetPatternUnit()));
535  VContainer::SetHeight(UnitConvertor(measurements->BaseHeight(), measurements->MUnit(),
536  *measurements->GetData()->GetPatternUnit()));
537 
538  doc->SetPatternWasChanged(true);
539  emit doc->UpdatePatternLabel();
540  }
541  else if (measurements->Type() == MeasurementsType::Individual)
542  {
544  }
545 
546  return true;
547 }
548 
549 //---------------------------------------------------------------------------------------------------------------------
550 bool MainWindow::UpdateMeasurements(const QString &path, int size, int height)
551 {
553 
554  if (measurements->isNull())
555  {
556  return false;
557  }
558 
559  if (qApp->patternType() != measurements->Type())
560  {
561  qCCritical(vMainWindow, "%s", qUtf8Printable(tr("Measurement files types have not match.")));
562  if (not VApplication::IsGUIMode())
563  {
564  qApp->exit(V_EX_DATAERR);
565  }
566  return false;
567  }
568 
569  try
570  {
572  measurements->ReadMeasurements();
573  }
574  catch (VExceptionEmptyParameter &e)
575  {
576  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
577  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
578  if (not VApplication::IsGUIMode())
579  {
580  qApp->exit(V_EX_NOINPUT);
581  }
582  return false;
583  }
584 
585  if (measurements->Type() == MeasurementsType::Multisize)
586  {
587  VContainer::SetSize(size);
588  VContainer::SetHeight(height);
589 
590  doc->SetPatternWasChanged(true);
591  emit doc->UpdatePatternLabel();
592  }
593  else if (measurements->Type() == MeasurementsType::Individual)
594  {
596  }
597 
598  return true;
599 }
600 
601 //---------------------------------------------------------------------------------------------------------------------
603 {
604  auto tempMeasurements = measurements->ListAll();
605  auto docMeasurements = doc->ListMeasurements();
606  const QSet<QString> match = QSet<QString>(docMeasurements.begin(), docMeasurements.end()).
607  subtract(QSet<QString>(tempMeasurements.begin(), tempMeasurements.end()));
608  if (not match.isEmpty())
609  {
610  QList<QString> list = match.values();
611  for (int i = 0; i < list.size(); ++i)
612  {
613  list[i] = qApp->TrVars()->MToUser(list.at(i));
614  }
615 
616  VException e(tr("Measurement file doesn't include all the required measurements."));
617  e.AddMoreInformation(tr("Please provide additional measurements: %1").arg(QStringList(list).join(", ")));
618  throw e;
619  }
620 }
621 
622 //---------------------------------------------------------------------------------------------------------------------
623 /**
624  * @brief SetToolButton set tool and show dialog.
625  * @param checked true if tool button checked.
626  * @param t tool type.
627  * @param cursor path tool cursor icon.
628  * @param toolTip first tooltipe.
629  * @param closeDialogSlot function what handle after close dialog.
630  */
631 template <typename Dialog, typename Func>
632 void MainWindow::SetToolButton(bool checked, Tool t, const QString &cursor, const QString &toolTip,
633  Func closeDialogSlot)
634 {
635  if (checked)
636  {
637  CancelTool();
638  emit EnableItemMove(false);
640  auto cursorResource = cursor;
641  if (qApp->devicePixelRatio() >= 2)
642  {
643  // Try to load HiDPI versions of the cursors if available
644  auto cursorHidpiResource = QString(cursor).replace(".png", "@2x.png");
645  if (QFileInfo(cursorResource).exists())
646  {
647  cursorResource = cursorHidpiResource;
648  }
649  }
650  QPixmap pixmap(cursorResource);
651  QCursor cur(pixmap, 2, 2);
652  ui->view->viewport()->setCursor(cur);
653  helpLabel->setText(toolTip);
654  ui->view->setShowToolOptions(false);
655  dialogTool = QSharedPointer<Dialog>(new Dialog(pattern, 0, this));
656 
657  switch(t)
658  {
660  dialogTool->setWindowTitle("Point - Intersect Arc and Axis");
661  break;
662  case Tool::Midpoint:
663  dialogTool->Build(t);
664  break;
665  case Tool::InternalPath:
666  case Tool::AnchorPoint:
667  case Tool::InsertNodes:
668  dialogTool->SetPiecesList(doc->getActivePatternPieces());
669  break;
670  default:
671  break;
672  }
673 
674  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
675  SCASSERT(scene != nullptr)
676 
679  connect(dialogTool.data(), &DialogTool::DialogClosed, this, closeDialogSlot);
680  connect(dialogTool.data(), &DialogTool::ToolTip, this, &MainWindow::ShowToolTip);
681  ui->view->itemClicked(nullptr);
682  }
683  else
684  {
685  if (QToolButton *tButton = qobject_cast< QToolButton * >(this->sender()))
686  {
687  tButton->setChecked(true);
688  }
689  }
690 }
691 
692 //---------------------------------------------------------------------------------------------------------------------
693 template <typename Dialog, typename Func, typename Func2>
694 /**
695  * @brief SetToolButtonWithApply set tool and show dialog.
696  * @param checked true if tool button checked.
697  * @param t tool type.
698  * @param cursor path tool cursor icon.
699  * @param toolTip first tooltipe.
700  * @param closeDialogSlot function to handle close of dialog.
701  * @param applyDialogSlot function to handle apply in dialog.
702  */
703 void MainWindow::SetToolButtonWithApply(bool checked, Tool t, const QString &cursor, const QString &toolTip,
704  Func closeDialogSlot, Func2 applyDialogSlot)
705 {
706  if (checked)
707  {
708  SetToolButton<Dialog>(checked, t, cursor, toolTip, closeDialogSlot);
709 
710  connect(dialogTool.data(), &DialogTool::DialogApplied, this, applyDialogSlot);
711  }
712  else
713  {
714  if (QToolButton *tButton = qobject_cast< QToolButton * >(this->sender()))
715  {
716  tButton->setChecked(true);
717  }
718  }
719 }
720 //---------------------------------------------------------------------------------------------------------------------
721 /**
722  * @brief ClosedDialog handle close dialog
723  * @param result result working dialog.
724  */
725 template <typename DrawTool>
726 void MainWindow::ClosedDialog(int result)
727 {
728  SCASSERT(not dialogTool.isNull())
729  if (result == QDialog::Accepted)
730  {
731  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
732  SCASSERT(scene != nullptr)
733 
734  QGraphicsItem *tool = dynamic_cast<QGraphicsItem *>(DrawTool::Create(dialogTool, scene, doc, pattern));
735  // Do not check for nullptr! See issue #719.
736  ui->view->itemClicked(tool);
737  }
738  handleArrowTool(true);
739 }
740 
741 //---------------------------------------------------------------------------------------------------------------------
742 /**
743  * @brief ClosedDialogWithApply handle close dialog that has apply button
744  * @param result result working dialog.
745  */
746 template <typename DrawTool>
748 {
749  SCASSERT(not dialogTool.isNull())
750  if (result == QDialog::Accepted)
751  {
752  ApplyDialog<DrawTool>(scene);
753  }
754  // If before Cancel was used Apply we have an item
755  DrawTool *vtool = qobject_cast<DrawTool *>(dialogTool->GetAssociatedTool());// Don't check for nullptr here
756  if (dialogTool->GetAssociatedTool() != nullptr)
757  {
758  SCASSERT(vtool != nullptr)
759  vtool->DialogLinkDestroy();
760  connect(vtool, &DrawTool::ToolTip, this, &MainWindow::ShowToolTip);
761  }
762  handleArrowTool(true);
763  ui->view->itemClicked(vtool);// Don't check for nullptr here
764  // If insert not to the end of file call lite parse
765  if (doc->getCursor() > 0)
766  {
768  if (historyDialog)
769  {
770  historyDialog->updateHistory();
771  }
772  }
773 }
774 
775 //---------------------------------------------------------------------------------------------------------------------
776 /**
777  * @brief ApplyDialog handle apply in dialog
778  */
779 template <typename DrawTool>
781 {
782  SCASSERT(not dialogTool.isNull())
783 
784  // Only create tool if not already created with apply
785  if (dialogTool->GetAssociatedTool() == nullptr)
786  {
787  SCASSERT(scene != nullptr)
788 
789  dialogTool->SetAssociatedTool(DrawTool::Create(dialogTool, scene, doc, pattern));
790  }
791  else
792  { // Or update associated tool with data
793  DrawTool * vtool = qobject_cast<DrawTool *>(dialogTool->GetAssociatedTool());
794  SCASSERT(vtool != nullptr)
795  vtool->FullUpdateFromGuiApply();
796  }
797 }
798 
799 //---------------------------------------------------------------------------------------------------------------------
800 template <typename DrawTool>
802 {
803  ClosedDialogWithApply<DrawTool>(result, draftScene);
804 }
805 
806 //---------------------------------------------------------------------------------------------------------------------
807 template <typename DrawTool>
809 {
810  ApplyDialog<DrawTool>(draftScene);
811 }
812 
813 //---------------------------------------------------------------------------------------------------------------------
814 template <typename DrawTool>
816 {
817  ClosedDialogWithApply<DrawTool>(result, pieceScene);
818  if (pattern->DataPieces()->size() > 0)
819  {
820  ui->anchorPoint_ToolButton->setEnabled(true);
821  ui->internalPath_ToolButton->setEnabled(true);
822  ui->insertNodes_ToolButton->setEnabled(true);
823  ui->anchorPoint_Action->setEnabled(true);
824  ui->internalPath_Action->setEnabled(true);
825  ui->insertNodes_Action->setEnabled(true);
826  }
827 }
828 
829 //---------------------------------------------------------------------------------------------------------------------
830 template <typename DrawTool>
832 {
833  ApplyDialog<DrawTool>(pieceScene);
834 }
835 
836 //Points
837 //---------------------------------------------------------------------------------------------------------------------
839 {
841  // Reuse DialogAlongLine and VToolAlongLine but with different cursor
842  SetToolButtonWithApply<DialogAlongLine>
843  (
844  checked,
846  ":/cursor/midpoint_cursor.png",
847  tr("<b>Tool::Point - Midpoint on Line</b>: Select first point"),
848  &MainWindow::ClosedDrawDialogWithApply<VToolAlongLine>,
849  &MainWindow::ApplyDrawDialog<VToolAlongLine>
850  );
851 }
852 
853 //---------------------------------------------------------------------------------------------------------------------
854 /**
855  * @brief handlePointAtDistanceAngleTool handler for handlePointAtDistanceAngle tool.
856  * @param checked true - button checked.
857  */
859 {
861  SetToolButtonWithApply<DialogEndLine>
862  (
863  checked,
865  ":/cursor/endline_cursor.png",
866  tr("<b>Tool::Point - Length and Angle</b>: Select point"),
867  &MainWindow::ClosedDrawDialogWithApply<VToolEndLine>,
868  &MainWindow::ApplyDrawDialog<VToolEndLine>
869  );
870 }
871 
872 //---------------------------------------------------------------------------------------------------------------------
873 /**
874  * @brief handleAlongLineTool handler for point along Line tools.
875  * @param checked true - button checked.
876  */
878 {
880  SetToolButtonWithApply<DialogAlongLine>
881  (
882  checked,
884  ":/cursor/alongline_cursor.png",
885  tr("<b>Tool::Point - On Line:</b> Select first point"),
886  &MainWindow::ClosedDrawDialogWithApply<VToolAlongLine>,
887  &MainWindow::ApplyDrawDialog<VToolAlongLine>
888  );
889 }
890 
891 //---------------------------------------------------------------------------------------------------------------------
892 /**
893  * @brief handleNormalTool handler point on perpendicular tool.
894  * @param checked true - button checked.
895  */
897 {
899  SetToolButtonWithApply<DialogNormal>
900  (
901  checked,
902  Tool::Normal,
903  ":/cursor/normal_cursor.png",
904  tr("<b>Tool::Point - On Perpendicular:</b> Select first point of line"),
905  &MainWindow::ClosedDrawDialogWithApply<VToolNormal>,
906  &MainWindow::ApplyDrawDialog<VToolNormal>
907  );
908 }
909 
910 //---------------------------------------------------------------------------------------------------------------------
911 /**
912  * @brief handleBisectorTool handler for bisector tool.
913  * @param checked true - button checked.
914  */
916 {
918  SetToolButtonWithApply<DialogBisector>
919  (
920  checked,
922  ":/cursor/bisector_cursor.png",
923  tr("<b>Tool::Point - On Bisector:</b> Select first point of angle"),
924  &MainWindow::ClosedDrawDialogWithApply<VToolBisector>,
925  &MainWindow::ApplyDrawDialog<VToolBisector>
926  );
927 }
928 
929 //---------------------------------------------------------------------------------------------------------------------
930 /**
931  * @brief handleShoulderPointTool handler for shoulderPoint tool.
932  * @param checked true - button checked.
933  */
935 {
937  SetToolButtonWithApply<DialogShoulderPoint>
938  (
939  checked,
941  ":/cursor/shoulder_cursor.png",
942  tr("<b>Tool::Point - Length to Line:</b> Select point"),
943  &MainWindow::ClosedDrawDialogWithApply<VToolShoulderPoint>,
944  &MainWindow::ApplyDrawDialog<VToolShoulderPoint>
945  );
946 }
947 
948 //---------------------------------------------------------------------------------------------------------------------
949 /**
950  * @brief handlePointOfContactTool handler for pointOfContact tool.
951  * @param checked true - button checked.
952  */
954 {
956  SetToolButtonWithApply<DialogPointOfContact>
957  (
958  checked, Tool::PointOfContact,
959  ":/cursor/pointcontact_cursor.png",
960  tr("<b>Tool::Point - Intersect Arc and Line:</b> Select first point of line"),
961  &MainWindow::ClosedDrawDialogWithApply<VToolPointOfContact>,
962  &MainWindow::ApplyDrawDialog<VToolPointOfContact>
963  );
964 }
965 
966 //---------------------------------------------------------------------------------------------------------------------
967 /**
968  * @brief handleTriangleTool handler Point - Intersect Axis and Triangle.
969  * @param checked true - button checked.
970  */
972 {
974  SetToolButtonWithApply<DialogTriangle>
975  (
976  checked,
978  ":/cursor/triangle_cursor.png",
979  tr("<b>Tool::Point - Intersect Axis and Triangle:</b> Select first point of axis"),
980  &MainWindow::ClosedDrawDialogWithApply<VToolTriangle>,
981  &MainWindow::ApplyDrawDialog<VToolTriangle>
982  );
983 }
984 
985 //---------------------------------------------------------------------------------------------------------------------
986 /**
987  * @brief handlePointIntersectXYTool handler for pointOfIntersection tool.
988  * @param checked true - button checked.
989  */
991 {
993  SetToolButtonWithApply<PointIntersectXYDialog>
994  (
995  checked,
997  ":/cursor/pointofintersect_cursor.png",
998  tr("<b>Tool::Point - Intersect XY</b> Select point for X value (vertical)"),
999  &MainWindow::ClosedDrawDialogWithApply<PointIntersectXYTool>,
1000  &MainWindow::ApplyDrawDialog<PointIntersectXYTool>
1001  );
1002 }
1003 
1004 //---------------------------------------------------------------------------------------------------------------------
1005 /**
1006  * @brief handleHeightTool handler tool height.
1007  * @param checked true - button checked.
1008  */
1010 {
1012  SetToolButtonWithApply<DialogHeight>
1013  (
1014  checked,
1015  Tool::Height,
1016  ":/cursor/height_cursor.png",
1017  tr("<b>Tool::Point - Intersect Line and Perpendicular:</b> Select base point"),
1018  &MainWindow::ClosedDrawDialogWithApply<VToolHeight>,
1019  &MainWindow::ApplyDrawDialog<VToolHeight>
1020  );
1021 }
1022 
1023 //---------------------------------------------------------------------------------------------------------------------
1025 {
1027  SetToolButtonWithApply<DialogLineIntersectAxis>
1028  (
1029  checked,
1031  ":/cursor/line_intersect_axis_cursor.png",
1032  tr("<b>Tool::Point - Intersect Line and Axis:</b> Select first point of line"),
1033  &MainWindow::ClosedDrawDialogWithApply<VToolLineIntersectAxis>,
1034  &MainWindow::ApplyDrawDialog<VToolLineIntersectAxis>
1035  );
1036 }
1037 
1038 //Lines
1039 //---------------------------------------------------------------------------------------------------------------------
1040 /**
1041  * @brief handleLineTool handler for line tool.
1042  * @param checked true - button checked.
1043  */
1044 void MainWindow::handleLineTool(bool checked)
1045 {
1047  SetToolButtonWithApply<DialogLine>
1048  (
1049  checked,
1050  Tool::Line,
1051  ":/cursor/line_cursor.png",
1052  tr("<b>Tool::Line:</b>:Select first point"),
1053  &MainWindow::ClosedDrawDialogWithApply<VToolLine>,
1054  &MainWindow::ApplyDrawDialog<VToolLine>
1055  );
1056 }
1057 
1058 //---------------------------------------------------------------------------------------------------------------------
1059 /**
1060  * @brief handleLineIntersectTool handler for lineIntersect tool.
1061  * @param checked true - button checked.
1062  */
1064 {
1066  SetToolButtonWithApply<DialogLineIntersect>
1067  (
1068  checked,
1070  ":/cursor/intersect_cursor.png",
1071  tr("<b>Tool::Point - Intersect Lines:</b> Select first point of first line"),
1072  &MainWindow::ClosedDrawDialogWithApply<VToolLineIntersect>,
1073  &MainWindow::ApplyDrawDialog<VToolLineIntersect>
1074  );
1075 }
1076 
1077 //Curves
1078 //---------------------------------------------------------------------------------------------------------------------
1079 /**
1080  * @brief handleCurveTool handler for curve tool.
1081  * @param checked true - button checked.
1082  */
1084 {
1086  SetToolButtonWithApply<DialogSpline>
1087  (
1088  checked,
1089  Tool::Spline,
1090  ":/cursor/spline_cursor.png",
1091  tr("<b>Tool::Curve - Interactive:</b> Select start point of curve"),
1092  &MainWindow::ClosedDrawDialogWithApply<VToolSpline>,
1093  &MainWindow::ApplyDrawDialog<VToolSpline>
1094  );
1095 }
1096 
1097 //---------------------------------------------------------------------------------------------------------------------
1098 /**
1099  * @brief handleSplineTool handler for spline tool.
1100  * @param checked true - button checked.
1101  */
1103 {
1105  SetToolButtonWithApply<DialogSplinePath>
1106  (
1107  checked,
1109  ":/cursor/splinepath_cursor.png",
1110  tr("<b>Tool::Spline - Interactive:</b> Select start point of spline"),
1111  &MainWindow::ClosedDrawDialogWithApply<VToolSplinePath>,
1112  &MainWindow::ApplyDrawDialog<VToolSplinePath>
1113  );
1114 }
1115 
1116 //---------------------------------------------------------------------------------------------------------------------
1118 {
1120  SetToolButtonWithApply<DialogCubicBezier>
1121  (
1122  checked,
1124  ":/cursor/cubic_bezier_cursor.png",
1125  tr("<b>Tool::Curve - Fixed:</b> Select first point of curve"),
1126  &MainWindow::ClosedDrawDialogWithApply<VToolCubicBezier>,
1127  &MainWindow::ApplyDrawDialog<VToolCubicBezier>
1128  );
1129 }
1130 
1131 //---------------------------------------------------------------------------------------------------------------------
1133 {
1135  SetToolButtonWithApply<DialogCubicBezierPath>
1136  (
1137  checked,
1139  ":/cursor/cubic_bezier_path_cursor.png",
1140  tr("<b>Tool::Spline - Fixed:</b> Select first point of spline"),
1141  &MainWindow::ClosedDrawDialogWithApply<VToolCubicBezierPath>,
1142  &MainWindow::ApplyDrawDialog<VToolCubicBezierPath>
1143  );
1144 }
1145 
1146 //---------------------------------------------------------------------------------------------------------------------
1147 /**
1148  * @brief handlePointAlongCurveTool handler for point along curve tool.
1149  * @param checked true - button is checked
1150  */
1152 {
1153  ToolSelectSpline();
1154  SetToolButtonWithApply<DialogCutSpline>
1155  (
1156  checked,
1158  ":/cursor/spline_cut_point_cursor.png",
1159  tr("<b>Tool::Point - On Curve:</b> Select first point of curve"),
1160  &MainWindow::ClosedDrawDialogWithApply<VToolCutSpline>,
1161  &MainWindow::ApplyDrawDialog<VToolCutSpline>
1162  );
1163 }
1164 
1165 //---------------------------------------------------------------------------------------------------------------------
1166 /**
1167  * @brief handlePointAlongSplineTool handler for point along spline tool.
1168  * @param checked true - button is checked
1169  */
1171 {
1173  SetToolButtonWithApply<DialogCutSplinePath>
1174  (
1175  checked,
1177  ":/cursor/splinepath_cut_point_cursor.png",
1178  tr("<b>Tool::Point - On Spline:</b> Select spline"),
1179  &MainWindow::ClosedDrawDialogWithApply<VToolCutSplinePath>,
1180  &MainWindow::ApplyDrawDialog<VToolCutSplinePath>
1181  );
1182 }
1183 
1184 //---------------------------------------------------------------------------------------------------------------------
1186 {
1187  ToolSelectCurve();
1188  SetToolButtonWithApply<DialogPointOfIntersectionCurves>
1189  (
1190  checked,
1192  "://cursor/intersection_curves_cursor.png",
1193  tr("<b>Tool::Point - Intersect Curves:</b> Select first curve"),
1194  &MainWindow::ClosedDrawDialogWithApply<VToolPointOfIntersectionCurves>,
1195  &MainWindow::ApplyDrawDialog<VToolPointOfIntersectionCurves>
1196  );
1197 }
1198 
1199 //---------------------------------------------------------------------------------------------------------------------
1201 {
1203  SetToolButtonWithApply<DialogCurveIntersectAxis>
1204  (
1205  checked,
1207  ":/cursor/curve_intersect_axis_cursor.png",
1208  tr("<b>Tool::Point - Intersect Curve and Axis:</b> Select curve"),
1209  &MainWindow::ClosedDrawDialogWithApply<VToolCurveIntersectAxis>,
1210  &MainWindow::ApplyDrawDialog<VToolCurveIntersectAxis>
1211  );
1212 }
1213 
1214 //Arcs
1215 //---------------------------------------------------------------------------------------------------------------------
1216 /**
1217  * @brief handleArcTool handler for arc tool.
1218  * @param checked true - button checked.
1219  */
1220 void MainWindow::handleArcTool(bool checked)
1221 {
1223  SetToolButtonWithApply<DialogArc>
1224  (
1225  checked,
1226  Tool::Arc,
1227  ":/cursor/arc_cursor.png",
1228  tr("<b>Tool::Arc - Radius and Angles:</b> Select point of center of arc"),
1229  &MainWindow::ClosedDrawDialogWithApply<VToolArc>,
1230  &MainWindow::ApplyDrawDialog<VToolArc>
1231  );
1232 }
1233 
1234 //---------------------------------------------------------------------------------------------------------------------
1235 /**
1236  * @brief handlePointAlongArcTool handler for PointAlongArc tool.
1237  * @param checked true - button checked.
1238  */
1240 {
1241  ToolSelectArc();
1242  SetToolButtonWithApply<DialogCutArc>
1243  (
1244  checked,
1245  Tool::CutArc,
1246  ":/cursor/arc_cut_cursor.png",
1247  tr("<b>Tool::Point - On Arc:</b> Select arc"),
1248  &MainWindow::ClosedDrawDialogWithApply<VToolCutArc>,
1249  &MainWindow::ApplyDrawDialog<VToolCutArc>
1250  );
1251 }
1252 
1253 //---------------------------------------------------------------------------------------------------------------------
1255 {
1257  // Reuse handleCurveIntersectAxisTool but with different cursor and tool tip
1258  SetToolButtonWithApply<DialogCurveIntersectAxis>
1259  (
1260  checked,
1262  ":/cursor/arc_intersect_axis_cursor.png",
1263  tr("<b>Tool::Point - Intersect Arc and Axis:</b> Select arc"),
1264  &MainWindow::ClosedDrawDialogWithApply<VToolCurveIntersectAxis>,
1265  &MainWindow::ApplyDrawDialog<VToolCurveIntersectAxis>
1266  );
1267 }
1268 
1269 //---------------------------------------------------------------------------------------------------------------------
1271 {
1272  ToolSelectArc();
1273  SetToolButtonWithApply<DialogPointOfIntersectionArcs>
1274  (
1275  checked,
1277  "://cursor/point_of_intersection_arcs.png",
1278  tr("<b>Tool::Point - Intersect Arcs:</b> Select first an arc"),
1279  &MainWindow::ClosedDrawDialogWithApply<VToolPointOfIntersectionArcs>,
1280  &MainWindow::ApplyDrawDialog<VToolPointOfIntersectionArcs>
1281  );
1282 }
1283 
1284 //---------------------------------------------------------------------------------------------------------------------
1286 {
1288  SetToolButtonWithApply<IntersectCirclesDialog>
1289  (
1290  checked,
1292  "://cursor/point_of_intersection_circles.png",
1293  tr("<b>Tool::Point - Intersect Circles:</b> Select first circle center"),
1294  &MainWindow::ClosedDrawDialogWithApply<IntersectCirclesTool>,
1295  &MainWindow::ApplyDrawDialog<IntersectCirclesTool>
1296  );
1297 }
1298 
1299 
1300 
1301 //---------------------------------------------------------------------------------------------------------------------
1303 {
1305  SetToolButtonWithApply<IntersectCircleTangentDialog>
1306  (
1307  checked,
1309  "://cursor/point_from_circle_and_tangent_cursor.png",
1310  tr("<b>Tool::Point - Intersect Circle and Tangent:</b> Select point on tangent"),
1311  &MainWindow::ClosedDrawDialogWithApply<IntersectCircleTangentTool>,
1312  &MainWindow::ApplyDrawDialog<IntersectCircleTangentTool>
1313  );
1314 }
1315 
1316 //---------------------------------------------------------------------------------------------------------------------
1318 {
1320  SetToolButtonWithApply<DialogPointFromArcAndTangent>
1321  (
1322  checked,
1324  "://cursor/point_from_arc_and_tangent_cursor.png",
1325  tr("<b>Tool::Point - Intersect Arc and Tangent:</b> Select point on tangent"),
1326  &MainWindow::ClosedDrawDialogWithApply<VToolPointFromArcAndTangent>,
1327  &MainWindow::ApplyDrawDialog<VToolPointFromArcAndTangent>
1328  );
1329 }
1330 
1331 //---------------------------------------------------------------------------------------------------------------------
1333 {
1335  SetToolButtonWithApply<DialogArcWithLength>
1336  (
1337  checked,
1339  "://cursor/arc_with_length_cursor.png",
1340  tr("<b>Tool::Arc - Radius and Length:</b> Select point of the center of the arc"),
1341  &MainWindow::ClosedDrawDialogWithApply<VToolArcWithLength>,
1342  &MainWindow::ApplyDrawDialog<VToolArcWithLength>
1343  );
1344 }
1345 
1346 //Elliptical Arcs
1347 //---------------------------------------------------------------------------------------------------------------------
1348 /**
1349  * @brief handleEllipticalArcTool handler for EllipticalArc tool.
1350  * @param checked true - button checked.
1351  */
1353 {
1355  SetToolButtonWithApply<DialogEllipticalArc>
1356  (
1357  checked,
1359  ":/cursor/el_arc_cursor.png",
1360  tr("<b>Tool::Arc - Elliptical:</b> Select point of center of elliptical arc"),
1361  &MainWindow::ClosedDrawDialogWithApply<VToolEllipticalArc>,
1362  &MainWindow::ApplyDrawDialog<VToolEllipticalArc>
1363  );
1364 }
1365 
1366 //Operations
1367 //---------------------------------------------------------------------------------------------------------------------
1369 {
1371  const QString tooltip = tr("<b>Tool::Operations - Create Group:</b> Select one or more objects -"
1372  " Hold <b>%1</b> for multiple selection, "
1373  "Press <b>ENTER</b> to finish group creation ")
1374  .arg(QCoreApplication::translate(strQShortcut.toUtf8().constData(),
1375  strCtrl.toUtf8().constData()));
1376  SetToolButton<AddToGroupDialog>
1377  (
1378  checked,
1379  Tool::Group,
1380  ":/cursor/group_cursor.png",
1381  tooltip,
1383  );
1384 }
1385 
1386 //---------------------------------------------------------------------------------------------------------------------
1388 {
1389  SCASSERT(dialogTool != nullptr)
1390  if (result == QDialog::Accepted)
1391  {
1393  SCASSERT(dialog != nullptr)
1394 
1395  QString gName = dialog->getName();
1396  QMap<quint32, quint32> gData = dialog->getGroupData();
1397  QDomElement group = doc->addGroupItems(gName, gData);
1398  if (group.isNull())
1399  {
1400  QMessageBox::information(this, tr("Add Group Objects"), tr("Group is Locked. Unlock to add objects"),
1401  QMessageBox::Ok, QMessageBox::Ok);
1402  }
1403  }
1404  handleArrowTool(true);
1405 }
1406 
1407 //---------------------------------------------------------------------------------------------------------------------
1409 {
1411  const QString tooltip = tr("<b>Tool::Operations - Rotation:</b> Select one or more objects -"
1412  " Hold <b>%1</b> for multiple selection, "
1413  "Press <b>ENTER</b> to confirm selection")
1414  .arg(QCoreApplication::translate(strQShortcut.toUtf8().constData(),
1415  strCtrl.toUtf8().constData()));
1416  SetToolButtonWithApply<DialogRotation>
1417  (
1418  checked,
1420  ":/cursor/rotation_cursor.png",
1421  tooltip,
1422  &MainWindow::ClosedDrawDialogWithApply<VToolRotation>,
1423  &MainWindow::ApplyDrawDialog<VToolRotation>
1424  );
1425 }
1426 
1427 //---------------------------------------------------------------------------------------------------------------------
1429 {
1431  const QString tooltip = tr("<b>Tool::Operations - Mirror by Line:</b> Select one or more objects -"
1432  " Hold <b>%1</b> for multiple selection, "
1433  "Press <b>ENTER</b> to confirm selection")
1434  .arg(QCoreApplication::translate(strQShortcut.toUtf8().constData(),
1435  strCtrl.toUtf8().constData()));
1436  SetToolButtonWithApply<DialogMirrorByLine>
1437  (
1438  checked,
1440  ":/cursor/mirror_by_line_cursor.png",
1441  tooltip, &MainWindow::ClosedDrawDialogWithApply<VToolMirrorByLine>,
1442  &MainWindow::ApplyDrawDialog<VToolMirrorByLine>
1443  );
1444 }
1445 
1446 //---------------------------------------------------------------------------------------------------------------------
1448 {
1450  const QString tooltip = tr("<b>Tool::Operations - Mirror by Axis:</b> Select one or more objects -"
1451  " Hold <b>%1</b> for multiple selection, "
1452  "Press <b>ENTER</b> to confirm selection")
1453  .arg(QCoreApplication::translate(strQShortcut.toUtf8().constData(),
1454  strCtrl.toUtf8().constData()));
1455  SetToolButtonWithApply<DialogMirrorByAxis>
1456  (
1457  checked,
1459  ":/cursor/mirror_by_axis_cursor.png",
1460  tooltip,
1461  &MainWindow::ClosedDrawDialogWithApply<VToolMirrorByAxis>,
1462  &MainWindow::ApplyDrawDialog<VToolMirrorByAxis>
1463  );
1464 }
1465 
1466 //---------------------------------------------------------------------------------------------------------------------
1467 void MainWindow::handleMoveTool(bool checked)
1468 {
1470  const QString tooltip = tr("<b>Tool::Operations - Move:</b> Select one or more objects -"
1471  " Hold <b>%1</b> for multiple selection, "
1472  "Press <b>ENTER</b> to confirm selection")
1473  .arg(QCoreApplication::translate(strQShortcut.toUtf8().constData(),
1474  strCtrl.toUtf8().constData()));
1475  SetToolButtonWithApply<DialogMove>
1476  (
1477  checked,
1478  Tool::Move,
1479  ":/cursor/move_cursor.png",
1480  tooltip,
1481  &MainWindow::ClosedDrawDialogWithApply<VToolMove>,
1482  &MainWindow::ApplyDrawDialog<VToolMove>
1483  );
1484 }
1485 
1486 //---------------------------------------------------------------------------------------------------------------------
1488 {
1490  SetToolButtonWithApply<DialogTrueDarts>
1491  (
1492  checked,
1494  "://cursor/true_darts_cursor.png",
1495  tr("<b>Tool::Operations - TrueDarts:</b> Select the first base line point"),
1496  &MainWindow::ClosedDrawDialogWithApply<VToolTrueDarts>,
1497  &MainWindow::ApplyDrawDialog<VToolTrueDarts>
1498  );
1499 }
1500 
1501 //---------------------------------------------------------------------------------------------------------------------
1502 /**
1503  * @brief handlePatternPieceTool handler for pattern piece tool.
1504  * @param checked true - button checked.
1505  */
1507 {
1509  SetToolButtonWithApply<PatternPieceDialog>
1510  (
1511  checked,
1512  Tool::Piece,
1513  ":/cursor/new_piece_cursor.png",
1514  tr("<b>Tool::Piece - Add New Pattern Piece:</b> Select main path of objects clockwise."),
1515  &MainWindow::ClosedPiecesDialogWithApply<PatternPieceTool>,
1516  &MainWindow::applyPiecesDialog<PatternPieceTool>
1517  );
1518 }
1519 
1520 //---------------------------------------------------------------------------------------------------------------------
1522 {
1524  SetToolButton<AnchorPointDialog>
1525  (
1526  checked,
1528  ":/cursor/anchor_point_cursor.png",
1529  tr("<b>Tool::Piece - Add Anchor Point:</b> Select anchor point"),
1531 }
1532 
1533 //---------------------------------------------------------------------------------------------------------------------
1535 {
1536  SCASSERT(dialogTool != nullptr);
1537  if (result == QDialog::Accepted)
1538  {
1540  }
1541  handleArrowTool(true);
1543 }
1544 
1545 //---------------------------------------------------------------------------------------------------------------------
1547 {
1549  SetToolButton<DialogInternalPath>
1550  (
1551  checked,
1553  ":/cursor/path_cursor.png",
1554  tr("<b>Tool::Piece - Internal Path:</b> Select path objects, use <b>SHIFT</b> to reverse curve direction"),
1556  );
1557 }
1558 
1559 //---------------------------------------------------------------------------------------------------------------------
1561 {
1562  SCASSERT(dialogTool != nullptr);
1563  if (result == QDialog::Accepted)
1564  {
1566  }
1567  handleArrowTool(true);
1569 }
1570 
1571 //---------------------------------------------------------------------------------------------------------------------
1573 {
1575  const QString tooltip = tr("<b>Tool::Piece - Insert Nodes:</b> Select one or more objects -"
1576  " Hold <b>%1</b> for multiple selection, "
1577  "Press <b>ENTER</b> to confirm selection")
1578  .arg(QCoreApplication::translate(strQShortcut.toUtf8().constData(),
1579  strCtrl.toUtf8().constData()));
1580  SetToolButton<InsertNodesDialog>
1581  (
1582  checked,
1584  "://cursor/insert_nodes_cursor.png",
1585  tooltip,
1587  );
1588 }
1589 
1590 //---------------------------------------------------------------------------------------------------------------------
1592 {
1593  SCASSERT(dialogTool != nullptr);
1594  if (result == QDialog::Accepted)
1595  {
1597  SCASSERT(tool != nullptr)
1598  PatternPieceTool::insertNodes(tool->getNodes(), tool->getPieceId(), pieceScene, pattern, doc);
1599  }
1600  handleArrowTool(true);
1602 }
1603 
1604 //---------------------------------------------------------------------------------------------------------------------
1605 /**
1606  * @brief handleUnionTool handler for Union tool.
1607  * @param checked true - button checked.
1608  */
1610 {
1611  selectPieceTool();
1612  SetToolButton<UnionDialog>
1613  (
1614  checked,
1615  Tool::Union,
1616  ":/cursor/union_cursor.png",
1617  tr("<b>Tool::Details - Union:</b> Select pattern piece"),
1619  );
1620 }
1621 
1622 //---------------------------------------------------------------------------------------------------------------------
1623 /**
1624  * @brief closeUnionDialog actions after closing Union tool dialog.
1625  * @param result result of dialog working.
1626  */
1628 {
1629  ClosedDialog<UnionTool>(result);
1631 }
1632 
1633 //---------------------------------------------------------------------------------------------------------------------
1634 /**
1635  * @brief handleNewLayout handler for New Layout tool.
1636  * @param tButton - toolbutton.
1637  * @param checked true - button checked.
1638  */
1640 {
1641  toolLayoutSettings(ui->layoutSettings_ToolButton, checked);
1642 }
1643 
1644 //---------------------------------------------------------------------------------------------------------------------
1645 /**
1646  * @brief ShowTool highlight tool.Tip show tools tooltip.
1647  * @param toolTip tooltip text.
1648  */
1649 void MainWindow::ShowToolTip(const QString &toolTip)
1650 {
1651  helpLabel->setText(toolTip);
1652 }
1653 
1654 //---------------------------------------------------------------------------------------------------------------------
1655 /**
1656  * @brief triggers the update of the groups
1657  */
1659 {
1661 }
1662 
1664 {
1666 }
1667 
1669 {
1671 }
1672 
1674 {
1676 }
1677 
1679 {
1681 }
1682 
1684 {
1686 }
1688 {
1690 }
1691 
1693 {
1695 }
1696 
1698 {
1699  qCDebug(vMainWindow, "Add Selected items to Group.");
1700 }
1701 
1702 //---------------------------------------------------------------------------------------------------------------------
1703 /**
1704  * @brief showEvent handle after show window.
1705  * @param event show event.
1706  */
1707 void MainWindow::showEvent( QShowEvent *event )
1708 {
1709  QMainWindow::showEvent( event );
1710  if ( event->spontaneous() )
1711  {
1712  return;
1713  }
1714 
1715  if (isInitialized)
1716  {
1717  return;
1718  }
1719  // do your init stuff here
1720 
1721  MinimumScrollBar();
1722 
1723  isInitialized = true;//first show windows are held
1724 }
1725 
1726 //---------------------------------------------------------------------------------------------------------------------
1727 void MainWindow::changeEvent(QEvent *event)
1728 {
1729  if (event->type() == QEvent::LanguageChange)
1730  {
1731  // retranslate designer form (single inheritance approach)
1732  ui->retranslateUi(this);
1733  undoAction->setText(tr("&Undo"));
1734  redoAction->setText(tr("&Redo"));
1735  helpLabel->setText(QObject::tr("Changes applied."));
1736  draftBlockLabel->setText(tr("Draft Block:"));
1738  emit pieceScene->LanguageChanged();
1739  }
1740  // remember to call base class implementation
1741  QMainWindow::changeEvent(event);
1742 }
1743 
1744 //---------------------------------------------------------------------------------------------------------------------
1745 /**
1746  * @brief closeEvent handle after close window.
1747  * @param event close event.
1748  */
1749 void MainWindow::closeEvent(QCloseEvent *event)
1750 {
1751  qCDebug(vMainWindow, "Closing main window");
1752  if (MaybeSave())
1753  {
1755 
1756  event->accept();
1757  QApplication::closeAllWindows();
1758  }
1759  else
1760  {
1761  qCDebug(vMainWindow, "Closing canceled.");
1762  event->ignore();
1763  }
1764 }
1765 
1766 //---------------------------------------------------------------------------------------------------------------------
1767 void MainWindow::customEvent(QEvent *event)
1768 {
1769  if (event->type() == UNDO_EVENT)
1770  {
1771  qApp->getUndoStack()->undo();
1772  }
1773 }
1774 
1775 //---------------------------------------------------------------------------------------------------------------------
1777 {
1778  qDeleteAll (scenes);
1779  scenes.clear();
1780  shadows.clear();
1781  papers.clear();
1782  ui->listWidget->clear();
1783  groupsWidget->clear();
1785 }
1786 
1787 //---------------------------------------------------------------------------------------------------------------------
1789 {
1790  for (int i=1; i<=scenes.size(); ++i)
1791  {
1792  QListWidgetItem *item = new QListWidgetItem(ScenePreview(i-1), QString::number(i));
1793  ui->listWidget->addItem(item);
1794  }
1795 
1796  if (not scenes.isEmpty())
1797  {
1798  ui->listWidget->setCurrentRow(0);
1800  }
1801 }
1802 
1803 //---------------------------------------------------------------------------------------------------------------------
1804 void MainWindow::exportToCSVData(const QString &fileName, const DialogExportToCSV &dialog)
1805 {
1806  QxtCsvModel csv;
1807 
1808  csv.insertColumn(0);
1809  csv.insertColumn(1);
1810  csv.insertColumn(2);
1811 
1812  if (dialog.WithHeader())
1813  {
1814  csv.setHeaderText(0, tr("Name"));
1815  csv.setHeaderText(1, tr("The calculated value"));
1816  csv.setHeaderText(2, tr("Formula"));
1817  }
1818 
1820  QMap<QString, QSharedPointer<VIncrement> >::const_iterator i;
1822  //Sorting QHash by id
1823  for (i = increments.constBegin(); i != increments.constEnd(); ++i)
1824  {
1825  QSharedPointer<VIncrement> incr = i.value();
1826  map.insert(incr->getIndex(), i.key());
1827  }
1828 
1829  qint32 currentRow = -1;
1830  QMapIterator<quint32, QString> iMap(map);
1831  while (iMap.hasNext())
1832  {
1833  iMap.next();
1834  QSharedPointer<VIncrement> incr = increments.value(iMap.value());
1835  currentRow++;
1836 
1837  csv.insertRow(currentRow);
1838  csv.setText(currentRow, 0, incr->GetName()); // name
1839  csv.setText(currentRow, 1, qApp->LocaleToString(*incr->GetValue())); // calculated value
1840 
1841  QString formula;
1842  try
1843  {
1844  formula = qApp->TrVars()->FormulaToUser(incr->GetFormula(), qApp->Settings()->GetOsSeparator());
1845  }
1846  catch (qmu::QmuParserError &e)
1847  {
1848  Q_UNUSED(e)
1849  formula = incr->GetFormula();
1850  }
1851 
1852  csv.setText(currentRow, 2, formula); // formula
1853  }
1854 
1855  csv.toCSV(fileName, dialog.WithHeader(), dialog.Separator(), QTextCodec::codecForMib(dialog.SelectedMib()));
1856 }
1857 
1859 {
1860  QString file = tr("untitled");
1861  if(!qApp->getFilePath().isEmpty())
1862  {
1863  QString filePath = qApp->getFilePath();
1864  file = QFileInfo(filePath).baseName();
1865  }
1866  exportToCSV(file);
1867 }
1868 
1869 //---------------------------------------------------------------------------------------------------------------------
1871 {
1872  const QString filter = tr("Individual measurements") + QLatin1String(" (*.vit);;") + tr("Multisize measurements") +
1873  QLatin1String(" (*.vst)");
1874  //Use standard path to individual measurements
1875  const QString path = qApp->Seamly2DSettings()->GetPathIndividualMeasurements();
1876 
1877  bool usedNotExistedDir = false;
1878  QDir directory(path);
1879  if (not directory.exists())
1880  {
1881  usedNotExistedDir = directory.mkpath(".");
1882  }
1883 
1884  const QString mPath = QFileDialog::getOpenFileName(this, tr("Open file"), path, filter, nullptr,
1885  QFileDialog::DontUseNativeDialog);
1886 
1887  if (not mPath.isEmpty())
1888  {
1889  if (LoadMeasurements(mPath))
1890  {
1891  if (not doc->MPath().isEmpty())
1892  {
1893  watcher->removePath(AbsoluteMPath(qApp->getFilePath(), doc->MPath()));
1894  }
1895  ui->unloadMeasurements_Action->setEnabled(true);
1896  doc->SetMPath(RelativeMPath(qApp->getFilePath(), mPath));
1897  watcher->addPath(mPath);
1898  PatternChangesWereSaved(false);
1899  ui->editCurrent_Action->setEnabled(true);
1900  helpLabel->setText(tr("Measurements loaded"));
1902 
1904  }
1905  }
1906 
1907  if (usedNotExistedDir)
1908  {
1909  QDir directory(path);
1910  directory.rmpath(".");
1911  }
1912 }
1913 
1914 //---------------------------------------------------------------------------------------------------------------------
1916 {
1917  const QString filter = tr("Multisize measurements") + QLatin1String(" (*.vst);;") + tr("Individual measurements") +
1918  QLatin1String("(*.vit)");
1919  //Use standard path to multisize measurements
1920  QString path = qApp->Seamly2DSettings()->GetPathMultisizeMeasurements();
1922  const QString mPath = QFileDialog::getOpenFileName(this, tr("Open file"), path, filter, nullptr,
1923  QFileDialog::DontUseNativeDialog);
1924 
1925  if (not mPath.isEmpty())
1926  {
1927  QString hText;
1928  if (not gradationHeights.isNull())
1929  {
1930  hText = gradationHeights->currentText();
1931  }
1932  QString sText;
1933  if (not gradationSizes.isNull())
1934  {
1935  sText = gradationSizes->currentText();
1936  }
1937 
1938  if(LoadMeasurements(mPath))
1939  {
1940  if (not doc->MPath().isEmpty())
1941  {
1942  watcher->removePath(AbsoluteMPath(qApp->getFilePath(), doc->MPath()));
1943  }
1944  ui->unloadMeasurements_Action->setEnabled(true);
1945  doc->SetMPath(RelativeMPath(qApp->getFilePath(), mPath));
1946  watcher->addPath(mPath);
1947  PatternChangesWereSaved(false);
1948  ui->editCurrent_Action->setEnabled(true);
1949  helpLabel->setText(tr("Measurements loaded"));
1951 
1953 
1954  if (qApp->patternType() == MeasurementsType::Multisize)
1955  {
1956  if (not hText.isEmpty() && not gradationHeights.isNull())
1957  {
1958  gradationHeights->setCurrentText(hText);
1959  }
1960 
1961  if (not sText.isEmpty() && not gradationSizes.isNull())
1962  {
1963  gradationSizes->setCurrentText(sText);
1964  }
1965  }
1966  }
1967  }
1968 }
1969 
1970 //---------------------------------------------------------------------------------------------------------------------
1972 {
1973  if (doc->MPath().isEmpty())
1974  {
1975  ui->unloadMeasurements_Action->setDisabled(true);
1976  return;
1977  }
1978 
1979  if (doc->ListMeasurements().isEmpty())
1980  {
1981  watcher->removePath(AbsoluteMPath(qApp->getFilePath(), doc->MPath()));
1982  if (qApp->patternType() == MeasurementsType::Multisize)
1983  {
1984  initStatusBar();
1985  }
1986  qApp->setPatternType(MeasurementsType::Unknown);
1987  doc->SetMPath(QString());
1988  emit doc->UpdatePatternLabel();
1989  PatternChangesWereSaved(false);
1990  ui->editCurrent_Action->setEnabled(false);
1991  ui->unloadMeasurements_Action->setDisabled(true);
1992  helpLabel->setText(tr("Measurements unloaded"));
1993 
1995  }
1996  else
1997  {
1998  qCWarning(vMainWindow, "%s",
1999  qUtf8Printable(tr("Couldn't unload measurements. Some of them are used in the pattern.")));
2000  }
2001 }
2002 
2003 //---------------------------------------------------------------------------------------------------------------------
2005 {
2006  if (not doc->MPath().isEmpty())
2007  {
2008  const QString absoluteMPath = AbsoluteMPath(qApp->getFilePath(), doc->MPath());
2009 
2010  QStringList arguments;
2011  if (qApp->patternType() == MeasurementsType::Multisize)
2012  {
2013  arguments = QStringList()
2014  << absoluteMPath
2015  << "-u"
2016  << UnitsToStr(qApp->patternUnit())
2017  << "-e"
2018  << QString().setNum(static_cast<int>(UnitConvertor(VContainer::height(), doc->MUnit(), Unit::Cm)))
2019  << "-s"
2020  << QString().setNum(static_cast<int>(UnitConvertor(VContainer::size(), doc->MUnit(), Unit::Cm)));
2021  }
2022  else
2023  {
2024  arguments = QStringList() << absoluteMPath
2025  << "-u"
2026  << UnitsToStr(qApp->patternUnit());
2027  }
2028 
2029  if (isNoScaling)
2030  {
2031  arguments.append(QLatin1String("--") + LONG_OPTION_NO_HDPI_SCALING);
2032  }
2033 
2034  const QString seamlyme = qApp->SeamlyMeFilePath();
2035  const QString workingDirectory = QFileInfo(seamlyme).absoluteDir().absolutePath();
2036  QProcess::startDetached(seamlyme, arguments, workingDirectory);
2037  }
2038  else
2039  {
2040  ui->editCurrent_Action->setEnabled(false);
2041  }
2042 }
2043 
2044 //---------------------------------------------------------------------------------------------------------------------
2045 void MainWindow::MeasurementsChanged(const QString &path)
2046 {
2047  mChanges = false;
2048  QFileInfo checkFile(path);
2049  if (checkFile.exists())
2050  {
2051  mChanges = true;
2052  mChangesAsked = false;
2053  }
2054  else
2055  {
2056  for(int i=0; i<=1000; i=i+10)
2057  {
2058  if (checkFile.exists())
2059  {
2060  mChanges = true;
2061  mChangesAsked = false;
2062  break;
2063  }
2064  else
2065  {
2066  std::this_thread::sleep_for(std::chrono::milliseconds(10));
2067  }
2068  }
2069  }
2070 
2072  ui->syncMeasurements_Action->setEnabled(mChanges);
2073 }
2074 
2075 //---------------------------------------------------------------------------------------------------------------------
2077 {
2078  if (mChanges)
2079  {
2080  const QString path = AbsoluteMPath(qApp->getFilePath(), doc->MPath());
2081  if(UpdateMeasurements(path, static_cast<int>(VContainer::size()), static_cast<int>(VContainer::height())))
2082  {
2083  if (not watcher->files().contains(path))
2084  {
2085  watcher->addPath(path);
2086  }
2087  const QString msg = tr("Measurements have been synced");
2088  qCDebug(vMainWindow, "%s", qUtf8Printable(msg));
2089  helpLabel->setText(msg);
2090  VWidgetPopup::PopupMessage(this, msg);
2092  mChanges = false;
2093  mChangesAsked = true;
2095  ui->syncMeasurements_Action->setEnabled(mChanges);
2096  }
2097  else
2098  {
2099  qCWarning(vMainWindow, "%s", qUtf8Printable(tr("Couldn't sync measurements.")));
2100  }
2101  }
2102 }
2103 
2104 //---------------------------------------------------------------------------------------------------------------------
2105 #if defined(Q_OS_MAC)
2106 void MainWindow::OpenAt(QAction *where)
2107 {
2108  const QString path = qApp->getFilePath().left(qApp->getFilePath().indexOf(where->text())) + where->text();
2109  if (path == qApp->getFilePath())
2110  {
2111  return;
2112  }
2113  QProcess process;
2114  process.start(QStringLiteral("/usr/bin/open"), QStringList() << path, QIODevice::ReadOnly);
2115  process.waitForFinished();
2116 }
2117 #endif //defined(Q_OS_MAC)
2118 
2119 //---------------------------------------------------------------------------------------------------------------------
2120 /**
2121  * @brief initStatusBar initialize horizontal bar for presenting status information
2122  */
2124 {
2125  if (!mouseCoordinates.isNull())
2126  {
2127  delete mouseCoordinates;
2128  }
2129  if (!infoToolButton.isNull())
2130  {
2131  delete infoToolButton;
2132  }
2133  if (!gradationHeights.isNull())
2134  {
2135  delete gradationHeights;
2136  }
2137  if (!gradationSizes.isNull())
2138  {
2139  delete gradationSizes;
2140  }
2141  if (!gradationHeightsLabel.isNull())
2142  {
2143  delete gradationHeightsLabel;
2144  }
2145  if (!gradationSizesLabel.isNull())
2146  {
2147  delete gradationSizesLabel;
2148  }
2149 
2150  if (qApp->patternType() == MeasurementsType::Multisize)
2151  {
2152  const QStringList listHeights = VMeasurement::ListHeights(doc->GetGradationHeights(), qApp->patternUnit());
2153  const QStringList listSizes = VMeasurement::ListSizes(doc->GetGradationSizes(), qApp->patternUnit());
2154 
2155  gradationHeightsLabel = new QLabel(tr("Height:"), this);
2157 
2158  // set default height
2159  SetDefaultHeight();
2160 
2161  connect(gradationHeights.data(), static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
2162  this, &MainWindow::ChangedHeight);
2163 
2164  gradationSizesLabel = new QLabel(tr("Size:"), this);
2166 
2167  // set default size
2168  SetDefaultSize();
2169 
2170  connect(gradationSizes.data(), static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
2171  this, &MainWindow::ChangedSize);
2172 
2173  }
2174 
2175  mouseCoordinates = new MouseCoordinates(qApp->patternUnit());
2176  ui->statusBar->addPermanentWidget((mouseCoordinates));
2177 
2178  infoToolButton = new QToolButton();
2179  infoToolButton->setDefaultAction(ui->documentInfo_Action);
2180  ui->statusBar->addPermanentWidget((infoToolButton));
2181 }
2182 
2183 //---------------------------------------------------------------------------------------------------------------------
2184 QComboBox *MainWindow::SetGradationList(QLabel *label, const QStringList &list)
2185 {
2186  QComboBox *comboBox = new QComboBox(this);
2187  comboBox->addItems(list);
2188  ui->statusBar->addPermanentWidget(label);
2189  ui->statusBar->addPermanentWidget(comboBox);
2190 
2191  return comboBox;
2192 }
2193 
2194 //---------------------------------------------------------------------------------------------------------------------
2196 {
2197  leftGoToStage = new QLabel(this);
2198  leftGoToStage->setPixmap(QPixmap("://icon/24x24/fast_forward_left_to_right_arrow.png"));
2199  ui->mode_ToolBar->insertWidget(ui->pieceMode_Action, leftGoToStage);
2200 
2201  rightGoToStage = new QLabel(this);
2202  rightGoToStage->setPixmap(QPixmap("://icon/24x24/left_to_right_arrow.png"));
2203  ui->mode_ToolBar->insertWidget(ui->layoutMode_Action, rightGoToStage);
2204 }
2205 
2206 //---------------------------------------------------------------------------------------------------------------------
2207 /**
2208  * @brief initPointNameToolBar enable Point Name toolbar.
2209  */
2211 {
2212  fontComboBox = new QFontComboBox ;
2213  fontComboBox->setCurrentFont(qApp->Seamly2DSettings()->getPointNameFont());
2214  ui->pointName_ToolBar->insertWidget(ui->showPointNames_Action,fontComboBox);
2215  fontComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
2216  fontComboBox->setEnabled(true);
2217 
2218  connect(fontComboBox, static_cast<void (QFontComboBox::*)(const QFont &)>(&QFontComboBox::currentFontChanged),
2219  this, [this](QFont font)
2220  {
2221  qApp->Seamly2DSettings()->setPointNameFont(font);
2222  upDateScenes();
2223  });
2224 
2225  fontSizeComboBox = new QComboBox ;
2226  ui->pointName_ToolBar->insertWidget(ui->showPointNames_Action,fontSizeComboBox);
2227  fontSizeComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
2228  fontSizeComboBox->addItem("6", QVariant(static_cast<int>(6)));
2229  fontSizeComboBox->addItem("7", QVariant(static_cast<int>(7)));
2230  fontSizeComboBox->addItem("8", QVariant(static_cast<int>(8)));
2231  fontSizeComboBox->addItem("9", QVariant(static_cast<int>(9)));
2232  fontSizeComboBox->addItem("10", QVariant(static_cast<int>(10)));
2233  fontSizeComboBox->addItem("11", QVariant(static_cast<int>(11)));
2234  fontSizeComboBox->addItem("12", QVariant(static_cast<int>(12)));
2235  fontSizeComboBox->addItem("13", QVariant(static_cast<int>(13)));
2236  fontSizeComboBox->addItem("14", QVariant(static_cast<int>(14)));
2237  fontSizeComboBox->addItem("15", QVariant(static_cast<int>(15)));
2238  fontSizeComboBox->addItem("16", QVariant(static_cast<int>(16)));
2239  fontSizeComboBox->addItem("18", QVariant(static_cast<int>(18)));
2240  fontSizeComboBox->addItem("20", QVariant(static_cast<int>(20)));
2241  fontSizeComboBox->addItem("22", QVariant(static_cast<int>(22)));
2242  fontSizeComboBox->addItem("24", QVariant(static_cast<int>(24)));
2243  fontSizeComboBox->addItem("26", QVariant(static_cast<int>(26)));
2244  fontSizeComboBox->addItem("28", QVariant(static_cast<int>(28)));
2245  fontSizeComboBox->addItem("32", QVariant(static_cast<int>(32)));
2246  fontSizeComboBox->addItem("36", QVariant(static_cast<int>(36)));
2247  fontSizeComboBox->addItem("40", QVariant(static_cast<int>(40)));
2248  fontSizeComboBox->addItem("44", QVariant(static_cast<int>(44)));
2249  fontSizeComboBox->addItem("48", QVariant(static_cast<int>(48)));
2250  fontSizeComboBox->addItem("54", QVariant(static_cast<int>(54)));
2251  fontSizeComboBox->addItem("60", QVariant(static_cast<int>(60)));
2252  fontSizeComboBox->addItem("66", QVariant(static_cast<int>(66)));
2253  fontSizeComboBox->addItem("72", QVariant(static_cast<int>(72)));
2254  fontSizeComboBox->addItem("80", QVariant(static_cast<int>(80)));
2255  fontSizeComboBox->addItem("96", QVariant(static_cast<int>(96)));
2256 
2257  int index = fontSizeComboBox->findData(qApp->Seamly2DSettings()->getPointNameSize());
2258  if (index < 0 || index > 28)
2259  {
2260  index = 18;
2261  }
2262  fontSizeComboBox->setCurrentIndex(index);
2263 
2264  connect(fontSizeComboBox, &QComboBox::currentTextChanged, this, [this](QString text)
2265  {
2266  qApp->Seamly2DSettings()->setPointNameSize(text.toInt());
2267  upDateScenes();
2268  });
2269  fontSizeComboBox->setEnabled(true);
2270 }
2271 
2272 //---------------------------------------------------------------------------------------------------------------------
2273 /**
2274  * @brief initDraftToolBar enable draw toolbar.
2275  */
2277 {
2278  draftBlockLabel = new QLabel(tr("Draft Block:"));
2279  ui->draft_ToolBar->addWidget(draftBlockLabel);
2280 
2281  // By using Qt UI Designer we can't add QComboBox to toolbar
2282  draftBlockComboBox = new QComboBox;
2283  ui->draft_ToolBar->addWidget(draftBlockComboBox);
2284  draftBlockComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
2285  draftBlockComboBox->setEnabled(false);
2286 
2287  connect(draftBlockComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
2288  this, [this](int index){changeDraftBlock(index);});
2289 
2290  connect(ui->renameDraft_Action, &QAction::triggered, this, [this]()
2291  {
2292  const QString activeDraftBlock = doc->getActiveDraftBlockName();
2293  const QString draftBlockName = createDraftBlockName(activeDraftBlock);
2294  if (draftBlockName.isEmpty())
2295  {
2296  return;
2297  }
2298  RenameDraftBlock *draftBlock = new RenameDraftBlock(doc, draftBlockName, draftBlockComboBox);
2299  qApp->getUndoStack()->push(draftBlock);
2300  });
2301 }
2302 
2303 //---------------------------------------------------------------------------------------------------------------------
2305 {
2306  /*First we will try use Standard Shortcuts from Qt, but because keypad "-" and "+" not the same keys like in main
2307  keypad, shortcut Ctrl+"-" or "+" from keypad will not working with standard shortcut (QKeySequence::ZoomIn or
2308  QKeySequence::ZoomOut). For example "+" is Qt::Key_Plus + Qt::KeypadModifier for keypad.
2309  Also for me don't work Qt:CTRL and work Qt::ControlModifier.*/
2310 
2311  QList<QKeySequence> zoomInShortcuts;
2312  zoomInShortcuts.append(QKeySequence(QKeySequence::ZoomIn));
2313  zoomInShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Plus + Qt::KeypadModifier));
2314  ui->zoomIn_Action->setShortcuts(zoomInShortcuts);
2315  connect(ui->zoomIn_Action, &QAction::triggered, ui->view, &VMainGraphicsView::zoomIn);
2316 
2317  QList<QKeySequence> zoomOutShortcuts;
2318  zoomOutShortcuts.append(QKeySequence(QKeySequence::ZoomOut));
2319  zoomOutShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Minus + Qt::KeypadModifier));
2320  ui->zoomOut_Action->setShortcuts(zoomOutShortcuts);
2321  connect(ui->zoomOut_Action, &QAction::triggered, ui->view, &VMainGraphicsView::zoomOut);
2322 
2323  QList<QKeySequence> zoom100PercentShortcuts;
2324  zoom100PercentShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_0));
2325  zoom100PercentShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_0 + Qt::KeypadModifier));
2326  ui->zoom100Percent_Action->setShortcuts(zoom100PercentShortcuts);
2327  connect(ui->zoom100Percent_Action, &QAction::triggered, ui->view, &VMainGraphicsView::zoom100Percent);
2328 
2329  QList<QKeySequence> zoomToFitShortcuts;
2330  zoomToFitShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Equal));
2331  ui->zoomToFit_Action->setShortcuts(zoomToFitShortcuts);
2332  connect(ui->zoomToFit_Action, &QAction::triggered, ui->view, &VMainGraphicsView::zoomToFit);
2333 
2334  QList<QKeySequence> zoomToSelectedShortcuts;
2335  zoomToSelectedShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Right));
2336  ui->zoomToSelected_Action->setShortcuts(zoomToSelectedShortcuts);
2337  connect(ui->zoomToSelected_Action, &QAction::triggered, this, &MainWindow::zoomToSelected);
2338 
2339  QList<QKeySequence> zoomToPreviousShortcuts;
2340  zoomToPreviousShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Left));
2341  ui->zoomToPrevious_Action->setShortcuts(zoomToPreviousShortcuts);
2342  connect(ui->zoomToPrevious_Action, &QAction::triggered, this, &MainWindow::zoomToPrevious);
2343 
2344  QList<QKeySequence> zoomToAreaShortcuts;
2345  zoomToAreaShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_A));
2346  ui->zoomToArea_Action->setShortcuts(zoomToAreaShortcuts);
2347  connect(ui->zoomToArea_Action, &QAction::toggled, this, &MainWindow::zoomToArea);
2348 
2350  connect(ui->zoomPan_Action, &QAction::toggled, this, &MainWindow::zoomPan);
2351 
2352  QList<QKeySequence> zoomToPointShortcuts;
2353  zoomToPointShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::AltModifier + Qt::Key_P));
2354  ui->zoomToPoint_Action->setShortcuts(zoomToPointShortcuts);
2355  connect(ui->zoomToPoint_Action, &QAction::triggered, this, &MainWindow::showZoomToPointDialog);
2356 
2357  m_zoomToPointComboBox = new QComboBox(ui->zoom_ToolBar);
2358  m_zoomToPointComboBox->setEnabled(false);
2359  m_zoomToPointComboBox->setToolTip(ui->zoomToPoint_Action->toolTip());
2360  ui->zoom_ToolBar->addWidget(m_zoomToPointComboBox);
2361  connect(m_zoomToPointComboBox, &QComboBox::currentTextChanged, this, &MainWindow::zoomToPoint);
2362 
2363  if (zoomScaleSpinBox != nullptr)
2364  {
2365  delete zoomScaleSpinBox;
2366  }
2367  zoomScaleSpinBox = new QDoubleSpinBox();
2368  zoomScaleSpinBox->setDecimals(1);
2369  zoomScaleSpinBox->setAlignment(Qt::AlignRight);
2370  zoomScaleSpinBox->setSingleStep(0.1);
2371  zoomScaleSpinBox->setMinimum(qFloor(VMainGraphicsView::MinScale()*1000)/10.0);
2372  zoomScaleSpinBox->setMaximum(qFloor(VMainGraphicsView::MaxScale()*1000)/10.0);
2373  zoomScaleSpinBox->setSuffix("%");
2374  zoomScaleSpinBox->setMaximumWidth(80);
2375  zoomScaleSpinBox->setKeyboardTracking(false);
2376  ui->zoom_ToolBar->insertWidget(ui->zoomIn_Action,zoomScaleSpinBox);
2377 
2378  zoomScaleChanged(ui->view->transform().m11());
2379  connect(zoomScaleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
2380  this,[this](double d){ui->view->zoomByScale(d/100.0);});
2381 
2382 }
2383 
2385 {
2387  connect(ui->tools_ToolBox_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2388  {
2389  ui->tools_ToolBox_ToolBar->setVisible(visible);
2390  qApp->Settings()->setShowToolsToolBar(visible);
2391  });
2392  connect(ui->points_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2393  {
2394  ui->points_ToolBar->setVisible(visible);
2395  qApp->Settings()->setShowPointToolBar(visible);
2396  });
2397  connect(ui->lines_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2398  {
2399  ui->lines_ToolBar->setVisible(visible);
2400  qApp->Settings()->setShowLineToolBar(visible);
2401  });
2402  connect(ui->curves_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2403  {
2404  ui->curves_ToolBar->setVisible(visible);
2405  qApp->Settings()->setShowCurveToolBar(visible);
2406  });
2407  connect(ui->arcs_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2408  {
2409  ui->arcs_ToolBar->setVisible(visible);
2410  qApp->Settings()->setShowArcToolBar(visible);
2411  });
2412  connect(ui->operations_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2413  {
2414  ui->operations_ToolBar->setVisible(visible);
2415  qApp->Settings()->setShowOpsToolBar(visible);
2416  });
2417  connect(ui->pieces_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2418  {
2419  ui->pieces_ToolBar->setVisible(visible);
2420  qApp->Settings()->setShowPieceToolBar(visible);
2421  });
2422  connect(ui->details_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2423  {
2424  ui->details_ToolBar->setVisible(visible);
2425  qApp->Settings()->setShowDetailsToolBar(visible);
2426  });
2427  connect(ui->layout_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
2428  {
2429  ui->layout_ToolBar->setVisible(visible);
2430  qApp->Settings()->setShowLayoutToolBar(visible);
2431  });
2432 }
2433 
2434 //---------------------------------------------------------------------------------------------------------------------
2435 /**
2436  * @brief initPenToolBar enable default color, line wight & type toolbar.
2437  */
2439 {
2440  if (m_penToolBar != nullptr)
2441  {
2442  delete m_penToolBar;
2443  }
2444  m_penToolBar = new PenToolBar("Toolbar Pen", this);
2445  m_penToolBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
2446  m_penToolBar->setObjectName("penToolBar");
2447  this->addToolBar(Qt::TopToolBarArea, m_penToolBar);
2448 
2450 }
2451 
2452 /**
2453  * Called when something changed in the pen tool bar
2454  * (e.g. color, weight, or type).
2455  */
2457 {
2458  doc->setDefaultPen(pen);
2459 }
2460 
2462 {
2463  setToolBarVisibility(ui->tools_ToolBox_ToolBar, qApp->Settings()->getShowToolsToolBar());
2464  setToolBarVisibility(ui->points_ToolBar, qApp->Settings()->getShowPointToolBar());
2465  setToolBarVisibility(ui->lines_ToolBar, qApp->Settings()->getShowLineToolBar());
2466  setToolBarVisibility(ui->curves_ToolBar, qApp->Settings()->getShowCurveToolBar());
2467  setToolBarVisibility(ui->arcs_ToolBar, qApp->Settings()->getShowArcToolBar());
2468  setToolBarVisibility(ui->operations_ToolBar, qApp->Settings()->getShowOpsToolBar());
2469  setToolBarVisibility(ui->pieces_ToolBar, qApp->Settings()->getShowPieceToolBar());
2470  setToolBarVisibility(ui->details_ToolBar, qApp->Settings()->getShowDetailsToolBar());
2471  setToolBarVisibility(ui->layout_ToolBar, qApp->Settings()->getShowLayoutToolBar());
2472 }
2473 
2474 void MainWindow::setToolBarVisibility(QToolBar *toolbar, bool visible)
2475 {
2476  toolbar->blockSignals(true);
2477  toolbar->setVisible(visible);
2478  toolbar->blockSignals(false);
2479 }
2480 
2482 {
2483  zoomScaleSpinBox->blockSignals(true);
2484  zoomScaleSpinBox->setValue(qFloor(scale*1000)/10.0);
2485  zoomScaleSpinBox->blockSignals(false);
2486  qCDebug(vMainWindow, "Value %f\n", (qreal(qFloor(scale*1000)/10.0)));
2487 }
2488 
2489 //---------------------------------------------------------------------------------------------------------------------
2491 {
2492  if (qApp->getCurrentScene() == draftScene)
2493  {
2494  ui->view->zoomToRect(doc->ActiveDrawBoundingRect());
2495  }
2496  else if (qApp->getCurrentScene() == pieceScene)
2497  {
2498  QGraphicsItem *item = qApp->getCurrentScene()->focusItem();
2499  {
2500  if ((item != nullptr) && (item->type() == QGraphicsItem::UserType + static_cast<int>(Tool::Piece)))
2501  {
2502  QRectF rect;
2503  rect = item->boundingRect();
2504  rect.translate(item->scenePos());
2505  ui->view->zoomToRect(rect);
2506  }
2507  }
2508  }
2509 }
2510 
2512 {
2513  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
2514  SCASSERT(scene != nullptr)
2515 
2516  /*Set transform for current scene*/
2517  scene->swapTransforms();
2518  ui->view->setTransform(scene->transform());
2519  zoomScaleChanged(ui->view->transform().m11());
2520 }
2521 
2522 //---------------------------------------------------------------------------------------------------------------------
2523 void MainWindow::zoomToArea(bool checked)
2524 {
2525  ui->view->zoomToAreaEnabled(checked);
2526 
2527  if (ui->zoomToArea_Action->isChecked())
2528  {
2529  ui->zoomPan_Action->setChecked(false);
2530  }
2531 }
2532 
2533 //---------------------------------------------------------------------------------------------------------------------
2534 void MainWindow::zoomPan(bool checked)
2535 {
2536  ui->view->zoomPanEnabled(checked);
2537  if (checked)
2538  {
2539  ui->zoomToArea_Action->setChecked(false);
2540  }
2541 }
2542 
2543 //---------------------------------------------------------------------------------------------------------------------
2544 /**
2545  * @brief zoomToPoint show dialog for choosing a point and update the graphics view to focus on it.
2546  */
2548 {
2549  QStringList pointNames = draftPointNamesList();
2550 
2551  bool ok;
2552  QString pointName = QInputDialog::getItem(this, tr("Zoom to Point"), tr("Point:"), pointNames, 0, true, &ok,
2553  Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
2554  if (!ok || pointName.isEmpty()) return;
2555 
2556  zoomToPoint(pointName);
2557 }
2558 
2559 //---------------------------------------------------------------------------------------------------------------------
2560 /**
2561  * @brief zoomToPoint show dialog for choosing a point and update the graphics view to focus on it.
2562  * @param pointName name of to zoom into.
2563  */
2564 void MainWindow::zoomToPoint(const QString &pointName)
2565 {
2567  QHash<quint32, QSharedPointer<VGObject> >::const_iterator i;
2568 
2569  for (i = objects->constBegin(); i != objects->constEnd(); ++i)
2570  {
2571  QSharedPointer<VGObject> object = i.value();
2572  const quint32 objectId = object->getIdObject();
2573  const QString objectName = object->name();
2574 
2575  if (objectName == pointName)
2576  {
2577  VPointF *point = (VPointF*)object.data();
2578  ui->view->zoom100Percent();
2579  ui->view->centerOn(point->toQPointF());
2580 
2581  // show point name if it's hidden
2582  // TODO: Need to make this work with operation's and dart tools
2583  quint32 toolId = point->getIdTool();
2584  const quint32 objId = point->getIdObject();
2585  if (objId != NULL_ID)
2586  {
2587  toolId = objId;
2588  }
2589  if (VAbstractTool *tool = qobject_cast<VAbstractTool *>(VAbstractPattern::getTool(toolId)))
2590  {
2591  tool->setPointNameVisiblity(toolId, true);
2592  }
2593 
2594  // show any hiden groups containing object
2595  QMap<quint32,QString> groups = doc->getGroupsContainingItem(toolId, objectId, true);
2596  groupsWidget->showGroups(groups);
2597 
2598  // Reset combobox so same point can be selected again
2599  m_zoomToPointComboBox->blockSignals(true);
2600  m_zoomToPointComboBox->setCurrentIndex(-1);
2601  m_zoomToPointComboBox->blockSignals(false);
2602 
2603  return;
2604  }
2605  }
2606 }
2607 
2608 //---------------------------------------------------------------------------------------------------------------------
2610 {
2611  connect(ui->arrowPointer_ToolButton, &QToolButton::clicked, this, &MainWindow::handleArrowTool);
2612 
2613  // This check helps to find missed tools
2614  Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 53, "Check if all tools were connected.");
2615 
2616  connect(ui->pointAtDistanceAngle_ToolButton, &QToolButton::clicked,
2618  connect(ui->line_ToolButton, &QToolButton::clicked, this, &MainWindow::handleLineTool);
2619  connect(ui->alongLine_ToolButton, &QToolButton::clicked, this, &MainWindow::handleAlongLineTool);
2620  connect(ui->shoulderPoint_ToolButton, &QToolButton::clicked, this, &MainWindow::handleShoulderPointTool);
2621  connect(ui->normal_ToolButton, &QToolButton::clicked, this, &MainWindow::handleNormalTool);
2622  connect(ui->bisector_ToolButton, &QToolButton::clicked, this, &MainWindow::handleBisectorTool);
2623  connect(ui->lineIntersect_ToolButton, &QToolButton::clicked, this, &MainWindow::handleLineIntersectTool);
2624  connect(ui->curve_ToolButton, &QToolButton::clicked, this, &MainWindow::handleCurveTool);
2625  connect(ui->curveWithCPs_ToolButton, &QToolButton::clicked, this, &MainWindow::handleCurveWithControlPointsTool);
2626  connect(ui->arc_ToolButton, &QToolButton::clicked, this, &MainWindow::handleArcTool);
2627  connect(ui->spline_ToolButton, &QToolButton::clicked, this, &MainWindow::handleSplineTool);
2628  connect(ui->splineWithCPs_ToolButton, &QToolButton::clicked, this, &MainWindow::handleSplineWithControlPointsTool);
2629  connect(ui->pointOfContact_ToolButton, &QToolButton::clicked, this, &MainWindow::handlePointOfContactTool);
2630  connect(ui->addPatternPiece_ToolButton,&QToolButton::clicked, this, &MainWindow::handlePatternPieceTool);
2631  connect(ui->internalPath_ToolButton, &QToolButton::clicked, this, &MainWindow::handleInternalPathTool);
2632  connect(ui->height_ToolButton, &QToolButton::clicked, this, &MainWindow::handleHeightTool);
2633  connect(ui->triangle_ToolButton, &QToolButton::clicked, this, &MainWindow::handleTriangleTool);
2634  connect(ui->pointIntersectXY_ToolButton, &QToolButton::clicked, this, &MainWindow::handlePointIntersectXYTool);
2635  connect(ui->pointAlongCurve_ToolButton, &QToolButton::clicked, this, &MainWindow::handlePointAlongCurveTool);
2636  connect(ui->pointAlongSpline_ToolButton, &QToolButton::clicked, this, &MainWindow::handlePointAlongSplineTool);
2637  connect(ui->unitePieces_ToolButton, &QToolButton::clicked, this, &MainWindow::handleUnionTool);
2638  connect(ui->pointAlongArc_ToolButton, &QToolButton::clicked, this, &MainWindow::handlePointAlongArcTool);
2639  connect(ui->lineIntersectAxis_ToolButton, &QToolButton::clicked, this, &MainWindow::handleLineIntersectAxisTool);
2640  connect(ui->curveIntersectAxis_ToolButton, &QToolButton::clicked, this, &MainWindow::handleCurveIntersectAxisTool);
2641  connect(ui->arcIntersectAxis_ToolButton, &QToolButton::clicked, this, &MainWindow::handleArcIntersectAxisTool);
2642  connect(ui->layoutSettings_ToolButton, &QToolButton::clicked, this, &MainWindow::handleNewLayout);
2643  connect(ui->pointOfIntersectionArcs_ToolButton, &QToolButton::clicked,
2645  connect(ui->pointOfIntersectionCircles_ToolButton, &QToolButton::clicked,
2647  connect(ui->pointOfIntersectionCurves_ToolButton, &QToolButton::clicked,
2649  connect(ui->pointFromCircleAndTangent_ToolButton, &QToolButton::clicked,
2651  connect(ui->pointFromArcAndTangent_ToolButton, &QToolButton::clicked,
2653  connect(ui->arcWithLength_ToolButton, &QToolButton::clicked, this, &MainWindow::handleArcWithLengthTool);
2654  connect(ui->trueDarts_ToolButton, &QToolButton::clicked, this, &MainWindow::handleTrueDartTool);
2655  connect(ui->exportDraftBlocks_ToolButton, &QToolButton::clicked, this, &MainWindow::exportDraftBlocksAs);
2656  connect(ui->group_ToolButton, &QToolButton::clicked, this, &MainWindow::handleGroupTool);
2657  connect(ui->rotation_ToolButton, &QToolButton::clicked, this, &MainWindow::handleRotationTool);
2658  connect(ui->mirrorByLine_ToolButton, &QToolButton::clicked, this, &MainWindow::handleMirrorByLineTool);
2659  connect(ui->mirrorByAxis_ToolButton, &QToolButton::clicked, this, &MainWindow::handleMirrorByAxisTool);
2660  connect(ui->move_ToolButton, &QToolButton::clicked, this, &MainWindow::handleMoveTool);
2661  connect(ui->midpoint_ToolButton, &QToolButton::clicked, this, &MainWindow::handleMidpointTool);
2662  connect(ui->exportLayout_ToolButton, &QToolButton::clicked, this, &MainWindow::exportLayoutAs);
2663  connect(ui->exportPiecesAs_ToolButton, &QToolButton::clicked, this, &MainWindow::exportPiecesAs);
2664  connect(ui->ellipticalArc_ToolButton, &QToolButton::clicked, this, &MainWindow::handleEllipticalArcTool);
2665  connect(ui->anchorPoint_ToolButton, &QToolButton::clicked, this, &MainWindow::handleAnchorPointTool);
2666  connect(ui->insertNodes_ToolButton, &QToolButton::clicked, this, &MainWindow::handleInsertNodesTool);
2667 }
2668 
2670 {
2671  qCDebug(vMainWindow, "Points Menu selected. \n");
2672 
2673  QMenu menu;
2674 
2675  QAction *action_PointAtDA = menu.addAction(QIcon(":/toolicon/32x32/segment.png"), tr("Length and Angle") + "\tL, A");
2676  QAction *action_PointAlongLine = menu.addAction(QIcon(":/toolicon/32x32/along_line.png"), tr("On Line") + "\tO, L");
2677  QAction *action_Midpoint = menu.addAction(QIcon(":/toolicon/32x32/midpoint.png"), tr("Midpoint") + "\tShift+O, Shift+L");
2678  QAction *action_AlongPerpendicular = menu.addAction(QIcon(":/toolicon/32x32/normal.png"), tr("On Perpendicular") + "\tO, P");
2679  QAction *action_Bisector = menu.addAction(QIcon(":/toolicon/32x32/bisector.png"), tr("On Bisector") + "\tO, B");
2680  QAction *action_Shoulder = menu.addAction(QIcon(":/toolicon/32x32/shoulder.png"), tr("Length to Line") + "\tP, S");
2681  QAction *action_PointOfContact = menu.addAction(QIcon(":/toolicon/32x32/point_of_contact.png"), tr("Intersect Arc and Line") + "\tA, L");
2682  QAction *action_Triangle = menu.addAction(QIcon(":/toolicon/32x32/triangle.png"), tr("Intersect Axis and Triangle") + "\tX, T");
2683  QAction *action_PointIntersectXY = menu.addAction(QIcon(":/toolicon/32x32/point_intersectxy_icon.png"), tr("Intersect XY") + "\tX, Y");
2684  QAction *action_PerpendicularPoint = menu.addAction(QIcon(":/toolicon/32x32/height.png"), tr("Intersect Line and Perpendicular") + "\tL, P");
2685  QAction *action_PointIntersectAxis = menu.addAction(QIcon(":/toolicon/32x32/line_intersect_axis.png"), tr("Intersect Line and Axis") + "\tL, X");
2686 
2687  QAction *selectedAction = menu.exec(QCursor::pos());
2688 
2689  if(selectedAction == nullptr)
2690  {
2691  return;
2692  }
2693  else if (selectedAction == action_Midpoint)
2694  {
2695  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2696  ui->midpoint_ToolButton->setChecked(true);
2697  handleMidpointTool(true);
2698  }
2699  else if (selectedAction == action_PointAtDA)
2700  {
2701  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2702  ui->pointAtDistanceAngle_ToolButton->setChecked(true);
2704  }
2705  else if (selectedAction == action_PointAlongLine)
2706  {
2707  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2708  ui->alongLine_ToolButton->setChecked(true);
2709  handleAlongLineTool(true);
2710  }
2711  else if (selectedAction == action_AlongPerpendicular)
2712  {
2713  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2714  ui->normal_ToolButton->setChecked(true);
2715  handleNormalTool(true);
2716  }
2717  else if (selectedAction == action_Bisector)
2718  {
2719  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2720  ui->bisector_ToolButton->setChecked(true);
2721  handleBisectorTool(true);
2722  }
2723  else if (selectedAction == action_Shoulder)
2724  {
2725  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2726  ui->shoulderPoint_ToolButton->setChecked(true);
2728  }
2729  else if (selectedAction == action_PointOfContact)
2730  {
2731  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2732  ui->pointOfContact_ToolButton->setChecked(true);
2734  }
2735  else if (selectedAction == action_Triangle)
2736  {
2737  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2738  ui->triangle_ToolButton->setChecked(true);
2739  handleTriangleTool(true);
2740  }
2741  else if (selectedAction == action_PointIntersectXY)
2742  {
2743  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2744  ui->pointIntersectXY_ToolButton->setChecked(true);
2746  }
2747  else if (selectedAction == action_PerpendicularPoint)
2748  {
2749  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2750  ui->height_ToolButton->setChecked(true);
2751  handleHeightTool(true);
2752  }
2753  else if (selectedAction == action_PointIntersectAxis)
2754  {
2755  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
2756  ui->lineIntersectAxis_ToolButton->setChecked(true);
2758  }
2759 }
2760 
2762 {
2763  qCDebug(vMainWindow, "Lines Menu selected. \n");
2764  QMenu menu;
2765 
2766  QAction *action_Line = menu.addAction(QIcon(":/toolicon/32x32/line.png"), tr("Line") + "\tAlt+L");
2767  QAction *action_LineIntersect = menu.addAction(QIcon(":/toolicon/32x32/intersect.png"), tr("Intersect Lines") + "\tI, L");
2768 
2769  QAction *selectedAction = menu.exec(QCursor::pos());
2770 
2771  if(selectedAction == nullptr)
2772  {
2773  return;
2774  }
2775  else if (selectedAction == action_Line)
2776  {
2777  ui->draft_ToolBox->setCurrentWidget(ui->lines_Page);
2778  ui->line_ToolButton->setChecked(true);
2779  handleLineTool(true);
2780  }
2781  else if (selectedAction == action_LineIntersect)
2782  {
2783  ui->draft_ToolBox->setCurrentWidget(ui->lines_Page);
2784  ui->lineIntersect_ToolButton->setChecked(true);
2786  }
2787 }
2788 
2790 {
2791  qCDebug(vMainWindow, "Arcs Menu selected. \n");
2792  QMenu menu;
2793 
2794  QAction *action_Arc = menu.addAction(QIcon(":/toolicon/32x32/arc.png"), tr("Radius and Angles") + "\tAlt+A");
2795  QAction *action_PointAlongArc = menu.addAction(QIcon(":/toolicon/32x32/arc_cut.png"), tr("Point on Arc") + "\tO, A");
2796  QAction *action_ArcIntersectAxis = menu.addAction(QIcon(":/toolicon/32x32/arc_intersect_axis.png"), tr("Intersect Arc and Axis") + "\tA, X");
2797  QAction *action_ArcIntersectArc = menu.addAction(QIcon(":/toolicon/32x32/point_of_intersection_arcs.png"), tr("Intersect Arcs") + "\tI, A");
2798  QAction *action_CircleIntersect = menu.addAction(QIcon(":/toolicon/32x32/point_of_intersection_circles.png"), tr("Intersect Circles") + "\tShift+I, Shift+C");
2799  QAction *action_CircleTangent = menu.addAction(QIcon(":/toolicon/32x32/point_from_circle_and_tangent.png"), tr("Intersect Circle and Tangent") + "\tC, T");
2800  QAction *action_ArcTangent = menu.addAction(QIcon(":/toolicon/32x32/point_from_arc_and_tangent.png"), tr("Intersect Arc and Tangent") + "\tA, T");
2801  QAction *action_ArcWithLength = menu.addAction(QIcon(":/toolicon/32x32/arc_with_length.png"), tr("Radius and Length") + "\tAlt+Shift+A");
2802  QAction *action_EllipticalArc = menu.addAction(QIcon(":/toolicon/32x32/el_arc.png"), tr("Elliptical") + "\tAlt+E");
2803 
2804  QAction *selectedAction = menu.exec(QCursor::pos());
2805 
2806  if(selectedAction == nullptr)
2807  {
2808  return;
2809  }
2810  else if (selectedAction == action_Arc)
2811  {
2812  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2813  ui->arc_ToolButton->setChecked(true);
2814  handleArcTool(true);
2815  }
2816  else if (selectedAction == action_PointAlongArc)
2817  {
2818  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2819  ui->pointAlongArc_ToolButton->setChecked(true);
2821  }
2822  else if (selectedAction == action_ArcIntersectAxis)
2823  {
2824  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2825  ui->arcIntersectAxis_ToolButton->setChecked(true);
2827  }
2828  else if (selectedAction == action_ArcIntersectArc)
2829  {
2830  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2831  ui->pointOfIntersectionArcs_ToolButton->setChecked(true);
2833  }
2834  else if (selectedAction == action_CircleIntersect)
2835  {
2836  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2837  ui->pointOfIntersectionCircles_ToolButton->setChecked(true);
2839  }
2840  else if (selectedAction == action_CircleTangent)
2841  {
2842  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2843  ui->pointFromCircleAndTangent_ToolButton->setChecked(true);
2845  }
2846  else if (selectedAction == action_ArcTangent)
2847  {
2848  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2849  ui->pointFromArcAndTangent_ToolButton->setChecked(true);
2851  }
2852  else if (selectedAction == action_ArcWithLength)
2853  {
2854  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2855  ui->arcWithLength_ToolButton->setChecked(true);
2857  }
2858  else if (selectedAction == action_EllipticalArc)
2859  {
2860  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
2861  ui->ellipticalArc_ToolButton->setChecked(true);
2863  }
2864 }
2865 
2867 {
2868  qCDebug(vMainWindow, "Curves Menu selected. \n");
2869  QMenu menu;
2870 
2871  QAction *action_Curve = menu.addAction(QIcon(":/toolicon/32x32/spline.png"), tr("Curve - Interactive") + "\tAlt+C");
2872  QAction *action_Spline = menu.addAction(QIcon(":/toolicon/32x32/splinePath.png"), tr("Spline - Interactive") + "\tAlt+S");
2873  QAction *action_CurveWithCPs = menu.addAction(QIcon(":/toolicon/32x32/cubic_bezier.png"), tr("Curve - Fixed") + "\tAlt+Shift+C");
2874  QAction *action_SplineWithCPs = menu.addAction(QIcon(":/toolicon/32x32/cubic_bezier_path.png"), tr("Spline - Fixed") + "\tAlt+Shift+S");
2875  QAction *action_PointAlongCurve = menu.addAction(QIcon(":/toolicon/32x32/spline_cut_point.png"), tr("Point on Curve") + "\tO, C");
2876  QAction *action_PointAlongSpline = menu.addAction(QIcon(":/toolicon/32x32/splinePath_cut_point.png"), tr("Point on Spline") + "\tO, S");
2877  QAction *action_CurveIntersectCurve = menu.addAction(QIcon(":/toolicon/32x32/intersection_curves.png"), tr("Intersect Curves") + "\tI, C");
2878  QAction *action_CurveIntersectAxis = menu.addAction(QIcon(":/toolicon/32x32/curve_intersect_axis.png"), tr("Intersect Curve & Axis") + "\tC, X");
2879 
2880  QAction *selectedAction = menu.exec(QCursor::pos());
2881 
2882  if(selectedAction == nullptr)
2883  {
2884  return;
2885  }
2886  else if (selectedAction == action_Curve)
2887  {
2888  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
2889  ui->curve_ToolButton->setChecked(true);
2890  handleCurveTool(true);
2891  }
2892  else if (selectedAction == action_Spline)
2893  {
2894  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
2895  ui->spline_ToolButton->setChecked(true);
2896  handleSplineTool(true);
2897  }
2898  else if (selectedAction == action_PointAlongCurve)
2899  {
2900  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
2901  ui->pointAlongCurve_ToolButton->setChecked(true);
2903  }
2904  else if (selectedAction == action_PointAlongSpline)
2905  {
2906  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
2907  ui->pointAlongSpline_ToolButton->setChecked(true);
2909  }
2910  else if (selectedAction == action_CurveWithCPs)
2911  {
2912  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
2913  ui->curveWithCPs_ToolButton->setChecked(true);
2915  }
2916  else if (selectedAction == action_SplineWithCPs)
2917  {
2918  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
2919  ui->splineWithCPs_ToolButton->setChecked(true);
2921  }
2922  else if (selectedAction == action_CurveIntersectCurve)
2923  {
2924  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
2925  ui->pointOfIntersectionCurves_ToolButton->setChecked(true);
2927  }
2928  else if (selectedAction == action_CurveIntersectAxis)
2929  {
2930  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
2931  ui->curveIntersectAxis_ToolButton->setChecked(true);
2933  }
2934 }
2935 
2937 {
2938  qCDebug(vMainWindow, "Circles Menu selected. \n");
2939 
2940 }
2941 
2943 {
2944  qCDebug(vMainWindow, "Operations Menu selected. \n");
2945  QMenu menu;
2946 
2947  QAction *action_Group = menu.addAction(QIcon(":/toolicon/32x32/group.png"), tr("Add Objects to Group") + "\tG");
2948  QAction *action_Rotate = menu.addAction(QIcon(":/toolicon/32x32/rotation.png"), tr("Rotate") + "\tR");
2949  QAction *action_MirrorByLine = menu.addAction(QIcon(":/toolicon/32x32/mirror_by_line.png"), tr("Mirror by Line") + "\tM, L");
2950  QAction *action_MirrorByAxis = menu.addAction(QIcon(":/toolicon/32x32/mirror_by_axis.png"), tr("Mirror by Axis") + "\tM, A");
2951  QAction *action_Move = menu.addAction(QIcon(":/toolicon/32x32/move.png"), tr("Move") + "\tAlt+M");
2952  QAction *action_TrueDarts = menu.addAction(QIcon(":/toolicon/32x32/true_darts.png"), tr("True Darts") + "\tT, D");
2953  QAction *action_ExportDraftBlocks = menu.addAction(QIcon(":/toolicon/32x32/export.png"), tr("Export Draft Blocks") + "\tE, D");
2954 
2955  QAction *selectedAction = menu.exec(QCursor::pos());
2956 
2957  if(selectedAction == nullptr)
2958  {
2959  return;
2960  }
2961  else if (selectedAction == action_Group)
2962  {
2963  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
2964  ui->group_ToolButton->setChecked(true);
2965  handleGroupTool(true);
2966  }
2967  else if (selectedAction == action_Rotate)
2968  {
2969  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
2970  ui->rotation_ToolButton->setChecked(true);
2971  handleRotationTool(true);
2972  }
2973  else if (selectedAction == action_MirrorByLine)
2974  {
2975  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
2976  ui->mirrorByLine_ToolButton->setChecked(true);
2977  handleMirrorByLineTool(true);
2978  }
2979  else if (selectedAction == action_MirrorByAxis)
2980  {
2981  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
2982  ui->mirrorByAxis_ToolButton->setChecked(true);
2983  handleMirrorByAxisTool(true);
2984  }
2985  else if (selectedAction == action_Move)
2986  {
2987  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
2988  ui->move_ToolButton->setChecked(true);
2989  handleMoveTool(true);
2990  }
2991  else if (selectedAction == action_TrueDarts)
2992  {
2993  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
2994  ui->trueDarts_ToolButton->setChecked(true);
2995  handleTrueDartTool(true);
2996  }
2997  else if (selectedAction == action_ExportDraftBlocks)
2998  {
2999  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
3001  }
3002 }
3003 
3005 {
3006  QMenu menu;
3007 
3008  QAction *action_Piece = menu.addAction(QIcon(":/toolicon/32x32/new_detail.png"), tr("New Pattern Piece") + "\tN, P");
3009  QAction *action_AnchorPoint = menu.addAction(QIcon(":/toolicon/32x32/anchor_point.png"), tr("Add AnchorPoint") + "\tA, P");
3010  QAction *action_InternalPath = menu.addAction(QIcon(":/toolicon/32x32/path.png"), tr("Create Internal Path") + "\tI, N");
3011  QAction *action_InsertNodes = menu.addAction(QIcon(":/toolicon/32x32/insert_nodes_icon.png"), tr("Insert Nodes in Path") + "\tI, P");
3012 
3013  action_AnchorPoint->setEnabled(pattern->DataPieces()->size() > 0);
3014  action_InternalPath->setEnabled(pattern->DataPieces()->size() > 0);
3015  action_InsertNodes->setEnabled(pattern->DataPieces()->size() > 0);
3016 
3017  QAction *selectedAction = menu.exec(QCursor::pos());
3018 
3019  if(selectedAction == nullptr)
3020  {
3021  return;
3022  }
3023  else if (selectedAction == action_Piece)
3024  {
3025  ui->draft_ToolBox->setCurrentWidget(ui->piece_Page);
3026  ui->addPatternPiece_ToolButton->setChecked(true);
3027  handlePatternPieceTool(true);
3028  }
3029  else if (selectedAction == action_AnchorPoint)
3030  {
3031  ui->draft_ToolBox->setCurrentWidget(ui->piece_Page);
3032  ui->anchorPoint_ToolButton->setChecked(true);
3033  handleAnchorPointTool(true);
3034  }
3035  else if (selectedAction == action_InternalPath)
3036  {
3037  ui->draft_ToolBox->setCurrentWidget(ui->piece_Page);
3038  ui->internalPath_ToolButton->setChecked(true);
3039  handleInternalPathTool(true);
3040  }
3041  else if (selectedAction == action_InsertNodes)
3042  {
3043  ui->draft_ToolBox->setCurrentWidget(ui->piece_Page);
3044  ui->insertNodes_ToolButton->setChecked(true);
3045  handleInsertNodesTool(true);
3046  }
3047 }
3048 
3050 {
3051  qCDebug(vMainWindow, "PatternPieces Menu selected. \n");
3052  QMenu menu;
3053 
3054  QAction *action_Union = menu.addAction(QIcon(":/toolicon/32x32/union.png"), tr("Union Tool") + "\tU");
3055  QAction *action_ExportPieces = menu.addAction(QIcon(":/toolicon/32x32/export.png"), tr("Export Pattern Pieces") + "\tE, P");
3056  QAction *selectedAction = menu.exec(QCursor::pos());
3057 
3058  if(selectedAction == nullptr)
3059  {
3060  return;
3061  }
3062  else if (selectedAction == action_Union)
3063  {
3064  ui->piece_ToolBox->setCurrentWidget(ui->details_Page);
3065  ui->unitePieces_ToolButton->setChecked(true);
3066  handleUnionTool(true);
3067  }
3068  else if (selectedAction == action_ExportPieces)
3069  {
3070  ui->piece_ToolBox->setCurrentWidget(ui->details_Page);
3071  exportPiecesAs();
3072  }
3073 }
3074 
3076 {
3077  qCDebug(vMainWindow, "Layout Menu selected. \n");
3078 
3079 
3080  QMenu menu;
3081 
3082  QAction *action_NewLayout = menu.addAction(QIcon(":/toolicon/32x32/layout_settings.png"), tr("New Print Layout") + "\tN, L");
3083  QAction *action_ExportLayout = menu.addAction(QIcon(":/toolicon/32x32/export.png"), tr("Export Layout") + "\tE, L");
3084 
3085  QAction *selectedAction = menu.exec(QCursor::pos());
3086 
3087  if(selectedAction == nullptr)
3088  {
3089  return;
3090  }
3091  else if (selectedAction == action_NewLayout)
3092  {
3093  ui->layout_ToolBox->setCurrentWidget(ui->layout_Page);
3094  ui->layoutSettings_ToolButton->setChecked(true);
3095  handleNewLayout(true);
3096  }
3097  else if (selectedAction == action_ExportLayout)
3098  {
3099  ui->layout_ToolBox->setCurrentWidget(ui->layout_Page);
3100  exportLayoutAs();
3101  }
3102 }
3103 
3104 //---------------------------------------------------------------------------------------------------------------------
3105 /**
3106  * @brief mouseMove save mouse position and show user.
3107  * @param scenePos position mouse.
3108  */
3109 void MainWindow::MouseMove(const QPointF &scenePos)
3110 {
3111  if (mouseCoordinates)
3112  {
3113  mouseCoordinates->updateCoordinates(scenePos);
3114  }
3115 }
3116 
3117 //---------------------------------------------------------------------------------------------------------------------
3118 QT_WARNING_PUSH
3119 QT_WARNING_DISABLE_GCC("-Wswitch-default")
3120 /**
3121  * @brief CancelTool cancel tool.
3122  */
3123 void MainWindow::CancelTool()
3124 {
3125  // This check helps to find missed tools in the switch
3126  Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 53, "Not all tools were handled.");
3127 
3128  qCDebug(vMainWindow, "Canceling tool.");
3129  dialogTool.clear();
3130  qCDebug(vMainWindow, "Dialog closed.");
3131 
3132  currentScene->setFocus(Qt::OtherFocusReason);
3133  currentScene->clearSelection();
3134  ui->view->itemClicked(nullptr); // Hide visualization to avoid a crash
3135 
3136  ui->zoomPan_Action->setChecked(false); //Disable Pan Zoom
3137  ui->view->zoomPanEnabled(false);
3138 
3139  ui->zoomToArea_Action->setChecked(false); //Disable Zoom to Area
3140  ui->view->zoomToAreaEnabled(false);
3141 
3142  switch ( currentTool )
3143  {
3144  case Tool::Arrow:
3145  ui->arrowPointer_ToolButton->setChecked(false);
3146  ui->arrow_Action->setChecked(false);
3147  helpLabel->setText("");
3148 
3149  // Crash: using CRTL+Z while using line tool.
3150  undoAction->setEnabled(false);
3151  redoAction->setEnabled(false);
3153  return;
3154  case Tool::BasePoint:
3155  case Tool::SinglePoint:
3156  case Tool::DoublePoint:
3157  case Tool::LinePoint:
3158  case Tool::AbstractSpline:
3159  case Tool::Cut:
3161  case Tool::NodePoint:
3162  case Tool::NodeArc:
3163  case Tool::NodeElArc:
3164  case Tool::NodeSpline:
3165  case Tool::NodeSplinePath:
3166  Q_UNREACHABLE(); //-V501
3167  //Nothing to do here because we can't create this tool from main window.
3168  break;
3169  case Tool::EndLine:
3170  ui->pointAtDistanceAngle_ToolButton->setChecked(false);
3171  break;
3172  case Tool::Line:
3173  ui->line_ToolButton->setChecked(false);
3174  break;
3175  case Tool::AlongLine:
3176  ui->alongLine_ToolButton->setChecked(false);
3177  break;
3178  case Tool::Midpoint:
3179  ui->midpoint_ToolButton->setChecked(false);
3180  break;
3181  case Tool::ShoulderPoint:
3182  ui->shoulderPoint_ToolButton->setChecked(false);
3183  break;
3184  case Tool::Normal:
3185  ui->normal_ToolButton->setChecked(false);
3186  break;
3187  case Tool::Bisector:
3188  ui->bisector_ToolButton->setChecked(false);
3189  break;
3190  case Tool::LineIntersect:
3191  ui->lineIntersect_ToolButton->setChecked(false);
3192  break;
3193  case Tool::Spline:
3194  ui->curve_ToolButton->setChecked(false);
3195  break;
3196  case Tool::CubicBezier:
3197  ui->curveWithCPs_ToolButton->setChecked(false);
3198  break;
3199  case Tool::Arc:
3200  ui->arc_ToolButton->setChecked(false);
3201  break;
3202  case Tool::ArcWithLength:
3203  ui->arcWithLength_ToolButton->setChecked(false);
3204  break;
3205  case Tool::SplinePath:
3206  ui->spline_ToolButton->setChecked(false);
3207  break;
3208  case Tool::CubicBezierPath:
3209  ui->splineWithCPs_ToolButton->setChecked(false);
3210  break;
3211  case Tool::PointOfContact:
3212  ui->pointOfContact_ToolButton->setChecked(false);
3213  break;
3214  case Tool::Piece:
3215  ui->addPatternPiece_ToolButton->setChecked(false);
3216  break;
3217  case Tool::InternalPath:
3218  ui->internalPath_ToolButton->setChecked(false);
3219  break;
3220  case Tool::Height:
3221  ui->height_ToolButton->setChecked(false);
3222  break;
3223  case Tool::Triangle:
3224  ui->triangle_ToolButton->setChecked(false);
3225  break;
3227  ui->pointIntersectXY_ToolButton->setChecked(false);
3228  break;
3229  case Tool::CutSpline:
3230  ui->pointAlongCurve_ToolButton->setChecked(false);
3231  break;
3232  case Tool::CutSplinePath:
3233  ui->pointAlongSpline_ToolButton->setChecked(false);
3234  break;
3235  case Tool::Union:
3236  ui->unitePieces_ToolButton->setChecked(false);
3237  break;
3238  case Tool::CutArc:
3239  ui->pointAlongArc_ToolButton->setChecked(false);
3240  break;
3242  ui->lineIntersectAxis_ToolButton->setChecked(false);
3243  break;
3245  ui->curveIntersectAxis_ToolButton->setChecked(false);
3246  break;
3248  ui->arcIntersectAxis_ToolButton->setChecked(false);
3249  break;
3251  ui->pointOfIntersectionArcs_ToolButton->setChecked(false);
3252  break;
3254  ui->pointOfIntersectionCircles_ToolButton->setChecked(false);
3255  break;
3257  ui->pointOfIntersectionCurves_ToolButton->setChecked(false);
3258  break;
3260  ui->pointFromCircleAndTangent_ToolButton->setChecked(false);
3261  break;
3263  ui->pointFromArcAndTangent_ToolButton->setChecked(false);
3264  break;
3265  case Tool::TrueDarts:
3266  ui->trueDarts_ToolButton->setChecked(false);
3267  break;
3268  case Tool::Group:
3269  ui->group_ToolButton->setChecked(false);
3270  break;
3271  case Tool::Rotation:
3272  ui->rotation_ToolButton->setChecked(false);
3273  break;
3274  case Tool::MirrorByLine:
3275  ui->mirrorByLine_ToolButton->setChecked(false);
3276  break;
3277  case Tool::MirrorByAxis:
3278  ui->mirrorByAxis_ToolButton->setChecked(false);
3279  break;
3280  case Tool::Move:
3281  ui->move_ToolButton->setChecked(false);
3282  break;
3283  case Tool::EllipticalArc:
3284  ui->ellipticalArc_ToolButton->setChecked(false);
3285  break;
3286  case Tool::AnchorPoint:
3287  ui->anchorPoint_ToolButton->setChecked(false);
3288  break;
3289  case Tool::InsertNodes:
3290  ui->insertNodes_ToolButton->setChecked(false);
3291  break;
3292  }
3293 
3294  // Crash: using CRTL+Z while using line tool.
3295  undoAction->setEnabled(qApp->getUndoStack()->canUndo());
3296  redoAction->setEnabled(qApp->getUndoStack()->canRedo());
3297 }
3298 
3300 
3301 //---------------------------------------------------------------------------------------------------------------------
3302 /**
3303  * @brief handleArrowTool enable arrow tool.
3304  */
3306 {
3307  if (checked && currentTool != Tool::Arrow)
3308  {
3309  qCDebug(vMainWindow, "Arrow tool.");
3310  CancelTool();
3311  ui->arrowPointer_ToolButton->setChecked(true);
3312  ui->arrow_Action->setChecked(true);
3314  emit EnableItemMove(true);
3317 
3318  // Only true for rubber band selection
3319  emit EnableLabelSelection(true);
3320  emit EnablePointSelection(false);
3321  emit EnableLineSelection(false);
3322  emit EnableArcSelection(false);
3323  emit EnableElArcSelection(false);
3324  emit EnableSplineSelection(false);
3325  emit EnableSplinePathSelection(false);
3326  emit EnableNodeLabelSelection(true);
3327  emit EnableNodePointSelection(true);
3328  emit enablePieceSelection(true);// Disable when done with pattern piece visualization
3329 
3330  // Hovering
3331  emit EnableLabelHover(true);
3332  emit EnablePointHover(true);
3333  emit EnableLineHover(true);
3334  emit EnableArcHover(true);
3335  emit EnableElArcHover(true);
3336  emit EnableSplineHover(true);
3337  emit EnableSplinePathHover(true);
3338  emit EnableNodeLabelHover(true);
3339  emit EnableNodePointHover(true);
3340  emit enablePieceHover(true);
3341 
3342  ui->view->allowRubberBand(true);
3343 
3344  ui->view->viewport()->unsetCursor();
3345  helpLabel->setText("");
3346  ui->view->setShowToolOptions(true);
3347  qCDebug(vMainWindow, "Enabled arrow tool.");
3348  }
3349  else
3350  {
3351  ui->view->viewport()->setCursor(QCursor(Qt::ArrowCursor));
3352  ui->arrowPointer_ToolButton->setChecked(true);
3353  ui->arrow_Action->setChecked(true);
3354  }
3355 }
3356 
3357 //---------------------------------------------------------------------------------------------------------------------
3358 /**
3359  * @brief keyPressEvent handle key press events.
3360  * @param event key event.
3361  */
3362 void MainWindow::keyPressEvent(QKeyEvent *event)
3363 {
3364  switch (event->key())
3365  {
3366  case Qt::Key_Escape:
3367  handleArrowTool(true);
3368  break;
3369  case Qt::Key_Return:
3370  case Qt::Key_Enter:
3371  EndVisualization();
3372  break;
3373  case Qt::Key_Space:
3374  if (qApp->Seamly2DSettings()->isPanActiveSpaceKey())
3375  {
3376  ui->zoomPan_Action->setChecked(true);
3377  }
3378  break;
3379  default:
3380  break;
3381  }
3382  QMainWindow::keyPressEvent (event);
3383 }
3384 
3385 //---------------------------------------------------------------------------------------------------------------------
3386 /**
3387  * @brief keyReleaseEvent handle key press events.
3388  * @param event key event.
3389  */
3390 void MainWindow::keyReleaseEvent(QKeyEvent *event)
3391 {
3392  switch (event->key())
3393  {
3394  case Qt::Key_Space:
3395  if (qApp->Seamly2DSettings()->isPanActiveSpaceKey())
3396  {
3397  ui->zoomPan_Action->setChecked(false);
3398  }
3399  default:
3400  break;
3401  }
3402  QMainWindow::keyReleaseEvent(event);
3403 }
3404 
3405 //---------------------------------------------------------------------------------------------------------------------
3406 /**
3407  * @brief SaveCurrentScene save scene options before set another.
3408  */
3410 {
3412  {
3413  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
3414  SCASSERT(scene != nullptr)
3415 
3416  /*Save transform*/
3417  scene->setCurrentTransform(ui->view->transform());
3418  /*Save scroll bars value for previous scene.*/
3419  QScrollBar *horScrollBar = ui->view->horizontalScrollBar();
3420  scene->setHorScrollBar(horScrollBar->value());
3421  QScrollBar *verScrollBar = ui->view->verticalScrollBar();
3422  scene->setVerScrollBar(verScrollBar->value());
3423  }
3424 }
3425 
3426 //---------------------------------------------------------------------------------------------------------------------
3427 /**
3428  * @brief RestoreCurrentScene restore scene options after change.
3429  */
3431 {
3432  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(currentScene);
3433  SCASSERT(scene != nullptr)
3434 
3435  /*Set transform for current scene*/
3436  ui->view->setTransform(scene->transform());
3437  zoomScaleChanged(ui->view->transform().m11());
3438  /*Set value for current scene scroll bar.*/
3439  QScrollBar *horScrollBar = ui->view->horizontalScrollBar();
3440  horScrollBar->setValue(scene->getHorScrollBar());
3441  QScrollBar *verScrollBar = ui->view->verticalScrollBar();
3442  verScrollBar->setValue(scene->getVerScrollBar());
3443 }
3444 
3445 //---------------------------------------------------------------------------------------------------------------------
3446 /**
3447  * @brief showDraftMode show draw scene.
3448  * @param checked true - button checked.
3449  */
3450 void MainWindow::showDraftMode(bool checked)
3451 {
3452  if (checked)
3453  {
3454  ui->toolbox_StackedWidget->setCurrentIndex(0);
3455  qCDebug(vMainWindow, "Show draft scene");
3456  handleArrowTool(true);
3457 
3458  leftGoToStage->setPixmap(QPixmap("://icon/24x24/fast_forward_left_to_right_arrow.png"));
3459  rightGoToStage->setPixmap(QPixmap("://icon/24x24/left_to_right_arrow.png"));
3460 
3461  ui->showDraftMode->setChecked(true);
3462  ui->pieceMode_Action->setChecked(false);
3463  ui->layoutMode_Action->setChecked(false);
3464 
3465  SaveCurrentScene();
3466 
3468  ui->view->setScene(currentScene);
3470 
3472  draftBlockComboBox->setCurrentIndex(currentBlockIndex); //restore current draft block
3473  drawMode = true;
3474 
3475  setEnableTools(true);
3476  SetEnableWidgets(true);
3477 
3478  draftScene->enablePiecesMode(qApp->Seamly2DSettings()->getShowControlPoints());
3479  draftScene->setOriginsVisible(qApp->Settings()->getShowAxisOrigin());
3480 
3482 
3483  //ui->toggleAnchorPoints_Action->setChecked(qApp->Settings()->getShowAnchorPoints());
3484  //draftScene->setOriginsVisible(qApp->Settings()->getShowAnchorPoints());
3485 
3486  ui->useToolColor_Action->setChecked(qApp->Settings()->getUseToolColor());
3487 
3488  ui->draft_ToolBox->setCurrentIndex(currentToolBoxIndex);
3489 
3490  if (qApp->patternType() == MeasurementsType::Multisize)
3491  {
3492  gradationHeightsLabel->setVisible(true);
3493  gradationHeights->setVisible(true);
3494  gradationSizesLabel->setVisible(true);
3495  gradationSizes->setVisible(true);
3496  }
3497  ui->groups_DockWidget->setWidget(groupsWidget);
3498  ui->groups_DockWidget->setWindowTitle(tr("Group Manager"));
3499  }
3500  else
3501  {
3502  ui->showDraftMode->setChecked(true);
3503  }
3504 }
3505 
3506 //---------------------------------------------------------------------------------------------------------------------
3507 /**
3508  * @brief showPieceMode show Piece scene.
3509  * @param checked true - button checked.
3510  */
3511 void MainWindow::showPieceMode(bool checked)
3512 {
3513  if (checked)
3514  {
3515  ui->toolbox_StackedWidget->setCurrentIndex(1);
3516  handleArrowTool(true);
3517 
3518  if(drawMode)
3519  {
3520  currentBlockIndex = draftBlockComboBox->currentIndex(); // Save current draftf block.
3521  drawMode = false;
3522  }
3523  draftBlockComboBox->setCurrentIndex(draftBlockComboBox->count()-1); // Need to get data about all blocks.
3524 
3525  leftGoToStage->setPixmap(QPixmap("://icon/24x24/right_to_left_arrow.png"));
3526  rightGoToStage->setPixmap(QPixmap("://icon/24x24/left_to_right_arrow.png"));
3527 
3528  ui->showDraftMode->setChecked(false);
3529  ui->pieceMode_Action->setChecked(true);
3530  ui->layoutMode_Action->setChecked(false);
3531 
3532  if(not qApp->getOpeningPattern())
3533  {
3534  if (pattern->DataPieces()->count() == 0)
3535  {
3536  QMessageBox::information(this, tr("Piece mode"), tr("You can't use Piece mode yet. "
3537  "Please, create at least one pattern piece."),
3538  QMessageBox::Ok, QMessageBox::Ok);
3539  showDraftMode(true);
3540  return;
3541  }
3542  }
3543 
3545 
3546  qCDebug(vMainWindow, "Show piece scene");
3547  SaveCurrentScene();
3548 
3550  ui->view->itemClicked(nullptr);
3551  ui->view->setScene(currentScene);
3553 
3554  if (mode == Draw::Calculation)
3555  {
3556  currentToolBoxIndex = ui->piece_ToolBox->currentIndex();
3557  }
3558  mode = Draw::Modeling;
3559  setEnableTools(true);
3560  SetEnableWidgets(true);
3561 
3562  pieceScene->setOriginsVisible(qApp->Settings()->getShowAxisOrigin());
3563 
3565 
3566  ui->piece_ToolBox->setCurrentIndex(ui->piece_ToolBox->indexOf(ui->details_Page));
3567 
3568  if (qApp->patternType() == MeasurementsType::Multisize)
3569  {
3570  gradationHeightsLabel->setVisible(true);
3571  gradationHeights->setVisible(true);
3572  gradationSizesLabel->setVisible(true);
3573  gradationSizes->setVisible(true);
3574  }
3575  ui->groups_DockWidget->setWidget(patternPiecesWidget);
3576  ui->groups_DockWidget->setWindowTitle(tr("Pattern Pieces"));
3577 
3578  helpLabel->setText("");
3579  }
3580  else
3581  {
3582  ui->pieceMode_Action->setChecked(true);
3583  }
3584 }
3585 
3586 //---------------------------------------------------------------------------------------------------------------------
3587 /**
3588  * @brief showLayoutMode show layout scene.
3589  * @param checked true - button checked.
3590  */
3591 void MainWindow::showLayoutMode(bool checked)
3592 {
3593  if (checked)
3594  {
3595  ui->toolbox_StackedWidget->setCurrentIndex(2);
3596  handleArrowTool(true);
3597 
3598  if(drawMode)
3599  {
3600  currentBlockIndex = draftBlockComboBox->currentIndex();//save current drfat block
3601  drawMode = false;
3602  }
3603  draftBlockComboBox->setCurrentIndex(draftBlockComboBox->count()-1);// Need to get data about all draft blocks
3604 
3605  leftGoToStage->setPixmap(QPixmap("://icon/24x24/right_to_left_arrow.png"));
3606  rightGoToStage->setPixmap(QPixmap("://icon/24x24/fast_forward_right_to_left_arrow.png"));
3607 
3608  ui->showDraftMode->setChecked(false);
3609  ui->pieceMode_Action->setChecked(false);
3610  ui->layoutMode_Action->setChecked(true);
3611 
3613  if(not qApp->getOpeningPattern())
3614  {
3615  const QHash<quint32, VPiece> *allPieces = pattern->DataPieces();
3616  if (allPieces->count() == 0)
3617  {
3618  QMessageBox::information(this, tr("Layout mode"), tr("You can't use Layout mode yet. "
3619  "Please, create at least one pattern piece."),
3620  QMessageBox::Ok, QMessageBox::Ok);
3621  showDraftMode(true);
3622  return;
3623  }
3624  else
3625  {
3626  QHash<quint32, VPiece>::const_iterator i = allPieces->constBegin();
3627  while (i != allPieces->constEnd())
3628  {
3629  if (i.value().isInLayout())
3630  {
3631  pieces.insert(i.key(), i.value());
3632  }
3633  ++i;
3634  }
3635 
3636  if (pieces.count() == 0)
3637  {
3638  QMessageBox::information(this, tr("Layout mode"), tr("You can't use Layout mode yet. Please, "
3639  "include at least one pattern piece in layout."),
3640  QMessageBox::Ok, QMessageBox::Ok);
3642  return;
3643  }
3644  }
3645  }
3646 
3647  draftBlockComboBox->setCurrentIndex(-1);// Hide pattern pieces
3648 
3649  qCDebug(vMainWindow, "Show layout scene");
3650 
3651  SaveCurrentScene();
3652 
3653  try
3654  {
3656  }
3657  catch (VException &e)
3658  {
3659  pieceList.clear();
3660  QMessageBox::warning(this, tr("Layout mode"),
3661  tr("You can't use Layout mode yet.") + QLatin1String(" \n") + e.ErrorMessage(),
3662  QMessageBox::Ok, QMessageBox::Ok);
3664  return;
3665  }
3666 
3668  ui->view->itemClicked(nullptr);
3669  ui->view->setScene(currentScene);
3670 
3671  if (mode == Draw::Calculation)
3672  {
3673  currentToolBoxIndex = ui->layout_ToolBox->currentIndex();
3674  }
3675  mode = Draw::Layout;
3676  setEnableTools(true);
3677  SetEnableWidgets(true);
3678  ui->layout_ToolBox->setCurrentIndex(ui->layout_ToolBox->indexOf(ui->layout_Page));
3679 
3680  mouseCoordinates->updateCoordinates(QPointF());
3681 
3682  if (qApp->patternType() == MeasurementsType::Multisize)
3683  {
3684  gradationHeightsLabel->setVisible(false);
3685  gradationHeights->setVisible(false);
3686  gradationSizesLabel->setVisible(false);
3687  gradationSizes->setVisible(false);
3688  }
3689 
3690  showLayoutPages(ui->listWidget->currentRow());
3691 
3692  if (scenes.isEmpty())
3693  {
3694  ui->layoutSettings_ToolButton->click();
3695  }
3696 
3697  helpLabel->setText("");
3698  }
3699  else
3700  {
3701  ui->layoutMode_Action->setChecked(true);
3702  }
3703 }
3704 
3705 //---------------------------------------------------------------------------------------------------------------------
3706 /**
3707  * @brief SaveAs save as pattern file.
3708  * @return true for successes saving.
3709  */
3711 {
3712  if (patternReadOnly)
3713  {
3714  QMessageBox messageBox(this);
3715  messageBox.setIcon(QMessageBox::Warning);
3716  messageBox.setText(tr("Can not save file."));
3717  messageBox.setInformativeText(tr("Pattern is read only."));
3718  messageBox.setDefaultButton(QMessageBox::Ok);
3719  messageBox.setStandardButtons(QMessageBox::Ok);
3720  messageBox.exec();
3721  return false;
3722  }
3723  QString filters(tr("Pattern files") + QLatin1String("(*.val)"));
3724  QString filePath = qApp->getFilePath();
3725  QString dir;
3726  QString fileName;
3727  if (filePath.isEmpty())
3728  {
3729  dir = qApp->Seamly2DSettings()->GetPathPattern();
3730  fileName = QLatin1String("pattern");
3731  }
3732  else
3733  {
3734  dir = QFileInfo(filePath).path();
3735  fileName = QFileInfo(filePath).baseName();
3736  }
3737 
3738  bool usedNotExistedDir = false;
3739  QDir directory(dir);
3740  if (!directory.exists())
3741  {
3742  usedNotExistedDir = directory.mkpath(".");
3743  }
3744 
3745  fileName = QFileDialog::getSaveFileName(this, tr("Save as"),
3746  dir + QLatin1String("/") + fileName + QLatin1String(".val"),
3747  filters, nullptr, QFileDialog::DontUseNativeDialog);
3748 
3749  auto RemoveTempDir = [usedNotExistedDir, dir]()
3750  {
3751  if (usedNotExistedDir)
3752  {
3753  QDir directory(dir);
3754  directory.rmpath(".");
3755  }
3756  };
3757 
3758  if (fileName.isEmpty())
3759  {
3760  RemoveTempDir();
3761  return false;
3762  }
3763 
3764  QFileInfo fileInfo(fileName);
3765  if (fileInfo.suffix().isEmpty() && fileInfo.suffix() != QLatin1String("val"))
3766  {
3767  fileName += QLatin1String(".val");
3768  }
3769 
3770  if (fileInfo.exists() && fileName != filePath)
3771  {
3772  // Temporarily try to lock the file before saving
3773  // Also help to rewrite current read-only pattern
3774  VLockGuard<char> tmp(fileName);
3775  if (!tmp.IsLocked())
3776  {
3777  qCWarning(vMainWindow, "%s",
3778  qUtf8Printable(tr("Failed to lock. File with this name is opened in another window.")));
3779  RemoveTempDir();
3780  return false;
3781  }
3782  }
3783 
3784  // Need for restoring previous state in case of failure
3785  const bool wasModified = doc->IsModified(); // Need because SetReadOnly() will change internal state
3786  QString error;
3787  const bool result = SavePattern(fileName, error);
3788  if (result == false)
3789  {
3790  QMessageBox messageBox(this);
3791  messageBox.setIcon(QMessageBox::Warning);
3792  messageBox.setInformativeText(tr("Could not save file"));
3793  messageBox.setDefaultButton(QMessageBox::Ok);
3794  messageBox.setDetailedText(error);
3795  messageBox.setStandardButtons(QMessageBox::Ok);
3796  messageBox.exec();
3797 
3798  // Restoring previous state
3799  doc->SetModified(wasModified);
3800 
3801  RemoveTempDir();
3802  return result;
3803  }
3804 
3805  QFile::remove(qApp->getFilePath() + autosavePrefix);
3808 
3809  if (fileName != filePath)
3810  {
3811  VlpCreateLock(lock, fileName);
3812  if (!lock->IsLocked())
3813  {
3814  qCWarning(vMainWindow, "%s", qUtf8Printable(tr("Failed to lock. This file already opened in another window. "
3815  "Expect collisions when running 2 copies of the program.")));
3816  RemoveTempDir();
3817  return false;
3818  }
3819  }
3820 
3821  RemoveTempDir();
3822  return result;
3823 }
3824 
3825 //---------------------------------------------------------------------------------------------------------------------
3826 /**
3827  * @brief Save save pattern file.
3828  * @return true for successes saving.
3829  */
3831 {
3832  if (patternReadOnly)
3833  {
3834  QMessageBox messageBox(this);
3835  messageBox.setIcon(QMessageBox::Warning);
3836  messageBox.setText(tr("Can not save file."));
3837  messageBox.setInformativeText(tr("Pattern is read only."));
3838  messageBox.setDefaultButton(QMessageBox::Ok);
3839  messageBox.setStandardButtons(QMessageBox::Ok);
3840  messageBox.exec();
3841  return false;
3842  }
3843  if (qApp->getFilePath().isEmpty())
3844  {
3845  return SaveAs();
3846  }
3847  else
3848  {
3851  {
3852  return false;
3853  }
3854 
3855 #ifdef Q_OS_WIN32
3856  qt_ntfs_permission_lookup++; // turn checking on
3857 #endif /*Q_OS_WIN32*/
3858  const bool isFileWritable = QFileInfo(qApp->getFilePath()).isWritable();
3859 
3860  if (!isFileWritable)
3861  {
3862  QMessageBox messageBox(this);
3863  messageBox.setIcon(QMessageBox::Question);
3864  messageBox.setText(tr("The document has no write permissions."));
3865  messageBox.setInformativeText("Do you want to change the permissions?");
3866  messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
3867  messageBox.setDefaultButton(QMessageBox::Yes);
3868 
3869  if (messageBox.exec() == QMessageBox::Yes)
3870  {
3871  bool changed = QFile::setPermissions(qApp->getFilePath(),
3872  QFileInfo(qApp->getFilePath()).permissions() | QFileDevice::WriteUser);
3873 #ifdef Q_OS_WIN32
3874  qt_ntfs_permission_lookup--; // turn it off again
3875 #endif /*Q_OS_WIN32*/
3876 
3877  if (!changed)
3878  {
3879  QMessageBox messageBox(this);
3880  messageBox.setIcon(QMessageBox::Warning);
3881  messageBox.setText(tr("Cannot set permissions for %1 to writable.").arg(qApp->getFilePath()));
3882  messageBox.setInformativeText(tr("Could not save the file."));
3883  messageBox.setDefaultButton(QMessageBox::Ok);
3884  messageBox.setStandardButtons(QMessageBox::Ok);
3885  messageBox.exec();
3886  return false;
3887  }
3888  }
3889  else
3890  {
3891  return false;
3892  }
3893  }
3894 
3895  QString error;
3896  bool result = SavePattern(qApp->getFilePath(), error);
3897  if (result)
3898  {
3899  QFile::remove(qApp->getFilePath() + autosavePrefix);
3902  }
3903  else
3904  {
3905  QMessageBox messageBox(this);
3906  messageBox.setIcon(QMessageBox::Warning);
3907  messageBox.setText(tr("Could not save the file"));
3908  messageBox.setDefaultButton(QMessageBox::Ok);
3909  messageBox.setDetailedText(error);
3910  messageBox.setStandardButtons(QMessageBox::Ok);
3911  messageBox.exec();
3912  }
3913  return result;
3914  }
3915 }
3916 
3917 //---------------------------------------------------------------------------------------------------------------------
3918 /**
3919  * @brief Open ask user select pattern file.
3920  */
3922 {
3923  qCDebug(vMainWindow, "Opening new file.");
3924  const QString filter(tr("Pattern files (*.val)"));
3925  //Get list last open files
3926  const QStringList files = qApp->Seamly2DSettings()->GetRecentFileList();
3927  QString dir;
3928  if (files.isEmpty())
3929  {
3930  dir = QDir::homePath();
3931  }
3932  else
3933  {
3934  //Absolute path to last open file
3935  dir = QFileInfo(files.first()).absolutePath();
3936  }
3937  qCDebug(vMainWindow, "Run QFileDialog::getOpenFileName: dir = %s.", qUtf8Printable(dir));
3938  const QString filePath = QFileDialog::getOpenFileName(this, tr("Open file"), dir, filter, nullptr,
3939  QFileDialog::DontUseNativeDialog);
3940  if (filePath.isEmpty())
3941  {
3942  return;
3943  }
3944  LoadPattern(filePath);
3945 }
3946 
3947 //---------------------------------------------------------------------------------------------------------------------
3948 /**
3949  * @brief Clear reset to default window.
3950  */
3952 {
3953  qCDebug(vMainWindow, "Resetting main window.");
3954  lock.reset();
3955  qCDebug(vMainWindow, "Unlocked pattern file.");
3956  showDraftMode(true);
3957  qCDebug(vMainWindow, "Returned to Draft mode.");
3958  setCurrentFile(QString());
3959  pattern->Clear();
3960  qCDebug(vMainWindow, "Clearing pattern.");
3961  if (not qApp->getFilePath().isEmpty() && not doc->MPath().isEmpty())
3962  {
3963  watcher->removePath(AbsoluteMPath(qApp->getFilePath(), doc->MPath()));
3964  }
3965  doc->clear();
3966  qCDebug(vMainWindow, "Clearing scenes.");
3967  draftScene->clear();
3968  pieceScene->clear();
3969  handleArrowTool(true);
3970  draftBlockComboBox->clear();
3971  ui->showDraftMode->setEnabled(false);
3972  ui->pieceMode_Action->setEnabled(false);
3973  ui->layoutMode_Action->setEnabled(false);
3974  ui->newDraft_Action->setEnabled(false);
3975  ui->renameDraft_Action->setEnabled(false);
3976  ui->save_Action->setEnabled(false);
3977  ui->saveAs_Action->setEnabled(false);
3978  ui->patternPreferences_Action->setEnabled(false);
3979 
3980  // disable zoom actions until a pattern is loaded
3981  zoomScaleSpinBox->setEnabled(false);
3982  ui->zoomIn_Action->setEnabled(false);
3983  ui->zoomOut_Action->setEnabled(false);
3984  ui->zoomToFit_Action->setEnabled(false);
3985  ui->zoomToSelected_Action->setEnabled(false);
3986  ui->zoom100Percent_Action->setEnabled(false);
3987  ui->zoomToPrevious_Action->setEnabled(false);
3988  ui->zoomToArea_Action->setEnabled(false);
3989  ui->zoomPan_Action->setEnabled(false);
3990  ui->zoomToPoint_Action->setEnabled(false);
3991 
3992  //disable group actions
3993  ui->groups_DockWidget->setEnabled(false);
3994 
3995  //disable history menu actions
3996  ui->history_Action->setEnabled(false);
3997  ui->table_Action->setEnabled(false);
3998 
3999  ui->lastTool_Action->setEnabled(false);
4000  ui->increaseSize_Action->setEnabled(false);
4001  ui->decreaseSize_Action->setEnabled(false);
4002  ui->useToolColor_Action->setEnabled(false);
4003  ui->showPointNames_Action->setEnabled(false);
4004  ui->toggleWireframe_Action->setEnabled(false);
4005  ui->toggleControlPoints_Action->setEnabled(false);
4006  ui->toggleAxisOrigin_Action->setEnabled(false);
4007  ui->toggleSeamAllowances_Action->setEnabled(false);
4008  ui->toggleGrainLines_Action->setEnabled(false);
4009  ui->toggleLabels_Action->setEnabled(false);
4010  //ui->toggleAnchorPoints_Action->setEnabled(false);
4011 
4012 
4013  //disable measurements menu actions
4014  ui->loadIndividual_Action->setEnabled(false);
4015  ui->loadMultisize_Action->setEnabled(false);
4016  ui->unloadMeasurements_Action->setEnabled(false);
4017  ui->editCurrent_Action->setEnabled(false);
4018 
4019  setEnableTools(false);
4020  qApp->setPatternUnit(Unit::Cm);
4021  qApp->setPatternType(MeasurementsType::Unknown);
4022 
4023 #ifndef QT_NO_CURSOR
4024  QGuiApplication::restoreOverrideCursor();
4025 #endif
4026  CleanLayout();
4027  pieceList.clear(); // don't move to CleanLayout()
4028  qApp->getUndoStack()->clear();
4030  toolProperties->itemClicked(nullptr);
4031 }
4032 
4033 //---------------------------------------------------------------------------------------------------------------------
4035 {
4036  WriteSettings();
4037 
4038  //File was closed correct.
4039  QStringList restoreFiles = qApp->Seamly2DSettings()->GetRestoreFileList();
4040  restoreFiles.removeAll(qApp->getFilePath());
4041  qApp->Seamly2DSettings()->SetRestoreFileList(restoreFiles);
4042 
4043  // Remove autosave file
4044  QFile autofile(qApp->getFilePath() + autosavePrefix);
4045  if (autofile.exists())
4046  {
4047  autofile.remove();
4048  }
4049  qCDebug(vMainWindow, "File %s closed correct.", qUtf8Printable(qApp->getFilePath()));
4050 }
4051 
4052 //---------------------------------------------------------------------------------------------------------------------
4054 {
4055  qCDebug(vMainWindow, "Full parsing file");
4056 
4058  try
4059  {
4060  SetEnabledGUI(true);
4062  }
4063  catch (const VExceptionUndo &e)
4064  {
4065  Q_UNUSED(e)
4066  /* If user want undo last operation before undo we need finish broken redo operation. For those we post event
4067  * myself. Later in method customEvent call undo.*/
4068  QApplication::postEvent(this, new UndoEvent());
4069  return;
4070  }
4071  catch (const VExceptionObjectError &e)
4072  {
4073  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error parsing file.")), //-V807
4074  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
4075  SetEnabledGUI(false);
4076  if (not VApplication::IsGUIMode())
4077  {
4078  qApp->exit(V_EX_NOINPUT);
4079  }
4080  return;
4081  }
4082  catch (const VExceptionConversionError &e)
4083  {
4084  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error can't convert value.")),
4085  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
4086  SetEnabledGUI(false);
4087  if (not VApplication::IsGUIMode())
4088  {
4089  qApp->exit(V_EX_NOINPUT);
4090  }
4091  return;
4092  }
4093  catch (const VExceptionEmptyParameter &e)
4094  {
4095  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error empty parameter.")),
4096  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
4097  SetEnabledGUI(false);
4098  if (not VApplication::IsGUIMode())
4099  {
4100  qApp->exit(V_EX_NOINPUT);
4101  }
4102  return;
4103  }
4104  catch (const VExceptionWrongId &e)
4105  {
4106  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error wrong id.")),
4107  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
4108  SetEnabledGUI(false);
4109  if (not VApplication::IsGUIMode())
4110  {
4111  qApp->exit(V_EX_NOINPUT);
4112  }
4113  return;
4114  }
4115  catch (VException &e)
4116  {
4117  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error parsing file.")),
4118  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
4119  SetEnabledGUI(false);
4120  if (not VApplication::IsGUIMode())
4121  {
4122  qApp->exit(V_EX_NOINPUT);
4123  }
4124  return;
4125  }
4126  catch (const std::bad_alloc &)
4127  {
4128  qCCritical(vMainWindow, "%s", qUtf8Printable(tr("Error parsing file (std::bad_alloc).")));
4129  SetEnabledGUI(false);
4130  if (not VApplication::IsGUIMode())
4131  {
4132  qApp->exit(V_EX_NOINPUT);
4133  }
4134  return;
4135  }
4136 
4137  QString patternPiece;
4138  if (draftBlockComboBox->currentIndex() != -1)
4139  {
4140  patternPiece = draftBlockComboBox->itemText(draftBlockComboBox->currentIndex());
4141  }
4142  draftBlockComboBox->blockSignals(true);
4143  draftBlockComboBox->clear();
4144 
4145  QStringList draftBlockNames = doc->getPatternPieces();
4146  draftBlockNames.sort();
4147  draftBlockComboBox->addItems(draftBlockNames);
4148 
4149  if (not drawMode)
4150  {
4151  draftBlockComboBox->setCurrentIndex(draftBlockComboBox->count()-1);
4152  }
4153  else
4154  {
4155  const qint32 index = draftBlockComboBox->findText(patternPiece);
4156  if ( index != -1 )
4157  {
4158  draftBlockComboBox->setCurrentIndex(index);
4159  }
4160  }
4161  draftBlockComboBox->blockSignals(false);
4162  ui->patternPreferences_Action->setEnabled(true);
4163 
4164  GlobalchangeDraftBlock(patternPiece);
4165 
4166  setEnableTools(draftBlockComboBox->count() > 0);
4168 
4171 }
4172 
4173 //---------------------------------------------------------------------------------------------------------------------
4174 void MainWindow::GlobalchangeDraftBlock(const QString &patternPiece)
4175 {
4176  const qint32 index = draftBlockComboBox->findText(patternPiece);
4177  try
4178  {
4179  if ( index != -1 )
4180  { // -1 for not found
4181  changeDraftBlock(index, false);
4182  }
4183  else
4184  {
4185  changeDraftBlock(0, false);
4186  }
4187  }
4188  catch (VExceptionBadId &e)
4189  {
4190  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Bad id.")),
4191  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
4192  SetEnabledGUI(false);
4193  if (not VApplication::IsGUIMode())
4194  {
4195  qApp->exit(V_EX_NOINPUT);
4196  }
4197  return;
4198  }
4199  catch (const VExceptionEmptyParameter &e)
4200  {
4201  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error empty parameter.")),
4202  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
4203  SetEnabledGUI(false);
4204  if (not VApplication::IsGUIMode())
4205  {
4206  qApp->exit(V_EX_NOINPUT);
4207  }
4208  return;
4209  }
4210 }
4211 
4212 //---------------------------------------------------------------------------------------------------------------------
4213 void MainWindow::SetEnabledGUI(bool enabled)
4214 {
4215  if (guiEnabled != enabled)
4216  {
4217  if (enabled == false)
4218  {
4219  handleArrowTool(true);
4220  qApp->getUndoStack()->clear();
4221  }
4222  SetEnableWidgets(enabled);
4223 
4224  guiEnabled = enabled;
4225 
4226  setEnableTools(enabled);
4227  ui->statusBar->setEnabled(enabled);
4228  #ifndef QT_NO_CURSOR
4229  QGuiApplication::setOverrideCursor(Qt::ArrowCursor);
4230  #endif
4231  }
4232 }
4233 
4234 //---------------------------------------------------------------------------------------------------------------------
4235 /**
4236  * @brief SetEnableWidgets enable action button.
4237  * @param enable enable value.
4238  */
4240 {
4241  const bool draftStage = (mode == Draw::Calculation);
4242  const bool pieceStage = (mode == Draw::Modeling);
4243  const bool designStage = (draftStage || pieceStage);
4244  const bool layoutStage = (mode == Draw::Layout);
4245 
4246  draftBlockComboBox->setEnabled(enable && draftStage);
4247  ui->arrow_Action->setEnabled(enable && designStage);
4248 
4249  // enable file menu actions
4250  ui->save_Action->setEnabled(isWindowModified() && enable && not patternReadOnly);
4251  ui->saveAs_Action->setEnabled(enable);
4252  ui->patternPreferences_Action->setEnabled(enable && designStage);
4253 
4254  // enable edit menu actions
4255  undoAction->setEnabled(enable && designStage && qApp->getUndoStack()->canUndo());
4256  redoAction->setEnabled(enable && designStage && qApp->getUndoStack()->canRedo());
4257 
4258  // enable view menu actions
4259  ui->showDraftMode->setEnabled(enable);
4260  ui->pieceMode_Action->setEnabled(enable);
4261  ui->layoutMode_Action->setEnabled(enable);
4262  zoomScaleSpinBox->setEnabled(enable);
4263  ui->zoomIn_Action->setEnabled(enable);
4264  ui->zoomOut_Action->setEnabled(enable);
4265  ui->zoomToFit_Action->setEnabled(enable);
4266  ui->zoomToSelected_Action->setEnabled(enable);
4267  ui->zoom100Percent_Action->setEnabled(enable);
4268  ui->zoomToPrevious_Action->setEnabled(enable);
4269  ui->zoomToArea_Action->setEnabled(enable);
4270  ui->zoomPan_Action->setEnabled(enable);
4271  ui->zoomToPoint_Action->setEnabled(enable && draftStage);
4272  m_zoomToPointComboBox->setEnabled(enable && draftStage);
4273 
4274  ui->increaseSize_Action->setEnabled(enable);
4275  ui->decreaseSize_Action->setEnabled(enable);
4276  ui->useToolColor_Action->setEnabled(enable && draftStage);
4277  ui->showPointNames_Action->setEnabled(enable);
4278  ui->toggleWireframe_Action->setEnabled(enable);
4279  ui->toggleControlPoints_Action->setEnabled(enable && draftStage);
4280  ui->toggleAxisOrigin_Action->setEnabled(enable);
4281  ui->toggleSeamAllowances_Action->setEnabled(enable && pieceStage);
4282  ui->toggleGrainLines_Action->setEnabled(enable && pieceStage);
4283  ui->toggleLabels_Action->setEnabled(enable && pieceStage);
4284  //ui->toggleAnchorPoints_Action->setEnabled(enable && draftStage);
4285 
4286  //enable group actions
4287  groupsWidget->setAddGroupEnabled(enable && draftStage);
4288 
4289  //enable tool menu actions
4290  ui->newDraft_Action->setEnabled(enable && draftStage);
4291  ui->renameDraft_Action->setEnabled(enable && draftStage);
4292 
4293  //enable measurement menu actions
4294  ui->loadIndividual_Action->setEnabled(enable && designStage);
4295  ui->loadMultisize_Action->setEnabled(enable && designStage);
4296  ui->unloadMeasurements_Action->setEnabled(enable && designStage);
4297  ui->table_Action->setEnabled(enable && draftStage);
4298 
4299  //enable history menu actions
4300  ui->history_Action->setEnabled(enable && draftStage);
4301 
4302  //enable utilities menu actions
4303  ui->calculator_Action->setEnabled(enable);
4304  ui->decimalChart_Action->setEnabled(enable);
4305 
4306  //enable help menu
4307  ui->shortcuts_Action->setEnabled(enable);
4308 
4309  //enable dock widget actions
4310  ui->groups_DockWidget->setEnabled(enable && designStage);
4311  ui->toolProperties_DockWidget->setEnabled(enable && draftStage);
4312  ui->layoutPages_DockWidget->setEnabled(enable && layoutStage);
4313  actionDockWidgetToolOptions->setEnabled(enable && designStage);
4314  actionDockWidgetGroups->setEnabled(enable && designStage);
4315  actionDockWidgetLayouts->setEnabled(enable && layoutStage);
4316 
4317  //Now we don't want allow user call context menu
4319  ui->view->setEnabled(enable);
4320 }
4321 
4322 //---------------------------------------------------------------------------------------------------------------------
4323 void MainWindow::UpdateHeightsList(const QStringList &list)
4324 {
4325  QString val;
4326  if (gradationHeights->currentIndex() != -1)
4327  {
4328  val = gradationHeights->currentText();
4329  }
4330 
4331  gradationHeights->blockSignals(true);
4332  gradationHeights->clear();
4333  gradationHeights->addItems(list);
4334  gradationHeights->blockSignals(false);
4335 
4336  int index = gradationHeights->findText(val);
4337  if (index != -1)
4338  {
4339  gradationHeights->setCurrentIndex(index);
4340  }
4341  else
4342  {
4343  ChangedHeight(0);
4344  }
4345 }
4346 
4347 //---------------------------------------------------------------------------------------------------------------------
4348 void MainWindow::UpdateSizesList(const QStringList &list)
4349 {
4350  QString val;
4351  if (gradationSizes->currentIndex() != -1)
4352  {
4353  val = gradationSizes->currentText();
4354  }
4355 
4356  gradationSizes->blockSignals(true);
4357  gradationSizes->clear();
4358  gradationSizes->addItems(list);
4359  gradationSizes->blockSignals(false);
4360 
4361  int index = gradationSizes->findText(val);
4362  if (index != -1)
4363  {
4364  gradationSizes->setCurrentIndex(index);
4365  }
4366  else
4367  {
4368  ChangedSize(0);
4369  }
4370 }
4371 
4372 //---------------------------------------------------------------------------------------------------------------------
4373 /**
4374  * @brief NewPattern create new empty pattern.
4375  */
4377 {
4378  if (draftBlockComboBox->count() == 0)
4379  {
4380  // Creating a new pattern design requires creating a new draft block
4381  qCDebug(vMainWindow, "New Draft Block.");
4382  QString draftBlockName = tr("Draft block %1").arg(draftBlockComboBox->count()+1);
4383  qCDebug(vMainWindow, "Generated Draft Block name: %s", qUtf8Printable(draftBlockName));
4384 
4385  qCDebug(vMainWindow, "First Draft Block");
4386  DialogNewPattern newPattern(pattern, draftBlockName, this);
4387  if (newPattern.exec() == QDialog::Accepted)
4388  {
4389  draftBlockName = newPattern.name();
4390  qApp->setPatternUnit(newPattern.PatternUnit());
4391  qCDebug(vMainWindow, "Draft Block name: %s", qUtf8Printable(draftBlockName));
4392  }
4393  else
4394  {
4395  qCDebug(vMainWindow, "Creating new Draft Block was canceled.");
4396  return;
4397  }
4398 
4399  //Set scene size to size scene view
4402 
4403  addDraftBlock(draftBlockName);
4404 
4405  mouseCoordinates = new MouseCoordinates(qApp->patternUnit());
4406  ui->statusBar->addPermanentWidget((mouseCoordinates));
4407 
4410  }
4411  else
4412  {
4413  OpenNewSeamly2D();
4414  }
4415 }
4416 
4417 //---------------------------------------------------------------------------------------------------------------------
4418 /**
4419  * @brief haveChange enable action save if we have unsaved change.
4420  */
4422 {
4423  if (guiEnabled)
4424  {
4425  const bool state = doc->IsModified() || !saved;
4426  setWindowModified(state);
4427  not patternReadOnly ? ui->save_Action->setEnabled(state): ui->save_Action->setEnabled(false);
4428  isLayoutStale = true;
4429  }
4430 }
4431 
4432 //---------------------------------------------------------------------------------------------------------------------
4433 /**
4434  * @brief ChangedSize change new size value.
4435  * @param index index of the selected item.
4436  */
4438 {
4439  const int size = static_cast<int>(VContainer::size());
4440  if (UpdateMeasurements(AbsoluteMPath(qApp->getFilePath(), doc->MPath()),
4441  gradationSizes.data()->itemText(index).toInt(),
4442  static_cast<int>(VContainer::height())))
4443  {
4445  emit pieceScene->DimensionsChanged();
4446  }
4447  else
4448  {
4449  qCWarning(vMainWindow, "%s", qUtf8Printable(tr("Couldn't update measurements.")));
4450 
4451  const qint32 index = gradationSizes->findText(QString().setNum(size));
4452  if (index != -1)
4453  {
4454  gradationSizes->setCurrentIndex(index);
4455  }
4456  else
4457  {
4458  qCDebug(vMainWindow, "Couldn't restore size value.");
4459  }
4460  }
4461 }
4462 
4463 //---------------------------------------------------------------------------------------------------------------------
4464 /**
4465  * @brief ChangedGrowth change new height value.
4466  * @param index index of the selected item.
4467  */
4469 {
4470  const int height = static_cast<int>(VContainer::height());
4471  if (UpdateMeasurements(AbsoluteMPath(qApp->getFilePath(), doc->MPath()), static_cast<int>(VContainer::size()),
4472  gradationHeights.data()->itemText(index).toInt()))
4473  {
4475  emit pieceScene->DimensionsChanged();
4476  }
4477  else
4478  {
4479  qCWarning(vMainWindow, "%s", qUtf8Printable(tr("Couldn't update measurements.")));
4480 
4481  const qint32 index = gradationHeights->findText(QString().setNum(height));
4482  if (index != -1)
4483  {
4484  gradationHeights->setCurrentIndex(index);
4485  }
4486  else
4487  {
4488  qCDebug(vMainWindow, "Couldn't restore height value.");
4489  }
4490  }
4491 }
4492 
4493 //---------------------------------------------------------------------------------------------------------------------
4495 {
4496  const QString defHeight = QString().setNum(doc->GetDefCustomHeight());
4497  int index = gradationHeights->findText(defHeight);
4498  if (index != -1)
4499  {
4500  gradationHeights->setCurrentIndex(index);
4501  }
4502  else
4503  {
4504  index = gradationHeights->findText(QString().setNum(VContainer::height()));
4505  if (index != -1)
4506  {
4507  gradationHeights->setCurrentIndex(index);
4508  }
4509  }
4510  VContainer::SetHeight(gradationHeights->currentText().toInt());
4511 }
4512 
4513 //---------------------------------------------------------------------------------------------------------------------
4515 {
4516  const QString defSize = QString().setNum(doc->GetDefCustomSize());
4517  int index = gradationSizes->findText(defSize);
4518  if (index != -1)
4519  {
4520  gradationSizes->setCurrentIndex(index);
4521  }
4522  else
4523  {
4524  index = gradationSizes->findText(QString().setNum(VContainer::size()));
4525  if (index != -1)
4526  {
4527  gradationSizes->setCurrentIndex(index);
4528  }
4529  }
4530  VContainer::SetSize(gradationSizes->currentText().toInt());
4531 }
4532 
4533 //---------------------------------------------------------------------------------------------------------------------
4534 /**
4535  * @brief setEnableTools enable button.
4536  * @param enable enable value.
4537  */
4539 {
4540  bool draftTools = false;
4541  bool pieceTools = false;
4542  bool layoutTools = false;
4543 
4544  switch (mode)
4545  {
4546  case Draw::Calculation:
4547  draftTools = enable;
4548  break;
4549  case Draw::Modeling:
4550  pieceTools = enable;
4551  break;
4552  case Draw::Layout:
4553  layoutTools = enable;
4554  break;
4555  default:
4556  break;
4557  }
4558 
4559  // This check helps to find missed tools
4560  Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 53, "Not all tools were handled.");
4561 
4562  //Toolbox Drafting Tools
4563  //Points
4564  ui->pointAtDistanceAngle_ToolButton->setEnabled(draftTools);
4565  ui->alongLine_ToolButton->setEnabled(draftTools);
4566  ui->normal_ToolButton->setEnabled(draftTools);
4567  ui->bisector_ToolButton->setEnabled(draftTools);
4568  ui->shoulderPoint_ToolButton->setEnabled(draftTools);
4569  ui->pointOfContact_ToolButton->setEnabled(draftTools);
4570  ui->triangle_ToolButton->setEnabled(draftTools);
4571  ui->pointIntersectXY_ToolButton->setEnabled(draftTools);
4572  ui->height_ToolButton->setEnabled(draftTools);
4573  ui->lineIntersectAxis_ToolButton->setEnabled(draftTools);
4574  ui->midpoint_ToolButton->setEnabled(draftTools);
4575 
4576  //Lines
4577  ui->line_ToolButton->setEnabled(draftTools);
4578  ui->lineIntersect_ToolButton->setEnabled(draftTools);
4579 
4580  //Curves
4581  ui->curve_ToolButton->setEnabled(draftTools);
4582  ui->spline_ToolButton->setEnabled(draftTools);
4583  ui->curveWithCPs_ToolButton->setEnabled(draftTools);
4584  ui->splineWithCPs_ToolButton->setEnabled(draftTools);
4585  ui->pointAlongCurve_ToolButton->setEnabled(draftTools);
4586  ui->pointAlongSpline_ToolButton->setEnabled(draftTools);
4587  ui->pointOfIntersectionCurves_ToolButton->setEnabled(draftTools);
4588  ui->curveIntersectAxis_ToolButton->setEnabled(draftTools);
4589 
4590  //Arcs
4591  ui->arc_ToolButton->setEnabled(draftTools);
4592  ui->pointAlongArc_ToolButton->setEnabled(draftTools);
4593  ui->arcIntersectAxis_ToolButton->setEnabled(draftTools);
4594  ui->pointOfIntersectionArcs_ToolButton->setEnabled(draftTools);
4595  ui->pointOfIntersectionCircles_ToolButton->setEnabled(draftTools);
4596  ui->pointFromCircleAndTangent_ToolButton->setEnabled(draftTools);
4597  ui->pointFromArcAndTangent_ToolButton->setEnabled(draftTools);
4598  ui->arcWithLength_ToolButton->setEnabled(draftTools);
4599  ui->ellipticalArc_ToolButton->setEnabled(draftTools);
4600 
4601  //Operations
4602  ui->group_ToolButton->setEnabled(draftTools);
4603  ui->rotation_ToolButton->setEnabled(draftTools);
4604  ui->mirrorByLine_ToolButton->setEnabled(draftTools);
4605  ui->mirrorByAxis_ToolButton->setEnabled(draftTools);
4606  ui->move_ToolButton->setEnabled(draftTools);
4607  ui->trueDarts_ToolButton->setEnabled(draftTools);
4608  ui->exportDraftBlocks_ToolButton->setEnabled(draftTools);
4609 
4610  //Piece
4611  ui->addPatternPiece_ToolButton->setEnabled(draftTools);
4612  ui->anchorPoint_ToolButton->setEnabled(draftTools & (pattern->DataPieces()->size() > 0));
4613  ui->internalPath_ToolButton->setEnabled(draftTools & (pattern->DataPieces()->size() > 0));
4614  ui->insertNodes_ToolButton->setEnabled(draftTools & (pattern->DataPieces()->size() > 0));
4615 
4616  //Details
4617  ui->unitePieces_ToolButton->setEnabled(pieceTools);
4618  ui->exportPiecesAs_ToolButton->setEnabled(pieceTools);
4619 
4620  //Layout
4621  ui->layoutSettings_ToolButton->setEnabled(layoutTools);
4622 
4623  //enable Toolbox Toolbar actions
4624  ui->arrow_Action->setEnabled(enable);
4625  ui->points_Action->setEnabled(draftTools);
4626  ui->lines_Action->setEnabled(draftTools);
4627  ui->arcs_Action->setEnabled(draftTools);
4628  ui->curves_Action->setEnabled(draftTools);
4629  ui->modifications_Action->setEnabled(draftTools);
4630  ui->pieces_Action->setEnabled(draftTools);
4631  ui->details_Action->setEnabled(pieceTools);
4632  ui->layout_Action->setEnabled(layoutTools);
4633 
4634  //Menu Actions
4635  //Points
4636  ui->midpoint_Action->setEnabled(draftTools);
4637  ui->pointAtDistanceAngle_Action->setEnabled(draftTools);
4638  ui->pointAlongLine_Action->setEnabled(draftTools);
4639  ui->pointAlongPerpendicular_Action->setEnabled(draftTools);
4640  ui->bisector_Action->setEnabled(draftTools);
4641  ui->pointOnShoulder_Action->setEnabled(draftTools);
4642  ui->pointOfContact_Action->setEnabled(draftTools);
4643  ui->triangle_Action->setEnabled(draftTools);
4644  ui->pointIntersectXY_Action->setEnabled(draftTools);
4645  ui->perpendicularPoint_Action->setEnabled(draftTools);
4646  ui->pointIntersectAxis_Action->setEnabled(draftTools);
4647 
4648  //Lines
4649  ui->lineTool_Action->setEnabled(draftTools);
4650  ui->lineIntersect_Action->setEnabled(draftTools);
4651 
4652  //Curves
4653  ui->curve_Action->setEnabled(draftTools);
4654  ui->spline_Action->setEnabled(draftTools);
4655  ui->curveWithCPs_Action->setEnabled(draftTools);
4656  ui->splineWithCPs_Action->setEnabled(draftTools);
4657  ui->pointAlongCurve_Action->setEnabled(draftTools);
4658  ui->pointAlongSpline_Action->setEnabled(draftTools);
4659  ui->curveIntersectCurve_Action->setEnabled(draftTools);
4660  ui->splineIntersectAxis_Action->setEnabled(draftTools);
4661 
4662  //Arcs
4663  ui->arcTool_Action->setEnabled(draftTools);
4664  ui->pointAlongArc_Action->setEnabled(draftTools);
4665  ui->arcIntersectAxis_Action->setEnabled(draftTools);
4666  ui->arcIntersectArc_Action->setEnabled(draftTools);
4667  ui->circleIntersect_Action->setEnabled(draftTools);
4668  ui->circleTangent_Action->setEnabled(draftTools);
4669  ui->arcTangent_Action->setEnabled(draftTools);;
4670  ui->arcWithLength_Action->setEnabled(draftTools);
4671  ui->ellipticalArc_Action->setEnabled(draftTools);
4672 
4673  //Operations
4674  ui->group_Action->setEnabled(draftTools);
4675  ui->rotation_Action->setEnabled(draftTools);
4676  ui->mirrorByLine_Action->setEnabled(draftTools);
4677  ui->mirrorByAxis_Action->setEnabled(draftTools);
4678  ui->move_Action->setEnabled(draftTools);
4679  ui->trueDarts_Action->setEnabled(draftTools);
4680  ui->exportDraftBlocks_Action->setEnabled(draftTools);
4681 
4682  //Piece
4683  ui->addPiece_Action->setEnabled(draftTools);
4684  ui->anchorPoint_Action->setEnabled(draftTools & (pattern->DataPieces()->size() > 0));
4685  ui->internalPath_Action->setEnabled(draftTools & (pattern->DataPieces()->size() > 0));
4686  ui->insertNodes_Action->setEnabled(draftTools & (pattern->DataPieces()->size() > 0));
4687 
4688  //Details
4689  ui->union_Action->setEnabled(pieceTools);
4690  ui->exportPieces_Action->setEnabled(pieceTools);
4691 
4692  //Layout
4693  ui->newPrintLayout_Action->setEnabled(layoutTools);
4694  ui->exportLayout_Action->setEnabled(layoutTools);
4695  ui->lastTool_Action->setEnabled(draftTools);
4696 
4697  ui->arrowPointer_ToolButton->setEnabled(draftTools || pieceTools);
4698  ui->arrowPointer_ToolButton->setChecked(draftTools || pieceTools);
4699  ui->arrow_Action->setChecked(draftTools || pieceTools);
4700 }
4701 
4702 //---------------------------------------------------------------------------------------------------------------------
4704 {
4705  const bool enabled = not scenes.isEmpty();
4706 
4707  ui->exportLayout_ToolButton->setEnabled(enabled);
4708  ui->exportAs_Action->setEnabled(enabled);
4709  ui->printPreview_Action->setEnabled(enabled);
4710  ui->printPreviewTiled_Action->setEnabled(enabled);
4711  ui->print_Action->setEnabled(enabled);
4712  ui->printTiled_Action->setEnabled(enabled);
4713 }
4714 
4715 //---------------------------------------------------------------------------------------------------------------------
4716 /**
4717  * @brief MinimumScrollBar set scroll bar to minimum.
4718  */
4720 {
4721  QScrollBar *horScrollBar = ui->view->horizontalScrollBar();
4722  horScrollBar->setValue(horScrollBar->minimum());
4723  QScrollBar *verScrollBar = ui->view->verticalScrollBar();
4724  verScrollBar->setValue(verScrollBar->minimum());
4725 }
4726 
4727 //---------------------------------------------------------------------------------------------------------------------
4728 /**
4729  * @brief SavePattern save pattern file.
4730  * @param fileName pattern file name.
4731  * @return true if all is good.
4732  */
4733 bool MainWindow::SavePattern(const QString &fileName, QString &error)
4734 {
4735  qCDebug(vMainWindow, "Saving pattern file %s.", qUtf8Printable(fileName));
4736  QFileInfo tempInfo(fileName);
4737 
4738  const QString mPath = AbsoluteMPath(qApp->getFilePath(), doc->MPath());
4739  if (not mPath.isEmpty() && qApp->getFilePath() != fileName)
4740  {
4741  doc->SetMPath(RelativeMPath(fileName, mPath));
4742  }
4743 
4744  const bool result = doc->SaveDocument(fileName, error);
4745  if (result)
4746  {
4747  if (tempInfo.suffix() != QLatin1String("autosave"))
4748  {
4749  setCurrentFile(fileName);
4750  helpLabel->setText(tr("File saved"));
4751  qCDebug(vMainWindow, "File %s saved.", qUtf8Printable(fileName));
4752  PatternChangesWereSaved(result);
4753  }
4754  }
4755  else
4756  {
4757  doc->SetMPath(mPath);
4758  emit doc->UpdatePatternLabel();
4759  qCDebug(vMainWindow, "Could not save file %s. %s.", qUtf8Printable(fileName), qUtf8Printable(error));
4760  }
4761  return result;
4762 }
4763 
4764 //---------------------------------------------------------------------------------------------------------------------
4765 /**
4766  * @brief AutoSavePattern start safe saving.
4767  */
4769 {
4770  if (patternReadOnly)
4771  {
4772  return;
4773  }
4774  qCDebug(vMainWindow, "Autosaving pattern.");
4775 
4776  if (qApp->getFilePath().isEmpty() == false && this->isWindowModified() == true)
4777  {
4778  QString autofile = qApp->getFilePath() + autosavePrefix;
4779  QString error;
4780  SavePattern(autofile, error);
4781  }
4782 }
4783 
4784 //---------------------------------------------------------------------------------------------------------------------
4785 /**
4786  * @brief setCurrentFile the function is called to reset the state of a few variables when a file
4787  * is loaded or saved, or when the user starts editing a new file (in which case fileName is empty).
4788  * @param fileName file name.
4789  */
4790 void MainWindow::setCurrentFile(const QString &fileName)
4791 {
4792  qCDebug(vMainWindow, "Set current name to \"%s\"", qUtf8Printable(fileName));
4793  qApp->setFilePath(fileName);
4794  doc->SetPatternWasChanged(true);
4795  emit doc->UpdatePatternLabel();
4796  qApp->getUndoStack()->setClean();
4797 
4798  if (not qApp->getFilePath().isEmpty() && VApplication::IsGUIMode())
4799  {
4800  qCDebug(vMainWindow, "Updating recent file list.");
4801  VSettings *settings = qApp->Seamly2DSettings();
4802  QStringList files = settings->GetRecentFileList();
4803  files.removeAll(fileName);
4804  files.prepend(fileName);
4805  while (files.size() > MaxRecentFiles)
4806  {
4807  files.removeLast();
4808  }
4809 
4810  settings->SetRecentFileList(files);
4812 
4813  qCDebug(vMainWindow, "Updating restore file list.");
4814  QStringList restoreFiles = settings->GetRestoreFileList();
4815  restoreFiles.removeAll(fileName);
4816  restoreFiles.prepend(fileName);
4817  settings->SetRestoreFileList(restoreFiles);
4818  }
4819 
4821 }
4822 
4823 //---------------------------------------------------------------------------------------------------------------------
4824 /**
4825  * @brief ReadSettings read setting for app.
4826  */
4828 {
4829  qCDebug(vMainWindow, "Reading settings.");
4830  const VSettings *settings = qApp->Seamly2DSettings();
4831  restoreGeometry(settings->GetGeometry());
4832  restoreState(settings->GetWindowState());
4833  restoreState(settings->GetToolbarsState(), APP_VERSION);
4834 
4835  // Scene antialiasing
4836  const bool graphOutputValue = settings->GetGraphicalOutput();
4837  ui->view->setRenderHint(QPainter::Antialiasing, graphOutputValue);
4838  ui->view->setRenderHint(QPainter::SmoothPixmapTransform, graphOutputValue);
4839 
4840  // Stack limit
4841  qApp->getUndoStack()->setUndoLimit(settings->GetUndoCount());
4842 
4843  // Text under tool button icon
4844  ToolBarStyles();
4845 
4846  isToolOptionsDockVisible = ui->toolProperties_DockWidget->isVisible();
4847  isGroupsDockVisible = ui->groups_DockWidget->isVisible();
4848  isLayoutsDockVisible = ui->layoutPages_DockWidget->isVisible();
4849  isToolboxDockVisible = ui->toolbox_DockWidget->isVisible();
4850 }
4851 
4852 //---------------------------------------------------------------------------------------------------------------------
4853 /**
4854  * @brief WriteSettings save setting for app.
4855  */
4857 {
4858  showDraftMode(true);
4859 
4860  VSettings *setings = qApp->Seamly2DSettings();
4861  setings->SetGeometry(saveGeometry());
4862  setings->SetWindowState(saveState());
4863  setings->SetToolbarsState(saveState(APP_VERSION));
4864 }
4865 
4866 //---------------------------------------------------------------------------------------------------------------------
4867 /**
4868  * @brief MaybeSave The function is called to save pending changes.
4869  * @return returns true in all cases, except when the user clicks Cancel.
4870  */
4872 {
4873  if (this->isWindowModified() && guiEnabled)
4874  {
4875  QScopedPointer<QMessageBox> messageBox(new QMessageBox(tr("Unsaved changes"),
4876  tr("The pattern has been modified.\n"
4877  "Do you want to save your changes?"),
4878  QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No,
4879  QMessageBox::Cancel, this, Qt::Sheet));
4880 
4881  messageBox->setDefaultButton(QMessageBox::Yes);
4882  messageBox->setEscapeButton(QMessageBox::Cancel);
4883 
4884  messageBox->setButtonText(QMessageBox::Yes,
4885  qApp->getFilePath().isEmpty() || patternReadOnly ? tr("Save...") : tr("Save"));
4886  messageBox->setButtonText(QMessageBox::No, tr("Don't Save"));
4887 
4888  messageBox->setWindowModality(Qt::ApplicationModal);
4889  const auto ret = static_cast<QMessageBox::StandardButton>(messageBox->exec());
4890 
4891  switch (ret)
4892  {
4893  case QMessageBox::Yes:
4894  if (patternReadOnly)
4895  {
4896  return SaveAs();
4897  }
4898  else
4899  {
4900  return Save();
4901  }
4902  case QMessageBox::No:
4903  return true;
4904  case QMessageBox::Cancel:
4905  return false;
4906  default:
4907  break;
4908  }
4909  }
4910  return true;
4911 }
4912 
4913 //---------------------------------------------------------------------------------------------------------------------
4915 {
4916  qCDebug(vMainWindow, "Updating recent file actions.");
4917  const QStringList files = qApp->Seamly2DSettings()->GetRecentFileList();
4918  const int numRecentFiles = qMin(files.size(), static_cast<int>(MaxRecentFiles));
4919 
4920  for (int i = 0; i < numRecentFiles; ++i)
4921  {
4922  QString text = QString("&%1. %2").arg(i + 1).arg(strippedName(files.at(i)));
4923  recentFileActs[i]->setText(text);
4924  recentFileActs[i]->setData(files.at(i));
4925  recentFileActs[i]->setVisible(true);
4926  }
4927  for (int j = numRecentFiles; j < MaxRecentFiles; ++j)
4928  {
4929  recentFileActs[j]->setVisible(false);
4930  }
4931 
4932  separatorAct->setVisible(numRecentFiles > 0);
4933 }
4934 
4935 //---------------------------------------------------------------------------------------------------------------------
4937 {
4938  //Add last 5 most recent projects to file menu.
4939  for (int i = 0; i < MaxRecentFiles; ++i)
4940  {
4941  ui->file_Menu->insertAction(ui->exit_Action, recentFileActs[i]);
4942  }
4943  separatorAct = new QAction(this);
4944  separatorAct->setSeparator(true);
4945  ui->file_Menu->insertAction(ui->exit_Action, separatorAct);
4947 
4948  //Add Undo/Redo actions to edit menu.
4949  QList<QKeySequence> undoShortcuts;
4950  undoShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Z));
4951  undoShortcuts.append(QKeySequence(Qt::AltModifier + Qt::Key_Backspace));
4952 
4953  undoAction = qApp->getUndoStack()->createUndoAction(this, tr("&Undo"));
4954  undoAction->setShortcuts(undoShortcuts);
4955  undoAction->setIcon(QIcon::fromTheme("edit-undo"));
4957  ui->edit_Menu->addAction(undoAction);
4958  ui->edit_Toolbar->addAction(undoAction);
4959 
4960  QList<QKeySequence> redoShortcuts;
4961  redoShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Y));
4962  redoShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::ShiftModifier + Qt::Key_Z));
4963  redoShortcuts.append(QKeySequence(Qt::AltModifier + Qt::ShiftModifier + Qt::Key_Backspace));
4964 
4965  redoAction = qApp->getUndoStack()->createRedoAction(this, tr("&Redo"));
4966  redoAction->setShortcuts(redoShortcuts);
4967  redoAction->setIcon(QIcon::fromTheme("edit-redo"));
4969  ui->edit_Menu->addAction(redoAction);
4970  ui->edit_Toolbar->addAction(redoAction);
4971 
4972  separatorAct = new QAction(this);
4973  separatorAct->setSeparator(true);
4974  ui->edit_Menu->addAction(separatorAct);
4975 
4976  AddDocks();
4977 
4978  separatorAct = new QAction(this);
4979  separatorAct->setSeparator(true);
4980  ui->view_Menu->addAction(separatorAct);
4981 
4982  QMenu *menu = new QMenu("Toolbars");
4983  ui->view_Menu->addMenu(menu);
4984 
4985  menu->addAction(ui->file_ToolBar->toggleViewAction());
4986  connect(ui->file_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
4987  {
4988  ui->file_ToolBar->setVisible(visible);
4989  });
4990  menu->addAction(ui->edit_Toolbar->toggleViewAction());
4991  connect(ui->edit_Toolbar, &QToolBar::visibilityChanged, this, [this](bool visible)
4992  {
4993  ui->edit_Toolbar->setVisible(visible);
4994  });
4995  menu->addAction(ui->view_ToolBar->toggleViewAction());
4996  connect(ui->view_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
4997  {
4998  ui->view_ToolBar->setVisible(visible);
4999  });
5000 
5001  menu->addAction(ui->mode_ToolBar->toggleViewAction());
5002  connect(ui->mode_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
5003  {
5004  ui->mode_ToolBar->setVisible(visible);
5005  });
5006  menu->addAction(ui->draft_ToolBar->toggleViewAction());
5007  connect(ui->draft_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
5008  {
5009  ui->draft_ToolBar->setVisible(visible);
5010  });
5011 
5012  menu->addAction(ui->zoom_ToolBar->toggleViewAction());
5013  connect(ui->zoom_ToolBar, &QToolBar::visibilityChanged, this, [this](bool visible)
5014  {
5015  ui->zoom_ToolBar->setVisible(visible);
5016  });
5017  menu->addAction(ui->tools_ToolBox_ToolBar->toggleViewAction());
5018  menu->addAction(ui->points_ToolBar->toggleViewAction());
5019  menu->addAction(ui->lines_ToolBar->toggleViewAction());
5020  menu->addAction(ui->curves_ToolBar->toggleViewAction());
5021  menu->addAction(ui->arcs_ToolBar->toggleViewAction());
5022  menu->addAction(ui->operations_ToolBar->toggleViewAction());
5023  menu->addAction(ui->pieces_ToolBar->toggleViewAction());
5024  menu->addAction(ui->details_ToolBar->toggleViewAction());
5025  menu->addAction(ui->layout_ToolBar->toggleViewAction());
5026  menu->addAction(ui->pointName_ToolBar->toggleViewAction());
5027 }
5028 
5029 //---------------------------------------------------------------------------------------------------------------------
5030 QT_WARNING_PUSH
5031 QT_WARNING_DISABLE_GCC("-Wswitch-default")
5032 void MainWindow::LastUsedTool()
5033 {
5034  // This check helps to find missed tools in the switch
5035  Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 53, "Not all tools were handled.");
5036 
5037  if (currentTool == lastUsedTool)
5038  {
5039  return;
5040  }
5041 
5042  switch ( lastUsedTool )
5043  {
5044  case Tool::Arrow:
5045  ui->arrowPointer_ToolButton->setChecked(true);
5046  ui->arrow_Action->setChecked(true);
5047  handleArrowTool(true);
5048  break;
5049  case Tool::BasePoint:
5050  case Tool::SinglePoint:
5051  case Tool::DoublePoint:
5052  case Tool::LinePoint:
5053  case Tool::AbstractSpline:
5054  case Tool::Cut:
5056  case Tool::NodePoint:
5057  case Tool::NodeArc:
5058  case Tool::NodeElArc:
5059  case Tool::NodeSpline:
5060  case Tool::NodeSplinePath:
5061  Q_UNREACHABLE(); //-V501
5062  //Nothing to do here because we can't create this tool from main window.
5063  break;
5064  case Tool::EndLine:
5065  ui->pointAtDistanceAngle_ToolButton->setChecked(true);
5066  handlePointAtDistanceAngleTool(true);
5067  break;
5068  case Tool::Line:
5069  ui->line_ToolButton->setChecked(true);
5070  handleLineTool(true);
5071  break;
5072  case Tool::AlongLine:
5073  ui->alongLine_ToolButton->setChecked(true);
5074  handleAlongLineTool(true);
5075  break;
5076  case Tool::Midpoint:
5077  ui->midpoint_ToolButton->setChecked(true);
5078  handleMidpointTool(true);
5079  break;
5080  case Tool::ShoulderPoint:
5081  ui->shoulderPoint_ToolButton->setChecked(true);
5082  handleShoulderPointTool(true);
5083  break;
5084  case Tool::Normal:
5085  ui->normal_ToolButton->setChecked(true);
5086  handleNormalTool(true);
5087  break;
5088  case Tool::Bisector:
5089  ui->bisector_ToolButton->setChecked(true);
5090  handleBisectorTool(true);
5091  break;
5092  case Tool::LineIntersect:
5093  ui->lineIntersect_ToolButton->setChecked(true);
5094  handleLineIntersectTool(true);
5095  break;
5096  case Tool::Spline:
5097  ui->curve_ToolButton->setChecked(true);
5098  handleCurveTool(true);
5099  break;
5100  case Tool::CubicBezier:
5101  ui->curveWithCPs_ToolButton->setChecked(true);
5102  handleCurveWithControlPointsTool(true);
5103  break;
5104  case Tool::Arc:
5105  ui->arc_ToolButton->setChecked(true);
5106  handleArcTool(true);
5107  break;
5108  case Tool::SplinePath:
5109  ui->spline_ToolButton->setChecked(true);
5110  handleSplineTool(true);
5111  break;
5112  case Tool::CubicBezierPath:
5113  ui->splineWithCPs_ToolButton->setChecked(true);
5114  handleSplineWithControlPointsTool(true);
5115  break;
5116  case Tool::PointOfContact:
5117  ui->pointOfContact_ToolButton->setChecked(true);
5118  handlePointOfContactTool(true);
5119  break;
5120  case Tool::Piece:
5121  ui->addPatternPiece_ToolButton->setChecked(true);
5122  handlePatternPieceTool(true);
5123  break;
5124  case Tool::InternalPath:
5125  ui->internalPath_ToolButton->setChecked(true);
5126  handleInternalPathTool(true);
5127  break;
5128  case Tool::Height:
5129  ui->height_ToolButton->setChecked(true);
5130  handleHeightTool(true);
5131  break;
5132  case Tool::Triangle:
5133  ui->triangle_ToolButton->setChecked(true);
5134  handleTriangleTool(true);
5135  break;
5137  ui->pointIntersectXY_ToolButton->setChecked(true);
5138  handlePointIntersectXYTool(true);
5139  break;
5141  ui->pointOfIntersectionArcs_ToolButton->setChecked(true);
5142  handlePointOfIntersectionArcsTool(true);
5143  break;
5144  case Tool::CutSpline:
5145  ui->pointAlongCurve_ToolButton->setChecked(true);
5146  handlePointAlongCurveTool(true);
5147  break;
5148  case Tool::CutSplinePath:
5149  ui->pointAlongSpline_ToolButton->setChecked(true);
5150  handlePointAlongSplineTool(true);
5151  break;
5152  case Tool::Union:
5153  ui->unitePieces_ToolButton->setChecked(true);
5154  handleUnionTool(true);
5155  break;
5156  case Tool::CutArc:
5157  ui->pointAlongArc_ToolButton->setChecked(true);
5158  handlePointAlongArcTool(true);
5159  break;
5161  ui->lineIntersectAxis_ToolButton->setChecked(true);
5162  handleLineIntersectAxisTool(true);
5163  break;
5165  ui->curveIntersectAxis_ToolButton->setChecked(true);
5166  handleCurveIntersectAxisTool(true);
5167  break;
5169  ui->arcIntersectAxis_ToolButton->setChecked(true);
5170  handleArcIntersectAxisTool(true);
5171  break;
5173  ui->pointOfIntersectionCircles_ToolButton->setChecked(true);
5174  handlePointOfIntersectionCirclesTool(true);
5175  break;
5177  ui->pointOfIntersectionCurves_ToolButton->setChecked(true);
5178  handleCurveIntersectCurveTool(true);
5179  break;
5181  ui->pointFromCircleAndTangent_ToolButton->setChecked(true);
5182  handlePointFromCircleAndTangentTool(true);
5183  break;
5185  ui->pointFromArcAndTangent_ToolButton->setChecked(true);
5186  handlePointFromArcAndTangentTool(true);
5187  break;
5188  case Tool::ArcWithLength:
5189  ui->arcWithLength_ToolButton->setChecked(true);
5190  handleArcWithLengthTool(true);
5191  break;
5192  case Tool::TrueDarts:
5193  ui->trueDarts_ToolButton->setChecked(true);
5194  handleTrueDartTool(true);
5195  break;
5196  case Tool::Group:
5197  ui->group_ToolButton->setChecked(true);
5198  handleGroupTool(true);
5199  break;
5200  case Tool::Rotation:
5201  ui->rotation_ToolButton->setChecked(true);
5202  handleRotationTool(true);
5203  break;
5204  case Tool::MirrorByLine:
5205  ui->mirrorByLine_ToolButton->setChecked(true);
5206  handleMirrorByLineTool(true);
5207  break;
5208  case Tool::MirrorByAxis:
5209  ui->mirrorByAxis_ToolButton->setChecked(true);
5210  handleMirrorByAxisTool(true);
5211  break;
5212  case Tool::Move:
5213  ui->move_ToolButton->setChecked(true);
5214  handleMoveTool(true);
5215  break;
5216  case Tool::EllipticalArc:
5217  ui->ellipticalArc_ToolButton->setChecked(true);
5218  handleEllipticalArcTool(true);
5219  break;
5220  case Tool::AnchorPoint:
5221  ui->anchorPoint_ToolButton->setChecked(true);
5222  handleAnchorPointTool(true);
5223  break;
5224  case Tool::InsertNodes:
5225  ui->insertNodes_ToolButton->setChecked(true);
5226  handleInsertNodesTool(true);
5227  break;
5228  }
5229 }
5230 
5232 
5233 //---------------------------------------------------------------------------------------------------------------------
5235 {
5236  //Add dock
5237  actionDockWidgetToolOptions = ui->toolProperties_DockWidget->toggleViewAction();
5238  ui->view_Menu->addAction(actionDockWidgetToolOptions);
5239  connect(ui->toolProperties_DockWidget, &QDockWidget::visibilityChanged, this, [this](bool visible)
5240  {
5241  isToolOptionsDockVisible = visible;
5242  });
5243 
5244  actionDockWidgetGroups = ui->groups_DockWidget->toggleViewAction();
5245  ui->view_Menu->addAction(actionDockWidgetGroups);
5246  connect(ui->groups_DockWidget, &QDockWidget::visibilityChanged, this, [this](bool visible)
5247  {
5248  isGroupsDockVisible = visible;
5249  });
5250 
5251  actionDockWidgetLayouts = ui->layoutPages_DockWidget->toggleViewAction();
5252  ui->view_Menu->addAction(actionDockWidgetLayouts);
5253  connect(ui->layoutPages_DockWidget, &QDockWidget::visibilityChanged, this, [this](bool visible)
5254  {
5255  isLayoutsDockVisible = visible;
5256  });
5257 
5258  actionDockWidgetToolbox = ui->toolbox_DockWidget->toggleViewAction();
5259  ui->view_Menu->addAction(actionDockWidgetToolbox);
5260  connect(ui->toolbox_DockWidget, &QDockWidget::visibilityChanged, this, [this](bool visible)
5261  {
5262  isToolboxDockVisible = visible;
5263  });
5264 }
5265 
5266 //---------------------------------------------------------------------------------------------------------------------
5268 {
5269  setTabPosition(Qt::RightDockWidgetArea, QTabWidget::West);
5270  setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::East);
5271 
5272  qCDebug(vMainWindow, "Initialize Tool Options Property editor.");
5273  toolProperties = new VToolOptionsPropertyBrowser(pattern, ui->toolProperties_DockWidget);
5274 
5277 
5278  qCDebug(vMainWindow, "Initialize Groups manager.");
5279  groupsWidget = new GroupsWidget(pattern, doc, this);
5280  ui->groups_DockWidget->setWidget(groupsWidget);
5282 
5288  patternPiecesWidget->setVisible(false);
5289 
5290  ui->toolbox_StackedWidget->setCurrentIndex(0);
5291 }
5292 
5293 //---------------------------------------------------------------------------------------------------------------------
5294 bool MainWindow::OpenNewSeamly2D(const QString &fileName) const
5295 {
5296  if (this->isWindowModified() || qApp->getFilePath().isEmpty() == false)
5297  {
5298  VApplication::NewSeamly2D(fileName);
5299  return true;
5300  }
5301  return false;
5302 }
5303 
5304 //---------------------------------------------------------------------------------------------------------------------
5306 {
5307  ui->setupUi(this);
5308 
5309  //Files menu
5310  connect(ui->actionNew, &QAction::triggered, this, &MainWindow::New);
5311  connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::Open);
5312  connect(ui->save_Action, &QAction::triggered, this, &MainWindow::Save);
5313  connect(ui->saveAs_Action, &QAction::triggered, this, &MainWindow::SaveAs);
5314  connect(ui->closePattern_Action, &QAction::triggered, this, [this]()
5315  {
5316  if (MaybeSave())
5317  {
5318  FileClosedCorrect();
5319  Clear();
5320  }
5321  });
5322 
5323  connect(ui->exportAs_Action, &QAction::triggered, this, &MainWindow::exportLayoutAs);
5324  connect(ui->printPreview_Action, &QAction::triggered, this, &MainWindow::PrintPreviewOrigin);
5325  connect(ui->printPreviewTiled_Action, &QAction::triggered, this, &MainWindow::PrintPreviewTiled);
5326  connect(ui->print_Action, &QAction::triggered, this, &MainWindow::PrintOrigin);
5327  connect(ui->printTiled_Action, &QAction::triggered, this, &MainWindow::PrintTiled);
5328 
5329  connect(ui->appPreferences_Action, &QAction::triggered, this, &MainWindow::Preferences);
5330  connect(ui->patternPreferences_Action, &QAction::triggered, this, [this]()
5331  {
5332  DialogPatternProperties proper(doc, pattern, this);
5333  connect(&proper, &DialogPatternProperties::UpdateGradation, this, [this]()
5334  {
5335  UpdateHeightsList(VMeasurement::ListHeights(doc->GetGradationHeights(), qApp->patternUnit()));
5336  UpdateSizesList(VMeasurement::ListSizes(doc->GetGradationSizes(), qApp->patternUnit()));
5337  });
5338  proper.exec();
5339  });
5340  ui->patternPreferences_Action->setEnabled(false);
5341 
5342  //Actions for recent files loaded by a main window application.
5343  for (int i = 0; i < MaxRecentFiles; ++i)
5344  {
5345  QAction *action = new QAction(this);
5346  action->setVisible(false);
5347  recentFileActs[i] = action;
5348  connect(recentFileActs[i], &QAction::triggered, this, [this]()
5349  {
5350  if (QAction *action = qobject_cast<QAction*>(sender()))
5351  {
5352  const QString filePath = action->data().toString();
5353  if (not filePath.isEmpty())
5354  {
5355  LoadPattern(filePath);
5356  }
5357  }
5358  });
5359  }
5360 
5361  connect(ui->documentInfo_Action, &QAction::triggered, this, [this]()
5362  {
5363  ShowInfoDialog *infoDialog = new ShowInfoDialog(doc, this);
5364  infoDialog->setAttribute(Qt::WA_DeleteOnClose, true);
5365  infoDialog->adjustSize();
5366  infoDialog->show();
5367  });
5368 
5369  connect(ui->exit_Action, &QAction::triggered, this, &MainWindow::close);
5370 
5371  //Edit Menu
5372  connect(ui->labelTemplateEditor_Action, &QAction::triggered, this, [this]()
5373  {
5374  EditLabelTemplateDialog editor(doc);
5375  editor.exec();
5376  });
5377 
5378  //View menu
5379  connect(ui->showDraftMode, &QAction::triggered, this, &MainWindow::showDraftMode);
5380  connect(ui->pieceMode_Action, &QAction::triggered, this, &MainWindow::showPieceMode);
5381  connect(ui->layoutMode_Action, &QAction::triggered, this, &MainWindow::showLayoutMode);
5382 
5383  connect(ui->toggleWireframe_Action, &QAction::triggered, this, [this](bool checked)
5384  {
5385  qApp->Seamly2DSettings()->setWireframe(checked);
5386  ui->view->itemClicked(nullptr);
5387  upDateScenes();
5388  });
5389 
5390  connect(ui->toggleControlPoints_Action, &QAction::triggered, this, [this](bool checked)
5391  {
5392  qApp->Seamly2DSettings()->setShowControlPoints(checked);
5393  ui->view->itemClicked(nullptr);
5394  draftScene->enablePiecesMode(checked);
5395  });
5396 
5397  connect(ui->toggleAxisOrigin_Action, &QAction::triggered, this, [this](bool checked)
5398  {
5399  qApp->Seamly2DSettings()->setShowAxisOrigin(checked);
5400  draftScene->setOriginsVisible(checked);
5401  pieceScene->setOriginsVisible(checked);
5402  });
5403 
5404  connect(ui->toggleSeamAllowances_Action, &QAction::triggered, this, [this](bool checked)
5405  {
5406  qApp->Seamly2DSettings()->setShowSeamAllowances(checked);
5407  ui->view->itemClicked(nullptr);
5408  refreshSeamAllowances();
5409  });
5410 
5411  connect(ui->toggleGrainLines_Action, &QAction::triggered, this, [this](bool checked)
5412  {
5413  qApp->Seamly2DSettings()->setShowGrainlines(checked);
5414  ui->view->itemClicked(nullptr);
5415  refreshGrainLines();
5416  });
5417 
5418  connect(ui->toggleLabels_Action, &QAction::triggered, this, [this](bool checked)
5419  {
5420  qApp->Seamly2DSettings()->setShowLabels(checked);
5421  ui->view->itemClicked(nullptr);
5422  refreshLabels();
5423  });
5424 /**
5425  connect(ui->toggleAnchorPoints_Action, &QAction::triggered, this, [this](bool checked)
5426  {
5427  qApp->Seamly2DSettings()->setShowAnchorPoints(checked);
5428  });
5429 **/
5430  connect(ui->increaseSize_Action, &QAction::triggered, this, [this]()
5431  {
5432  int index = qMin(fontSizeComboBox->currentIndex() + 1, fontSizeComboBox->count()-1);
5433  fontSizeComboBox->setCurrentIndex(index);
5434  qApp->Seamly2DSettings()->setPointNameSize(fontSizeComboBox->currentText().toInt());
5435  upDateScenes();
5436  });
5437 
5438  connect(ui->decreaseSize_Action, &QAction::triggered, this, [this]()
5439  {
5440  const int index = qMax(fontSizeComboBox->currentIndex() - 1, 0);
5441  fontSizeComboBox->setCurrentIndex(index);
5442  qApp->Seamly2DSettings()->setPointNameSize(fontSizeComboBox->currentText().toInt());
5443  upDateScenes();
5444  });
5445 
5446  connect(ui->showPointNames_Action, &QAction::triggered, this, [this](bool checked)
5447  {
5448  qApp->Seamly2DSettings()->setHidePointNames(checked);
5449  upDateScenes();
5450  });
5451 
5452  connect(ui->useToolColor_Action, &QAction::triggered, this, [this](bool checked)
5453  {
5454  qApp->Seamly2DSettings()->setUseToolColor(checked);
5455  upDateScenes();
5456  });
5457 
5458  //Tools menu
5459  connect(ui->newDraft_Action, &QAction::triggered, this, [this]()
5460  {
5461  qCDebug(vMainWindow, "New Draft Block.");
5462  QString draftBlockName = tr("Draft Block %1").arg(draftBlockComboBox->count()+1);
5463  qCDebug(vMainWindow, "Generated Draft Block name: %s", qUtf8Printable(draftBlockName));
5464 
5465  qCDebug(vMainWindow, "Draft Block count %d", draftBlockComboBox->count());
5466  draftBlockName = createDraftBlockName(draftBlockName);
5467  qCDebug(vMainWindow, "Draft Block name: %s", qUtf8Printable(draftBlockName));
5468  if (draftBlockName.isEmpty())
5469  {
5470  qCDebug(vMainWindow, "Draft Block name is empty.");
5471  return;
5472  }
5473 
5474  addDraftBlock(draftBlockName);
5475  });
5476 
5477  //Tools->Point submenu actions
5478  connect(ui->midpoint_Action, &QAction::triggered, this, [this]
5479  {
5480  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5481  ui->midpoint_ToolButton->setChecked(true);
5482  handleMidpointTool(true);
5483  });
5484  connect(ui->pointAtDistanceAngle_Action, &QAction::triggered, this, [this]
5485  {
5486  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5487  ui->pointAtDistanceAngle_ToolButton->setChecked(true);
5488  handlePointAtDistanceAngleTool(true);
5489  });
5490  connect(ui->pointAlongLine_Action, &QAction::triggered, this, [this]
5491  {
5492  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5493  ui->alongLine_ToolButton->setChecked(true);
5494  handleAlongLineTool(true);
5495  });
5496  connect(ui->pointAlongPerpendicular_Action, &QAction::triggered, this, [this]
5497  {
5498  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5499  ui->normal_ToolButton->setChecked(true);
5500  handleNormalTool(true);
5501  });
5502  connect(ui->bisector_Action, &QAction::triggered, this, [this]
5503  {
5504  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5505  ui->bisector_ToolButton->setChecked(true);
5506  handleBisectorTool(true);
5507  });
5508  connect(ui->pointOnShoulder_Action, &QAction::triggered, this, [this]
5509  {
5510  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5511  ui->shoulderPoint_ToolButton->setChecked(true);
5512  handleShoulderPointTool(true);
5513  });
5514  connect(ui->pointOfContact_Action, &QAction::triggered, this, [this]
5515  {
5516  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5517  ui->pointOfContact_ToolButton->setChecked(true);
5518  handlePointOfContactTool(true);
5519  });
5520  connect(ui->triangle_Action, &QAction::triggered, this, [this]
5521  {
5522  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5523  ui->triangle_ToolButton->setChecked(true);
5524  handleTriangleTool(true);
5525  });
5526  connect(ui->pointIntersectXY_Action, &QAction::triggered, this, [this]
5527  {
5528  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5529  ui->pointIntersectXY_ToolButton->setChecked(true);
5530  handlePointIntersectXYTool(true);
5531  });
5532  connect(ui->perpendicularPoint_Action, &QAction::triggered, this, [this]
5533  {
5534  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5535  ui->height_ToolButton->setChecked(true);
5536  handleHeightTool(true);
5537  });
5538  connect(ui->pointIntersectAxis_Action, &QAction::triggered, this, [this]
5539  {
5540  ui->draft_ToolBox->setCurrentWidget(ui->points_Page);
5541  ui->lineIntersectAxis_ToolButton->setChecked(true);
5542  handleLineIntersectAxisTool(true);
5543  });
5544 
5545  //Tools->Line submenu actions
5546  connect(ui->lineTool_Action, &QAction::triggered, this, [this]
5547  {
5548 
5549  ui->draft_ToolBox->setCurrentWidget(ui->lines_Page);
5550  ui->line_ToolButton->setChecked(true);
5551  handleLineTool(true);
5552  });
5553  connect(ui->lineIntersect_Action, &QAction::triggered, this, [this]
5554  {
5555  ui->draft_ToolBox->setCurrentWidget(ui->lines_Page);
5556  ui->lineIntersect_ToolButton->setChecked(true);
5557  handleLineIntersectTool(true);
5558  });
5559 
5560  //Tools->Curve submenu actions
5561  connect(ui->curve_Action, &QAction::triggered, this, [this]
5562  {
5563  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
5564  ui->curve_ToolButton->setChecked(true);
5565  handleCurveTool(true);
5566  });
5567  connect(ui->spline_Action, &QAction::triggered, this, [this]
5568  {
5569  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
5570  ui->spline_ToolButton->setChecked(true);
5571  handleSplineTool(true);
5572  });
5573  connect(ui->curveWithCPs_Action, &QAction::triggered, this, [this]
5574  {
5575  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
5576  ui->curveWithCPs_ToolButton->setChecked(true);
5577  handleCurveWithControlPointsTool(true);
5578  });
5579  connect(ui->splineWithCPs_Action, &QAction::triggered, this, [this]
5580  {
5581  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
5582  ui->splineWithCPs_ToolButton->setChecked(true);
5583  handleSplineWithControlPointsTool(true);
5584  });
5585  connect(ui->pointAlongCurve_Action, &QAction::triggered, this, [this]
5586  {
5587  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
5588  ui->pointAlongCurve_ToolButton->setChecked(true);
5589  handlePointAlongCurveTool(true);
5590  });
5591  connect(ui->pointAlongSpline_Action, &QAction::triggered, this, [this]
5592  {
5593  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
5594  ui->pointAlongSpline_ToolButton->setChecked(true);
5595  handlePointAlongSplineTool(true);
5596  });
5597  connect(ui->curveIntersectCurve_Action, &QAction::triggered, this, [this]
5598  {
5599  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
5600  ui->pointOfIntersectionCurves_ToolButton->setChecked(true);
5601  handleCurveIntersectCurveTool(true);
5602  });
5603  connect(ui->splineIntersectAxis_Action, &QAction::triggered, this, [this]
5604  {
5605  ui->draft_ToolBox->setCurrentWidget(ui->curves_Page);
5606  ui->curveIntersectAxis_ToolButton->setChecked(true);
5607  handleCurveIntersectAxisTool(true);
5608  });
5609 
5610  //Tools->Arc submenu actions
5611  connect(ui->arcTool_Action, &QAction::triggered, this, [this]
5612  {
5613  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5614  ui->arc_ToolButton->setChecked(true);
5615  handleArcTool(true);
5616  });
5617 
5618  connect(ui->pointAlongArc_Action, &QAction::triggered, this, [this]
5619  {
5620  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5621  ui->pointAlongArc_ToolButton->setChecked(true);
5622  handlePointAlongArcTool(true);
5623  });
5624 
5625  connect(ui->arcIntersectAxis_Action, &QAction::triggered, this, [this]
5626  {
5627  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5628  ui->arcIntersectAxis_ToolButton->setChecked(true);
5629  handleArcIntersectAxisTool(true);
5630  });
5631 
5632  connect(ui->arcIntersectArc_Action, &QAction::triggered, this, [this]
5633  {
5634  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5635  ui->pointOfIntersectionArcs_ToolButton->setChecked(true);
5636  handlePointOfIntersectionArcsTool(true);
5637  });
5638 
5639  connect(ui->circleIntersect_Action, &QAction::triggered, this, [this]
5640  {
5641  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5642  ui->pointOfIntersectionCircles_ToolButton->setChecked(true);
5643  handlePointOfIntersectionCirclesTool(true);
5644  });
5645 
5646  connect(ui->circleTangent_Action, &QAction::triggered, this, [this]
5647  {
5648  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5649  ui->pointFromCircleAndTangent_ToolButton->setChecked(true);
5650  handlePointFromCircleAndTangentTool(true);
5651  });
5652 
5653  connect(ui->arcTangent_Action, &QAction::triggered, this, [this]
5654  {
5655  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5656  ui->pointFromArcAndTangent_ToolButton->setChecked(true);
5657  handlePointFromArcAndTangentTool(true);
5658  });
5659 
5660  connect(ui->arcWithLength_Action, &QAction::triggered, this, [this]
5661  {
5662  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5663  ui->arcWithLength_ToolButton->setChecked(true);
5664  handleArcWithLengthTool(true);
5665  });
5666 
5667  connect(ui->ellipticalArc_Action, &QAction::triggered, this, [this]
5668  {
5669  ui->draft_ToolBox->setCurrentWidget(ui->arcs_Page);
5670  ui->ellipticalArc_ToolButton->setChecked(true);
5671  handleEllipticalArcTool(true);
5672  });
5673 
5674  //Tools->Operations submenu actions
5675  connect(ui->group_Action, &QAction::triggered, this, [this]
5676  {
5677  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
5678  ui->group_ToolButton->setChecked(true);
5679  handleGroupTool(true);
5680  });
5681 
5682  connect(ui->rotation_Action, &QAction::triggered, this, [this]
5683  {
5684  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
5685  ui->rotation_ToolButton->setChecked(true);
5686  handleRotationTool(true);
5687  });
5688 
5689  connect(ui->mirrorByLine_Action, &QAction::triggered, this, [this]
5690  {
5691  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
5692  ui->mirrorByLine_ToolButton->setChecked(true);
5693  handleMirrorByLineTool(true); });
5694  connect(ui->mirrorByAxis_Action, &QAction::triggered, this, [this]
5695  {
5696  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
5697  ui->mirrorByAxis_ToolButton->setChecked(true);
5698  handleMirrorByAxisTool(true);
5699  });
5700 
5701  connect(ui->move_Action, &QAction::triggered, this, [this]
5702  {
5703  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
5704  ui->move_ToolButton->setChecked(true);
5705  handleMoveTool(true);
5706  });
5707 
5708  connect(ui->trueDarts_Action, &QAction::triggered, this, [this]
5709  {
5710  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
5711  ui->trueDarts_ToolButton->setChecked(true);
5712  handleTrueDartTool(true);
5713  });
5714 
5715  connect(ui->exportDraftBlocks_Action, &QAction::triggered, this, [this]
5716  {
5717  ui->draft_ToolBox->setCurrentWidget(ui->operations_Page);
5718  exportDraftBlocksAs();
5719  });
5720 
5721  //Tools->Details submenu actions
5722  connect(ui->union_Action, &QAction::triggered, this, [this]
5723  {
5724  ui->piece_ToolBox->setCurrentWidget(ui->details_Page);
5725  ui->unitePieces_ToolButton->setChecked(true);
5726  handleUnionTool(true);
5727  });
5728 
5729  connect(ui->exportPieces_Action, &QAction::triggered, this, [this]
5730  {
5731  ui->piece_ToolBox->setCurrentWidget(ui->details_Page);
5732  exportPiecesAs();
5733  });
5734 
5735  //Tools->Piece submenu actions
5736  connect(ui->addPiece_Action, &QAction::triggered, this, [this]
5737  {
5738  ui->draft_ToolBox->setCurrentWidget(ui->piece_Page);
5739  ui->addPatternPiece_ToolButton->setChecked(true);
5740  handlePatternPieceTool(true);
5741  });
5742  connect(ui->anchorPoint_Action, &QAction::triggered, this, [this]
5743  {
5744  ui->draft_ToolBox->setCurrentWidget(ui->piece_Page);
5745  ui->anchorPoint_ToolButton->setChecked(true);
5746  handleAnchorPointTool(true);
5747  });
5748  connect(ui->internalPath_Action, &QAction::triggered, this, [this]
5749  {
5750  ui->draft_ToolBox->setCurrentWidget(ui->piece_Page);
5751  ui->internalPath_ToolButton->setChecked(true);
5752  handleInternalPathTool(true);
5753  });
5754  connect(ui->insertNodes_Action, &QAction::triggered, this, [this]
5755  {
5756  ui->draft_ToolBox->setCurrentWidget(ui->piece_Page);
5757  ui->insertNodes_ToolButton->setChecked(true);
5758  handleInsertNodesTool(true);
5759  });
5760 
5761  //Tools->Layout submenu actions
5762  connect(ui->newPrintLayout_Action, &QAction::triggered, this, [this]
5763  {
5764  ui->layout_ToolBox->setCurrentWidget(ui->layout_Page);
5765  ui->layoutSettings_ToolButton->setChecked(true);
5766  handleNewLayout(true);
5767  });
5768 
5769  connect(ui->exportLayout_Action, &QAction::triggered, this, [this]
5770  {
5771  ui->layout_ToolBox->setCurrentWidget(ui->layout_Page);
5772  exportLayoutAs();
5773  });
5774 
5775  connect(ui->lastTool_Action, &QAction::triggered, this, &MainWindow::LastUsedTool);
5776 
5777  //Measurements menu
5778  connect(ui->openSeamlyMe_Action, &QAction::triggered, this, [this]()
5779  {
5780  const QString seamlyme = qApp->SeamlyMeFilePath();
5781  const QString workingDirectory = QFileInfo(seamlyme).absoluteDir().absolutePath();
5782 
5783  QStringList arguments;
5784  if (isNoScaling)
5785  {
5786  arguments.append(QLatin1String("--") + LONG_OPTION_NO_HDPI_SCALING);
5787  }
5788 
5789  QProcess::startDetached(seamlyme, arguments, workingDirectory);
5790  });
5791 
5792  connect(ui->editCurrent_Action, &QAction::triggered, this, &MainWindow::ShowMeasurements);
5793  connect(ui->unloadMeasurements_Action, &QAction::triggered, this, &MainWindow::UnloadMeasurements);
5794  connect(ui->loadIndividual_Action, &QAction::triggered, this, &MainWindow::LoadIndividual);
5795  connect(ui->loadMultisize_Action, &QAction::triggered, this, &MainWindow::LoadMultisize);
5796  connect(ui->syncMeasurements_Action, &QAction::triggered, this, &MainWindow::SyncMeasurements);
5797  connect(ui->table_Action, &QAction::triggered, this, [this](bool checked)
5798  {
5799  if (checked)
5800  {
5801  dialogTable = new DialogVariables(pattern, doc, this);
5802  connect(dialogTable.data(), &DialogVariables::updateProperties, toolProperties,
5803  &VToolOptionsPropertyBrowser::refreshOptions);
5804  connect(dialogTable.data(), &DialogVariables::DialogClosed, this, [this]()
5805  {
5806  ui->table_Action->setChecked(false);
5807  if (dialogTable != nullptr)
5808  {
5809  delete dialogTable;
5810  }
5811  });
5812  dialogTable->show();
5813  }
5814  else
5815  {
5816  ui->table_Action->setChecked(true);
5817  dialogTable->activateWindow();
5818  }
5819  });
5820  connect(ui->exportVariablesToCSV_Action, &QAction::triggered, this, &MainWindow::handleExportToCSV);
5821 
5822  //History menu
5823  connect(ui->history_Action, &QAction::triggered, this, [this](bool checked)
5824  {
5825  if (checked)
5826  {
5827  historyDialog = new HistoryDialog(pattern, doc, this);
5828  connect(this, &MainWindow::RefreshHistory, historyDialog.data(), &HistoryDialog::updateHistory);
5829  connect(historyDialog.data(), &HistoryDialog::DialogClosed, this, [this]()
5830  {
5831  ui->history_Action->setChecked(false);
5832  if (historyDialog != nullptr)
5833  {
5834  delete historyDialog;
5835  }
5836  });
5837  historyDialog->show();
5838  }
5839  else
5840  {
5841  ui->history_Action->setChecked(true);
5842  historyDialog->activateWindow();
5843  }
5844  });
5845 
5846  //Utilities menu
5847  connect(ui->calculator_Action, &QAction::triggered, this, [this]()
5848  {
5849  CalculatorDialog *calcDialog = new CalculatorDialog(this);
5850  calcDialog->setAttribute(Qt::WA_DeleteOnClose, true);
5851  calcDialog->setWindowTitle(tr("Calculator"));
5852  calcDialog->adjustSize();
5853  calcDialog->show();
5854  });
5855 
5856  connect(ui->decimalChart_Action, &QAction::triggered, this, [this]()
5857  {
5858  DecimalChartDialog *decimalchartDialog = new DecimalChartDialog(this);
5859  decimalchartDialog->setAttribute(Qt::WA_DeleteOnClose, true);
5860  decimalchartDialog->show();
5861  });
5862 
5863  //Help menu
5864  connect(ui->shortcuts_Action, &QAction::triggered, this, [this]()
5865  {
5866  ShortcutsDialog *shortcutsDialog = new ShortcutsDialog(this);
5867  shortcutsDialog->setAttribute(Qt::WA_DeleteOnClose, true);
5868  shortcutsDialog->show();
5869  });
5870  connect(ui->wiki_Action, &QAction::triggered, this, []()
5871  {
5872  qCDebug(vMainWindow, "Showing online help");
5873  QDesktopServices::openUrl(QUrl(QStringLiteral("https://wiki.seamly.net/wiki/Main_Page")));
5874  });
5875 
5876  connect(ui->forum_Action, &QAction::triggered, this, []()
5877  {
5878  qCDebug(vMainWindow, "Opening forum");
5879  QDesktopServices::openUrl(QUrl(QStringLiteral("https://forum.seamly.net/")));
5880  });
5881 
5882  connect(ui->reportBug_Action, &QAction::triggered, this, []()
5883  {
5884  qCDebug(vMainWindow, "Reporting bug");
5885  QDesktopServices::openUrl(QUrl(QStringLiteral(
5886  "https://github.com/FashionFreedom/Seamly2D/issues/new?&labels=bug&template=bug_report.md&title=BUG%3A")));
5887  });
5888 
5889  connect(ui->aboutQt_Action, &QAction::triggered, this, [this]()
5890  {
5891  QMessageBox::aboutQt(this, tr("About Qt"));
5892  });
5893 
5894  connect(ui->aboutSeamly2D_Action, &QAction::triggered, this, [this]()
5895  {
5896  DialogAboutApp *aboutDialog = new DialogAboutApp(this);
5897  aboutDialog->setAttribute(Qt::WA_DeleteOnClose, true);
5898  aboutDialog->show();
5899  });
5900 
5901  //Toolbox toolbar
5902  connect(ui->arrow_Action, &QAction::triggered, this, &MainWindow::handleArrowTool);
5903  connect(ui->points_Action, &QAction::triggered, this, &MainWindow::handlePointsMenu);
5904  connect(ui->lines_Action, &QAction::triggered, this, &MainWindow::handleLinesMenu);
5905  connect(ui->arcs_Action, &QAction::triggered, this, &MainWindow::handleArcsMenu);
5906  connect(ui->curves_Action, &QAction::triggered, this, &MainWindow::handleCurvesMenu);
5907  connect(ui->modifications_Action, &QAction::triggered, this, &MainWindow::handleOperationsMenu);
5908  connect(ui->details_Action, &QAction::triggered, this, &MainWindow::handlePatternPiecesMenu);
5909  connect(ui->pieces_Action, &QAction::triggered, this, &MainWindow::handlePieceMenu);
5910  connect(ui->layout_Action, &QAction::triggered, this, &MainWindow::handleLayoutMenu);
5911 }
5912 
5913 //---------------------------------------------------------------------------------------------------------------------
5915 {
5916  //Autosaving file each 1 minutes
5917  delete autoSaveTimer;
5918  autoSaveTimer = nullptr;
5919 
5920  autoSaveTimer = new QTimer(this);
5921  autoSaveTimer->setTimerType(Qt::VeryCoarseTimer);
5922  connect(autoSaveTimer, &QTimer::timeout, this, &MainWindow::AutoSavePattern);
5923  autoSaveTimer->stop();
5924 
5925  if (qApp->Seamly2DSettings()->GetAutosaveState())
5926  {
5927  const qint32 autoTime = qApp->Seamly2DSettings()->getAutosaveInterval();
5928  autoSaveTimer->start(autoTime*60000);
5929  qCDebug(vMainWindow, "Autosaving every %d minutes.", autoTime);
5930  }
5931  qApp->setAutoSaveTimer(autoSaveTimer);
5932 }
5933 
5934 //---------------------------------------------------------------------------------------------------------------------
5935 QString MainWindow::createDraftBlockName(const QString &text)
5936 {
5937  QInputDialog *dialog = new QInputDialog(this);
5938  dialog->setInputMode( QInputDialog::TextInput );
5939  dialog->setLabelText(tr("Name:"));
5940  dialog->setTextEchoMode(QLineEdit::Normal);
5941  dialog->setWindowTitle(tr("Draft block."));
5942  dialog->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint
5943  & ~Qt::WindowMaximizeButtonHint
5944  & ~Qt::WindowMinimizeButtonHint);
5945  dialog->resize(300, 100);
5946  dialog->setTextValue(text);
5947  QString draftBlockName;
5948  while (1)
5949  {
5950  const bool result = dialog->exec();
5951  draftBlockName = dialog->textValue();
5952  if (result == false || draftBlockName.isEmpty())
5953  {
5954  delete dialog;
5955  return QString();
5956  }
5957  if (draftBlockComboBox->findText(draftBlockName) == -1)
5958  {
5959  break; //exit dialog
5960  }
5961  //repeat show dialog
5962  QMessageBox messageBox;
5963  messageBox.setWindowTitle(tr("Name Exists"));
5964  messageBox.setIcon(QMessageBox::Warning);
5965  messageBox.setStandardButtons(QMessageBox::Retry | QMessageBox::Cancel);
5966  messageBox.setDefaultButton(QMessageBox::Retry);
5967  messageBox.setText(tr("The action can't be completed because the Draft Block name already exists."));
5968  int boxResult = messageBox.exec();
5969 
5970  switch (boxResult)
5971  {
5972  case QMessageBox::Retry:
5973  break; // Repeat Dialog
5974  case QMessageBox::Cancel:
5975  return QString(); // Exit Dialog
5976  default:
5977  break; // should never be reached
5978  }
5979  }
5980  delete dialog;
5981  return draftBlockName;
5982 }
5983 
5984 //---------------------------------------------------------------------------------------------------------------------
5986 {
5987  CancelTool();
5988  CleanLayout();
5989 
5990  delete doc;
5991  delete ui;
5992 }
5993 
5994 //---------------------------------------------------------------------------------------------------------------------
5995 /**
5996  * @brief LoadPattern open pattern file.
5997  * @param fileName name of file.
5998  */
5999 bool MainWindow::LoadPattern(const QString &fileName, const QString& customMeasureFile)
6000 {
6001  qCDebug(vMainWindow, "Loading new file %s.", qUtf8Printable(fileName));
6002 
6003  //We have unsaved changes or load more then one file per time
6004  if (OpenNewSeamly2D(fileName))
6005  {
6006  return false;
6007  }
6008 
6009  if (fileName.isEmpty())
6010  {
6011  qCDebug(vMainWindow, "New loaded filename is empty.");
6012  Clear();
6013  return false;
6014  }
6015 
6016  try
6017  {
6018  // Here comes undocumented Seamly2D's feature.
6019  // Because app bundle in Mac OS X doesn't allow setup association for SeamlyMe we must do this through Seamly2D
6020  VMeasurements measurements(pattern);
6021  measurements.SetSize(VContainer::rsize());
6022  measurements.SetHeight(VContainer::rheight());
6023  measurements.setXMLContent(fileName);
6024 
6025  if (measurements.Type() == MeasurementsType::Multisize || measurements.Type() == MeasurementsType::Individual)
6026  {
6027  const QString seamlyme = qApp->SeamlyMeFilePath();
6028  const QString workingDirectory = QFileInfo(seamlyme).absoluteDir().absolutePath();
6029 
6030  QStringList arguments = QStringList() << fileName;
6031  if (isNoScaling)
6032  {
6033  arguments.append(QLatin1String("--") + LONG_OPTION_NO_HDPI_SCALING);
6034  }
6035 
6036  QProcess::startDetached(seamlyme, arguments, workingDirectory);
6037  qApp->exit(V_EX_OK);
6038  return false; // stop continue processing
6039  }
6040  }
6041  catch (VException &e)
6042  {
6043  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
6044  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
6045  Clear();
6046  if (not VApplication::IsGUIMode())
6047  {
6048  qApp->exit(V_EX_NOINPUT);
6049  }
6050  return false;
6051  }
6052 
6053  qCDebug(vMainWindow, "Locking file");
6054  VlpCreateLock(lock, fileName);
6055 
6056  if (lock->IsLocked())
6057  {
6058  qCDebug(vMainWindow, "Pattern file %s was locked.", qUtf8Printable(fileName));
6059  }
6060  else
6061  {
6062  if (not IgnoreLocking(lock->GetLockError(), fileName))
6063  {
6064  return false;
6065  }
6066  }
6067 
6068  // On this stage scene empty. Fit scene size to view size
6071 
6072  qApp->setOpeningPattern();//Begin opening file
6073  try
6074  {
6075  VPatternConverter converter(fileName);
6078  doc->setXMLContent(converter.Convert());
6079  if (!customMeasureFile.isEmpty())
6080  {
6081  doc->SetMPath(RelativeMPath(fileName, customMeasureFile));
6082  }
6083  qApp->setPatternUnit(doc->MUnit());
6084  const QString path = AbsoluteMPath(fileName, doc->MPath());
6085 
6086  if (not path.isEmpty())
6087  {
6088  // Check if exist
6089  const QString newPath = CheckPathToMeasurements(fileName, path);
6090  if (newPath.isEmpty())
6091  {
6092  qApp->setOpeningPattern();// End opening file
6093  Clear();
6094  qCCritical(vMainWindow, "%s", qUtf8Printable(tr("The measurements file '%1' could not be found.")
6095  .arg(path)));
6096  if (not VApplication::IsGUIMode())
6097  {
6098  qApp->exit(V_EX_NOINPUT);
6099  }
6100  return false;
6101  }
6102 
6103  if (not LoadMeasurements(newPath))
6104  {
6105  qCCritical(vMainWindow, "%s", qUtf8Printable(tr("The measurements file '%1' could not be found.")
6106  .arg(newPath)));
6107  qApp->setOpeningPattern();// End opening file
6108  Clear();
6109  if (not VApplication::IsGUIMode())
6110  {
6111  qApp->exit(V_EX_NOINPUT);
6112  }
6113  return false;
6114  }
6115  else
6116  {
6117  ui->unloadMeasurements_Action->setEnabled(true);
6118  watcher->addPath(path);
6119  ui->editCurrent_Action->setEnabled(true);
6120  }
6121  }
6122 
6123  if (qApp->patternType() == MeasurementsType::Unknown)
6124  {// Show toolbar only if was not uploaded any measurements.
6125  initStatusBar();
6126  }
6127  }
6128  catch (VException &e)
6129  {
6130  qCCritical(vMainWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
6131  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
6132  qApp->setOpeningPattern();// End opening file
6133  Clear();
6134  if (not VApplication::IsGUIMode())
6135  {
6136  qApp->exit(V_EX_NOINPUT);
6137  }
6138  return false;
6139  }
6140 
6141  FullParseFile();
6142 
6143  if (guiEnabled)
6144  { // No errors occurred
6146  SetEnableWidgets(true);
6147  setCurrentFile(fileName);
6148  helpLabel->setText(tr("File loaded"));
6149  qCDebug(vMainWindow, "File loaded.");
6150 
6151  //Fit scene size to best size for first show
6152  zoomFirstShow();
6154 
6155  showDraftMode(true);
6156 
6157  qApp->setOpeningPattern();// End opening file
6158  return true;
6159  }
6160  else
6161  {
6162  qApp->setOpeningPattern();// End opening file
6163  return false;
6164  }
6165 }
6166 
6167 //---------------------------------------------------------------------------------------------------------------------
6169 {
6170  QStringList restoreFiles;
6171  //Take all files that need to be restored
6172  QStringList files = qApp->Seamly2DSettings()->GetRestoreFileList();
6173  if (files.size() > 0)
6174  {
6175  for (int i = 0; i < files.size(); ++i)
6176  {
6177  // Seeking file that really needs reopen
6178  VLockGuard<char> tmp(files.at(i));
6179  if (tmp.IsLocked())
6180  {
6181  restoreFiles.append(files.at(i));
6182  }
6183  }
6184 
6185  // Clearing list after filtering
6186  for (int i = 0; i < restoreFiles.size(); ++i)
6187  {
6188  files.removeAll(restoreFiles.at(i));
6189  }
6190 
6191  // Clear all files that do not exist.
6192  QStringList filtered;
6193  for (int i = 0; i < files.size(); ++i)
6194  {
6195  if (QFileInfo(files.at(i)).exists())
6196  {
6197  filtered.append(files.at(i));
6198  }
6199  }
6200 
6201  qApp->Seamly2DSettings()->SetRestoreFileList(filtered);
6202  }
6203  return restoreFiles;
6204 }
6205 
6206 //---------------------------------------------------------------------------------------------------------------------
6208 {
6209  ToolBarStyle(ui->draft_ToolBar);
6210  ToolBarStyle(ui->mode_ToolBar);
6211  ToolBarStyle(ui->edit_Toolbar);
6212  ToolBarStyle(ui->zoom_ToolBar);
6213  ToolBarStyle(ui->file_ToolBar);
6214 
6215  fontComboBox->setCurrentFont(qApp->Seamly2DSettings()->getPointNameFont());
6216  int index = fontSizeComboBox->findData(qApp->Seamly2DSettings()->getPointNameSize());
6217  fontSizeComboBox->setCurrentIndex(index);
6218 }
6219 
6221 {
6226 }
6227 
6228 //---------------------------------------------------------------------------------------------------------------------
6230 {
6231  if (index < 0 || index >= scenes.size())
6232  {
6233  ui->view->setScene(tempSceneLayout);
6234  }
6235  else
6236  {
6237  ui->view->setScene(scenes.at(index));
6238  }
6239 
6240  ui->view->fitInView(ui->view->scene()->sceneRect(), Qt::KeepAspectRatio);
6241 }
6242 
6243 //---------------------------------------------------------------------------------------------------------------------
6245 {
6246  // Calling constructor of the dialog take some time. Because of this user have time to call the dialog twice.
6247  static QPointer<DialogPreferences> guard;// Prevent any second run
6248  if (guard.isNull())
6249  {
6250  QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
6251  DialogPreferences *preferences = new DialogPreferences(this);
6252  // QScopedPointer needs to be sure any exception will never block guard
6253  QScopedPointer<DialogPreferences> dialog(preferences);
6254  guard = preferences;
6255  connect(dialog.data(), &DialogPreferences::updateProperties, this, &MainWindow::WindowsLocale); // Must be first
6256  connect(dialog.data(), &DialogPreferences::updateProperties, this, &MainWindow::ToolBarStyles);
6258  connect(dialog.data(), &DialogPreferences::updateProperties, this, &MainWindow::refreshLabels);
6259  connect(dialog.data(), &DialogPreferences::updateProperties, this, &MainWindow::resetOrigins);
6260  connect(dialog.data(), &DialogPreferences::updateProperties, this, &MainWindow::upDateScenes);
6261  connect(dialog.data(), &DialogPreferences::updateProperties, this, &MainWindow::updateViewToolbar);
6262  connect(dialog.data(), &DialogPreferences::updateProperties, this, &MainWindow::resetPanShortcuts);
6263  connect(dialog.data(), &DialogPreferences::updateProperties, this, [this](){emit doc->FullUpdateFromFile();});
6264  connect(dialog.data(), &DialogPreferences::updateProperties,
6266 
6269 
6270 
6271  QGuiApplication::restoreOverrideCursor();
6272 
6273  if (guard->exec() == QDialog::Accepted)
6274  {
6275  InitAutoSave();
6276  }
6277  }
6278 }
6279 
6280 //---------------------------------------------------------------------------------------------------------------------
6281 #if defined(Q_OS_MAC)
6282 void MainWindow::CreateMeasurements()
6283 {
6284  const QString seamlyme = qApp->SeamlyMeFilePath();
6285  const QString workingDirectory = QFileInfo(seamlyme).absoluteDir().absolutePath();
6286 
6287  QStringList arguments;
6288  if (isNoScaling)
6289  {
6290  arguments.append(QLatin1String("--") + LONG_OPTION_NO_HDPI_SCALING);
6291  }
6292 
6293  QProcess::startDetached(seamlyme, arguments, workingDirectory);
6294 }
6295 #endif
6296 
6297 //---------------------------------------------------------------------------------------------------------------------
6299 {
6300  ui->exportLayout_ToolButton->setChecked(true);
6301 
6302  if (isLayoutStale)
6303  {
6304  if (ContinueIfLayoutStale() == QMessageBox::No)
6305  {
6306  ui->exportLayout_ToolButton->setChecked(false);
6307  return;
6308  }
6309  }
6310 
6311  try
6312  {
6313  ExportLayoutDialog dialog(scenes.size(), Draw::Layout, FileName(), this);
6314 
6315  if (dialog.exec() == QDialog::Rejected)
6316  {
6317  ui->exportLayout_ToolButton->setChecked(false);
6318  return;
6319  }
6320 
6321  ExportData(QVector<VLayoutPiece>(), dialog);
6322  }
6323  catch (const VException &e)
6324  {
6325  ui->exportLayout_ToolButton->setChecked(false);
6326  qCritical("%s\n\n%s\n\n%s", qUtf8Printable(tr("Export error.")),
6327  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
6328  return;
6329  }
6330  ui->exportLayout_ToolButton->setChecked(false);
6331 }
6332 
6333 //---------------------------------------------------------------------------------------------------------------------
6335 {
6336  ui->arrowPointer_ToolButton->setChecked(false);
6337  ui->arrow_Action->setChecked(false);
6338  ui->exportPiecesAs_ToolButton->setChecked(true);
6339 
6340  const QHash<quint32, VPiece> *allPieces = pattern->DataPieces();
6341  QHash<quint32, VPiece>::const_iterator i = allPieces->constBegin();
6342  QHash<quint32, VPiece> piecesInLayout;
6343  while (i != allPieces->constEnd())
6344  {
6345  if (i.value().isInLayout())
6346  {
6347  piecesInLayout.insert(i.key(), i.value());
6348  }
6349  ++i;
6350  }
6351 
6352  if (piecesInLayout.count() == 0)
6353  {
6354  QMessageBox::information(this, tr("Layout mode"), tr("You don't have any pieces to export. Please, "
6355  "include at least one piece in layout."),
6356  QMessageBox::Ok, QMessageBox::Ok);
6357  return;
6358  }
6359 
6361  try
6362  {
6363  pieceList = preparePiecesForLayout(piecesInLayout);
6364  }
6365  catch (VException &e)
6366  {
6367  QMessageBox::warning(this, tr("Export pieces"),
6368  tr("Can't export pieces.") + QLatin1String(" \n") + e.ErrorMessage(),
6369  QMessageBox::Ok, QMessageBox::Ok);
6370  return;
6371  }
6372 
6373  try
6374  {
6375  ExportLayoutDialog dialog(1, Draw::Modeling, FileName(), this);
6376  dialog.setWindowTitle("Export Pattern Pieces");
6377 
6378  if (dialog.exec() == QDialog::Rejected)
6379  {
6380  ui->exportPiecesAs_ToolButton->setChecked(false);
6381  return;
6382  }
6383 
6384  ExportData(pieceList, dialog);
6385  }
6386  catch (const VException &e)
6387  {
6388  ui->exportPiecesAs_ToolButton->setChecked(false);
6389  qCritical("%s\n\n%s\n\n%s", qUtf8Printable(tr("Export error.")),
6390  qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
6391  return;
6392  }
6393 
6394  ui->arrowPointer_ToolButton->setChecked(true);
6395  ui->arrow_Action->setChecked(true);
6396  ui->exportPiecesAs_ToolButton->setChecked(false);
6397 }
6398 
6399 //---------------------------------------------------------------------------------------------------------------------
6401 {
6402  //select export tool button
6403  ui->arrowPointer_ToolButton->setChecked(false);
6404  ui->arrow_Action->setChecked(false);
6405  ui->exportDraftBlocks_ToolButton->setChecked(true);
6406 
6407  //Get view info so we can restore after export
6408  int vScrollBar = ui->view->verticalScrollBar()->value();
6409  int hScrollBar = ui->view->horizontalScrollBar()->value();
6410  QTransform viewTransform = ui->view->transform();
6411 
6412  //Include all items in draft scene
6413  ui->view->zoomToFit();
6414  ui->view->repaint();
6415  ui->view->zoom100Percent();
6416 
6417  // Enable all draft blocks in the scene
6418  const QList<QGraphicsItem *> items = draftScene->items();
6419  for (auto *item : items)
6420  {
6421  item->setEnabled(true);
6422  }
6423  ui->view->repaint();
6424 
6425  draftScene->setOriginsVisible(false);
6426 
6427  //Open a file dialog to save export
6428  ExportLayoutDialog dialog(1, Draw::Calculation, FileName(), this);
6429  dialog.setWindowTitle("Export Draft Blocks");
6430 
6431  if (dialog.exec() == QDialog::Accepted)
6432  {
6433  const QString filename = QString("%1/%2%3")
6434  .arg(dialog.path()) //1
6435  .arg(dialog.fileName()) //2
6436  .arg(ExportLayoutDialog::exportFormatSuffix(dialog.format())); //3
6437 
6438  QRectF rect;
6439  rect = draftScene->itemsBoundingRect();
6440  draftScene->update(rect);
6441  QGraphicsRectItem *paper = new QGraphicsRectItem(rect);
6442  QMarginsF margins = QMarginsF(0, 0, 0, 0);
6443 
6444  switch(dialog.format())
6445  {
6447  {
6448  exportSVG(filename, paper, draftScene);
6449  break;
6450  }
6452  {
6453  exportPNG(filename, draftScene);
6454  break;
6455  }
6457  {
6458  exportJPG(filename, draftScene);
6459  break;
6460  }
6462  {
6463  exportBMP(filename, draftScene);
6464  break;
6465  }
6467  {
6468  exportTIF(filename, draftScene);
6469  break;
6470  }
6472  {
6473  exportPPM(filename, draftScene);
6474  break;
6475  }
6477  {
6478  exportPDF(filename, paper, draftScene, true, margins);
6479  break;
6480  }
6484  {
6485  exportPS(filename, paper, draftScene, true, margins);
6486  break;
6487  }
6489  {
6490  exportEPS(filename, paper, draftScene, true, margins);
6491  break;
6492  }
6520  default:
6521  break;
6522  }
6523  }
6524 
6525  // Disable draft blocks in the scenee except current block
6527 
6528  draftScene->setOriginsVisible(qApp->Settings()->getShowAxisOrigin());
6529 
6530  // Restore scale, scrollbars, current active draft block
6531  ui->view->setTransform(viewTransform);
6532  VMainGraphicsView::NewSceneRect(ui->view->scene(), ui->view);
6533  zoomScaleChanged(ui->view->transform().m11());
6534 
6535  ui->view->verticalScrollBar()->setValue(vScrollBar);
6536  ui->view->horizontalScrollBar()->setValue(hScrollBar);
6537 
6538  //reset tool buttons
6539  ui->arrowPointer_ToolButton->setChecked(true);
6540  ui->arrow_Action->setChecked(true);
6541  ui->exportDraftBlocks_ToolButton->setChecked(false);
6542 }
6543 
6544 //---------------------------------------------------------------------------------------------------------------------
6545 void MainWindow::ReopenFilesAfterCrash(QStringList &args)
6546 {
6547  const QStringList files = GetUnlokedRestoreFileList();
6548  if (files.size() > 0)
6549  {
6550  qCDebug(vMainWindow, "Reopen files after crash.");
6551 
6552  QStringList restoreFiles;
6553  for (int i = 0; i < files.size(); ++i)
6554  {
6555  QFile file(files.at(i) + autosavePrefix);
6556  if (file.exists())
6557  {
6558  restoreFiles.append(files.at(i));
6559  }
6560  }
6561 
6562  if (restoreFiles.size() > 0)
6563  {
6564  QMessageBox::StandardButton reply;
6565  const QString mes = tr("Seamly2D didn't shut down correctly. Do you want reopen files (%1) you had open?")
6566  .arg(restoreFiles.size());
6567  reply = QMessageBox::question(this, tr("Reopen files."), mes, QMessageBox::Yes|QMessageBox::No,
6568  QMessageBox::Yes);
6569  if (reply == QMessageBox::Yes)
6570  {
6571  qCDebug(vMainWindow, "User said Yes.");
6572 
6573  for (int i = 0; i < restoreFiles.size(); ++i)
6574  {
6575  QString error;
6576  if (VDomDocument::SafeCopy(restoreFiles.at(i) + autosavePrefix, restoreFiles.at(i), error))
6577  {
6578  QFile autoFile(restoreFiles.at(i) + autosavePrefix);
6579  autoFile.remove();
6580  LoadPattern(restoreFiles.at(i));
6581  args.removeAll(restoreFiles.at(i));// Do not open file twice after we restore him.
6582  }
6583  else
6584  {
6585  qCDebug(vMainWindow, "Could not copy %s%s to %s %s",
6586  qUtf8Printable(restoreFiles.at(i)), qUtf8Printable(autosavePrefix),
6587  qUtf8Printable(restoreFiles.at(i)), qUtf8Printable(error));
6588  }
6589  }
6590  }
6591  }
6592  }
6593 }
6594 
6595 //---------------------------------------------------------------------------------------------------------------------
6596 QString MainWindow::CheckPathToMeasurements(const QString &patternPath, const QString &path)
6597 {
6598  if (path.isEmpty())
6599  {
6600  return path;
6601  }
6602 
6603  QFileInfo table(path);
6604  if (table.exists() == false)
6605  {
6606  if (!VApplication::IsGUIMode())
6607  {
6608  return QString();// console mode doesn't support fixing path to a measurement file
6609  }
6610  else
6611  {
6612  const QString text = tr("The measurements file <br/><br/> <b>%1</b> <br/><br/> could not be found. Do you "
6613  "want to update the file location?").arg(path);
6614  QMessageBox::StandardButton res = QMessageBox::question(this, tr("Loading measurements file"), text,
6615  QMessageBox::Yes | QMessageBox::No,
6616  QMessageBox::Yes);
6617  if (res == QMessageBox::No)
6618  {
6619  return QString();
6620  }
6621  else
6622  {
6623  MeasurementsType patternType;
6624  if (table.suffix() == QLatin1String("vst"))
6625  {
6626  patternType = MeasurementsType::Multisize;
6627  }
6628  else if (table.suffix() == QLatin1String("vit"))
6629  {
6630  patternType = MeasurementsType::Individual;
6631  }
6632  else
6633  {
6634  patternType = MeasurementsType::Unknown;
6635  }
6636 
6637  QString mPath;
6638  if (patternType == MeasurementsType::Multisize)
6639  {
6640  const QString filter = tr("Multisize measurements") + QLatin1String(" (*.vst)");
6641  //Use standard path to multisize measurements
6642  QString path = qApp->Seamly2DSettings()->GetPathMultisizeMeasurements();
6644  mPath = QFileDialog::getOpenFileName(this, tr("Open file"), path, filter, nullptr,
6645  QFileDialog::DontUseNativeDialog);
6646  }
6647  else if (patternType == MeasurementsType::Individual)
6648  {
6649  const QString filter = tr("Individual measurements") + QLatin1String(" (*.vit)");
6650  //Use standard path to individual measurements
6651  const QString path = qApp->Seamly2DSettings()->GetPathIndividualMeasurements();
6652 
6653  bool usedNotExistedDir = false;
6654  QDir directory(path);
6655  if (not directory.exists())
6656  {
6657  usedNotExistedDir = directory.mkpath(".");
6658  }
6659 
6660  mPath = QFileDialog::getOpenFileName(this, tr("Open file"), path, filter, nullptr,
6661  QFileDialog::DontUseNativeDialog);
6662 
6663  if (usedNotExistedDir)
6664  {
6665  QDir directory(path);
6666  directory.rmpath(".");
6667  }
6668  }
6669  else
6670  {
6671  const QString filter = tr("Individual measurements") + QLatin1String(" (*.vit);;") +
6672  tr("Multisize measurements") + QLatin1String(" (*.vst)");
6673  //Use standard path to individual measurements
6674  const QString path = qApp->Seamly2DSettings()->GetPathIndividualMeasurements();
6676 
6677  bool usedNotExistedDir = false;
6678  QDir directory(path);
6679  if (not directory.exists())
6680  {
6681  usedNotExistedDir = directory.mkpath(".");
6682  }
6683 
6684  mPath = QFileDialog::getOpenFileName(this, tr("Open file"), path, filter, nullptr,
6685  QFileDialog::DontUseNativeDialog);
6686 
6687  if (usedNotExistedDir)
6688  {
6689  QDir directory(path);
6690  directory.rmpath(".");
6691  }
6692  }
6693 
6694  if (mPath.isEmpty())
6695  {
6696  return mPath;
6697  }
6698  else
6699  {
6700  QScopedPointer<VMeasurements> measurements(new VMeasurements(pattern));
6701  measurements->SetSize(VContainer::rsize());
6702  measurements->SetHeight(VContainer::rheight());
6703  measurements->setXMLContent(mPath);
6704 
6705  patternType = measurements->Type();
6706 
6707  if (patternType == MeasurementsType::Unknown)
6708  {
6709  VException e(tr("Measurement file has unknown format."));
6710  throw e;
6711  }
6712 
6713  if (patternType == MeasurementsType::Multisize)
6714  {
6715  VVSTConverter converter(mPath);
6716  measurements->setXMLContent(converter.Convert());// Read again after conversion
6717  }
6718  else
6719  {
6720  VVITConverter converter(mPath);
6721  measurements->setXMLContent(converter.Convert());// Read again after conversion
6722  }
6723 
6724  if (not measurements->IsDefinedKnownNamesValid())
6725  {
6726  VException e(tr("Measurement file contains invalid known measurement(s)."));
6727  throw e;
6728  }
6729 
6730  CheckRequiredMeasurements(measurements.data());
6731 
6732  qApp->setPatternType(patternType);
6733  doc->SetMPath(RelativeMPath(patternPath, mPath));
6734  PatternChangesWereSaved(false);
6735  return mPath;
6736  }
6737  }
6738  }
6739  }
6740  return path;
6741 }
6742 
6743 //---------------------------------------------------------------------------------------------------------------------
6744 void MainWindow::changeDraftBlock(int index, bool zoomBestFit)
6745 {
6746  if (index != -1)
6747  {
6748  doc->changeActiveDraftBlock(draftBlockComboBox->itemText(index));
6749  doc->setCurrentData();
6750  emit RefreshHistory();
6751  if (drawMode)
6752  {
6753  handleArrowTool(true);
6754  if (zoomBestFit)
6755  {
6756  zoomToSelected();
6757  }
6758  }
6759  toolProperties->itemClicked(nullptr);//hide options for tool in previous pattern piece
6761  }
6762 }
6763 
6764 //---------------------------------------------------------------------------------------------------------------------
6766 {
6767  if (not dialogTool.isNull())
6768  {
6769  dialogTool->ShowDialog(click);
6770  }
6771 }
6772 
6773 //---------------------------------------------------------------------------------------------------------------------
6774 /**
6775  * @brief zoomFirstShow Fit scene size to best size for first show
6776  */
6778 {
6779  /* If don't call zoomToFit() twice, after first scaling or moving pattern piece, scene change coordinate and whole
6780  * pattern will be moved. Looks very ugly. It is best solution that i have now.
6781  */
6782  if (pattern->DataPieces()->size() > 0)
6783  {
6784  showPieceMode(true);
6785  ui->view->zoomToFit();
6786  }
6787  if (not ui->showDraftMode->isChecked())
6788  {
6789  showDraftMode(true);
6790  }
6791  zoomToSelected();
6792 
6795 
6796  if (pattern->DataPieces()->size() > 0)
6797  {
6798  showPieceMode(true);
6799  ui->view->zoomToFit();
6800  }
6801 
6802  if (not ui->showDraftMode->isChecked())
6803  {
6804  showDraftMode(true);
6805  }
6806 }
6807 
6808 //---------------------------------------------------------------------------------------------------------------------
6810 {
6812  if(not qApp->getOpeningPattern())
6813  {
6814  if (pieces->count() == 0)
6815  {
6816  qCCritical(vMainWindow, "%s", qUtf8Printable(tr("You can't export empty scene.")));
6817  qApp->exit(V_EX_DATAERR);
6818  return;
6819  }
6820  }
6822 
6823  const bool exportOnlyPieces = expParams->exportOnlyPieces();
6824  if (exportOnlyPieces)
6825  {
6826  try
6827  {
6828  ExportLayoutDialog dialog(1, Draw::Modeling, expParams->OptBaseName(), this);
6829  dialog.setDestinationPath(expParams->OptDestinationPath());
6830  dialog.selectFormat(static_cast<LayoutExportFormat>(expParams->OptExportType()));
6831  dialog.setBinaryDXFFormat(expParams->IsBinaryDXF());
6832  dialog.setTextAsPaths(expParams->isTextAsPaths());
6833 
6834  ExportData(pieceList, dialog);
6835  }
6836  catch (const VException &e)
6837  {
6838  qCCritical(vMainWindow, "%s\n\n%s", qUtf8Printable(tr("Export error.")), qUtf8Printable(e.ErrorMessage()));
6839  qApp->exit(V_EX_DATAERR);
6840  return;
6841  }
6842  }
6843  else
6844  {
6845  auto settings = expParams->DefaultGenerator();
6846  settings->SetTestAsPaths(expParams->isTextAsPaths());
6847 
6848  if (LayoutSettings(*settings.get()))
6849  {
6850  try
6851  {
6852  ExportLayoutDialog dialog(scenes.size(), Draw::Layout, expParams->OptBaseName(), this);
6853  dialog.setDestinationPath(expParams->OptDestinationPath());
6854  dialog.selectFormat(static_cast<LayoutExportFormat>(expParams->OptExportType()));
6855  dialog.setBinaryDXFFormat(expParams->IsBinaryDXF());
6856 
6857  ExportData(pieceList, dialog);
6858  }
6859  catch (const VException &e)
6860  {
6861  qCCritical(vMainWindow, "%s\n\n%s", qUtf8Printable(tr("Export error.")), qUtf8Printable(e.ErrorMessage()));
6862  qApp->exit(V_EX_DATAERR);
6863  return;
6864  }
6865  }
6866  else
6867  {
6868  return;
6869  }
6870  }
6871 
6872  qApp->exit(V_EX_OK);
6873 }
6874 
6875 //---------------------------------------------------------------------------------------------------------------------
6876 bool MainWindow::SetSize(const QString &text)
6877 {
6878  if (not VApplication::IsGUIMode())
6879  {
6880  if (this->isWindowModified() || not qApp->getFilePath().isEmpty())
6881  {
6882  if (qApp->patternType() == MeasurementsType::Multisize)
6883  {
6884  const int size = static_cast<int>(UnitConvertor(text.toInt(), Unit::Cm, *pattern->GetPatternUnit()));
6885  const qint32 index = gradationSizes->findText(QString().setNum(size));
6886  if (index != -1)
6887  {
6888  gradationSizes->setCurrentIndex(index);
6889  }
6890  else
6891  {
6892  qCCritical(vMainWindow, "%s",
6893  qUtf8Printable(tr("Not supported size value '%1' for this pattern file.").arg(text)));
6894  return false;
6895  }
6896  }
6897  else
6898  {
6899  qCCritical(vMainWindow, "%s",
6900  qUtf8Printable(tr("Couldn't set size. Need a file with multisize measurements.")));
6901  return false;
6902  }
6903  }
6904  else
6905  {
6906  qCCritical(vMainWindow, "%s", qUtf8Printable(tr("Couldn't set size. File wasn't opened.")));
6907  return false;
6908  }
6909  }
6910  else
6911  {
6912  qCWarning(vMainWindow, "%s", qUtf8Printable(tr("The method %1 does nothing in GUI mode").arg(Q_FUNC_INFO)));
6913  return false;
6914  }
6915  return true;
6916 }
6917 
6918 //---------------------------------------------------------------------------------------------------------------------
6919 bool MainWindow::SetHeight(const QString &text)
6920 {
6921  if (not VApplication::IsGUIMode())
6922  {
6923  if (this->isWindowModified() || not qApp->getFilePath().isEmpty())
6924  {
6925  if (qApp->patternType() == MeasurementsType::Multisize)
6926  {
6927  const int height = static_cast<int>(UnitConvertor(text.toInt(), Unit::Cm, *pattern->GetPatternUnit()));
6928  const qint32 index = gradationHeights->findText(QString().setNum(height));
6929  if (index != -1)
6930  {
6931  gradationHeights->setCurrentIndex(index);
6932  }
6933  else
6934  {
6935  qCCritical(vMainWindow, "%s",
6936  qUtf8Printable(tr("Not supported height value '%1' for this pattern file.").arg(text)));
6937  return false;
6938  }
6939  }
6940  else
6941  {
6942  qCCritical(vMainWindow, "%s",
6943  qUtf8Printable(tr("Couldn't set height. Need a file with multisize measurements.")));
6944  return false;
6945  }
6946  }
6947  else
6948  {
6949  qCCritical(vMainWindow, "%s", qUtf8Printable(tr("Couldn't set height. File wasn't opened.")));
6950  return false;
6951  }
6952  }
6953  else
6954  {
6955  qCWarning(vMainWindow, "%s", qUtf8Printable(tr("The method %1 does nothing in GUI mode").arg(Q_FUNC_INFO)));
6956  return false;
6957  }
6958  return true;
6959 }
6960 
6961 //---------------------------------------------------------------------------------------------------------------------
6963 {
6964  const VCommandLinePtr cmd = qApp->CommandLine();
6965  auto args = cmd->OptInputFileNames();
6966 
6967  isNoScaling = cmd->IsNoScalingEnabled();
6968 
6970  {
6971  ReopenFilesAfterCrash(args);
6972  }
6973  else
6974  {
6975  if (args.size() != 1)
6976  {
6977  qCritical() << tr("Please, provide one input file.");
6978  qApp->exit(V_EX_NOINPUT);
6979  return;
6980  }
6981  }
6982 
6983  for (int i=0, sz = args.size(); i < sz; ++i)
6984  {
6985  const bool loaded = LoadPattern(args.at(static_cast<int>(i)), cmd->OptMeasurePath());
6986 
6987  if (not loaded && not VApplication::IsGUIMode())
6988  {
6989  return; // process only one input file
6990  }
6991 
6992  bool hSetted = true;
6993  bool sSetted = true;
6994  if (loaded && (cmd->IsTestModeEnabled() || cmd->IsExportEnabled()))
6995  {
6996  if (cmd->IsSetGradationSize())
6997  {
6998  sSetted = SetSize(cmd->OptGradationSize());
6999  }
7000 
7001  if (cmd->IsSetGradationHeight())
7002  {
7003  hSetted = SetHeight(cmd->OptGradationHeight());
7004  }
7005  }
7006 
7007  if (not cmd->IsTestModeEnabled())
7008  {
7009  if (cmd->IsExportEnabled())
7010  {
7011  if (loaded && hSetted && sSetted)
7012  {
7013  DoExport(cmd);
7014  return; // process only one input file
7015  }
7016  else
7017  {
7018  qApp->exit(V_EX_DATAERR);
7019  return;
7020  }
7021  break;
7022  }
7023  }
7024  }
7025 
7026  if (not VApplication::IsGUIMode())
7027  {
7028  qApp->exit(V_EX_OK);// close program after processing in console mode
7029  }
7030 }
7031 
7032 //---------------------------------------------------------------------------------------------------------------------
7034 {
7035  QString shownName = tr("untitled.val");
7036  if(not qApp->getFilePath().isEmpty())
7037  {
7038  shownName = qApp->getFilePath();
7039  }
7040  shownName += QLatin1String("[*]");
7041  return shownName;
7042 }
7043 
7044 //---------------------------------------------------------------------------------------------------------------------
7046 {
7047  if(doc->MPath().isEmpty())
7048  {
7049  return "";
7050  }
7051  else
7052  {
7053  QString shownName(" - [");
7054  shownName += strippedName(AbsoluteMPath(qApp->getFilePath(), doc->MPath()));
7055 
7056  if(mChanges)
7057  {
7058  shownName += QLatin1String("*");
7059  }
7060 
7061  shownName += QLatin1String("]");
7062  return shownName;
7063  }
7064 }
7065 
7066 //---------------------------------------------------------------------------------------------------------------------
7068 {
7069  bool isFileWritable = true;
7070  if (!qApp->getFilePath().isEmpty())
7071  {
7072 #ifdef Q_OS_WIN32
7073  qt_ntfs_permission_lookup++; // turn checking on
7074 #endif /*Q_OS_WIN32*/
7075  isFileWritable = QFileInfo(qApp->getFilePath()).isWritable();
7076 #ifdef Q_OS_WIN32
7077  qt_ntfs_permission_lookup--; // turn it off again
7078 #endif /*Q_OS_WIN32*/
7079  }
7080 
7081  if (!patternReadOnly && isFileWritable)
7082  {
7083  setWindowTitle(VER_INTERNALNAME_STR + QString(" - ") + GetPatternFileName() + GetMeasurementFileName());
7084  }
7085  else
7086  {
7087  setWindowTitle(VER_INTERNALNAME_STR + QString(" - ") + GetPatternFileName() +
7088  GetMeasurementFileName() + QString(" - ") + tr("read only"));
7089  }
7090  setWindowFilePath(qApp->getFilePath());
7091 
7092 #if defined(Q_OS_MAC)
7093  static QIcon fileIcon = QIcon(QCoreApplication::applicationDirPath() +
7094  QLatin1String("/../Resources/Seamly2D.icns"));
7095  QIcon icon;
7096  if (!qApp->getFilePath().isEmpty())
7097  {
7098  if (!isWindowModified())
7099  {
7100  icon = fileIcon;
7101  }
7102  else
7103  {
7104  static QIcon darkIcon;
7105 
7106  if (darkIcon.isNull())
7107  {
7108  darkIcon = QIcon(darkenPixmap(fileIcon.pixmap(16, 16)));
7109  }
7110  icon = darkIcon;
7111  }
7112  }
7113  setWindowIcon(icon);
7114 #endif //defined(Q_OS_MAC)
7115 }
7116 
7118 {
7119  if (draftScene)
7120  {
7121  draftScene->update();
7122  }
7123 
7124  if (pieceScene)
7125  {
7126  pieceScene->update();
7127  }
7128 }
7129 
7131 {
7132  ui->toggleWireframe_Action->setChecked(qApp->Settings()->isWireframe());
7133  ui->toggleControlPoints_Action->setChecked(qApp->Settings()->getShowControlPoints());
7134  ui->toggleAxisOrigin_Action->setChecked(qApp->Settings()->getShowAxisOrigin());
7135  ui->toggleGrainLines_Action->setChecked(qApp->Settings()->showGrainlines());
7136  ui->toggleSeamAllowances_Action->setChecked(qApp->Settings()->showSeamAllowances());
7137  ui->toggleLabels_Action->setChecked(qApp->Settings()->showLabels());
7138 }
7139 
7141 {
7142  QList<QKeySequence> zoomPanShortcuts;
7143  zoomPanShortcuts = ui->zoomPan_Action->shortcuts();
7144  zoomPanShortcuts.removeAll(QKeySequence(Qt::Key_Space));
7145  if (!qApp->Seamly2DSettings()->isPanActiveSpaceKey())
7146  {
7147  zoomPanShortcuts.append(QKeySequence(Qt::Key_Space));
7148  }
7149  ui->zoomPan_Action->setShortcuts(zoomPanShortcuts);
7150 }
7151 
7152 //---------------------------------------------------------------------------------------------------------------------
7153 bool MainWindow::IgnoreLocking(int error, const QString &path)
7154 {
7155  QMessageBox::StandardButton answer = QMessageBox::Abort;
7157  {
7158  switch(error)
7159  {
7160  case QLockFile::LockFailedError:
7161  answer = QMessageBox::warning(this, tr("Locking file"),
7162  tr("This file already opened in another window. Ignore if you want "
7163  "to continue (not recommended, can cause a data corruption)."),
7164  QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort);
7165  break;
7166  case QLockFile::PermissionError:
7167  answer = QMessageBox::question(this, tr("Locking file"),
7168  tr("The lock file could not be created, for lack of permissions. "
7169  "Ignore if you want to continue (not recommended, can cause "
7170  "a data corruption)."),
7171  QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort);
7172  break;
7173  case QLockFile::UnknownError:
7174  answer = QMessageBox::question(this, tr("Locking file"),
7175  tr("Unknown error happened, for instance a full partition prevented "
7176  "writing out the lock file. Ignore if you want to continue (not "
7177  "recommended, can cause a data corruption)."),
7178  QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort);
7179  break;
7180  default:
7181  answer = QMessageBox::Abort;
7182  break;
7183  }
7184  }
7185 
7186  if (answer == QMessageBox::Abort)
7187  {
7188  qCDebug(vMainWindow, "Failed to lock %s", qUtf8Printable(path));
7189  qCDebug(vMainWindow, "Error type: %d", error);
7190  Clear();
7191  if (not VApplication::IsGUIMode())
7192  {
7193  switch(error)
7194  {
7195  case QLockFile::LockFailedError:
7196  qCCritical(vMainWindow, "%s",
7197  qUtf8Printable(tr("This file already opened in another window.")));
7198  break;
7199  case QLockFile::PermissionError:
7200  qCCritical(vMainWindow, "%s",
7201  qUtf8Printable(tr("The lock file could not be created, for lack of permissions.")));
7202  break;
7203  case QLockFile::UnknownError:
7204  qCCritical(vMainWindow, "%s",
7205  qUtf8Printable(tr("Unknown error happened, for instance a full partition prevented "
7206  "writing out the lock file.")));
7207  break;
7208  default:
7209  break;
7210  }
7211 
7212  qApp->exit(V_EX_NOINPUT);
7213  }
7214  return false;
7215  }
7216  return true;
7217 }
7218 
7219 //---------------------------------------------------------------------------------------------------------------------
7220 /**
7221  * @brief draftPointNamesList gets the list of points in draft mode.
7222  */
7224 {
7225  QStringList pointNames;
7226  for (QHash<quint32, QSharedPointer<VGObject>>::const_iterator item = pattern->DataGObjects()->begin();
7227  item != pattern->DataGObjects()->end();
7228  ++item)
7229  {
7230  if (item.value()->getType() == GOType::Point && !pointNames.contains(item.value()->name()))
7231  pointNames << item.value()->name();
7232  }
7233  pointNames.sort();
7234  pointNames.removeDuplicates();
7235  return pointNames;
7236 }
7237 
7238 //---------------------------------------------------------------------------------------------------------------------
7239 /**
7240  * @brief updateZoomToPointComboBox updates the list of points included in the toolbar combobox.
7241  */
7242 void MainWindow::updateZoomToPointComboBox(QStringList namesList)
7243 {
7244  m_zoomToPointComboBox->blockSignals(true); // prevent this UI update from zooming to the first point
7245  m_zoomToPointComboBox->clear();
7246  m_zoomToPointComboBox->addItems(namesList);
7247  m_zoomToPointComboBox->blockSignals(false);
7248 }
7249 
7250 //---------------------------------------------------------------------------------------------------------------------
7252 {
7253  // Only true for rubber band selection
7254  emit EnableLabelSelection(false);
7255  emit EnablePointSelection(false);
7256  emit EnableLineSelection(false);
7257  emit EnableArcSelection(false);
7258  emit EnableElArcSelection(false);
7259  emit EnableSplineSelection(false);
7260  emit EnableSplinePathSelection(false);
7261 
7262  // Hovering
7263  emit EnableLabelHover(true);
7264  emit EnablePointHover(true);
7265  emit EnableLineHover(false);
7266  emit EnableArcHover(false);
7267  emit EnableElArcHover(false);
7268  emit EnableSplineHover(false);
7269  emit EnableSplinePathHover(false);
7270 
7271  ui->view->allowRubberBand(false);
7272 }
7273 
7274 //---------------------------------------------------------------------------------------------------------------------
7276 {
7277  ToolSelectPoint();
7279 }
7280 
7281 //---------------------------------------------------------------------------------------------------------------------
7283 {
7284  ToolSelectPoint();
7286 }
7287 
7288 //---------------------------------------------------------------------------------------------------------------------
7290 {
7291  // Only true for rubber band selection
7292  emit EnableLabelSelection(false);
7293  emit EnablePointSelection(false);
7294  emit EnableLineSelection(false);
7295  emit EnableArcSelection(false);
7296  emit EnableElArcSelection(false);
7297  emit EnableSplineSelection(false);
7298  emit EnableSplinePathSelection(false);
7299 
7300  // Hovering
7301  emit EnableLabelHover(false);
7302  emit EnablePointHover(false);
7303  emit EnableLineHover(false);
7304  emit EnableArcHover(false);
7305  emit EnableElArcHover(false);
7306  emit EnableSplineHover(true);
7307  emit EnableSplinePathHover(false);
7308 
7310 
7311  ui->view->allowRubberBand(false);
7312 }
7313 
7314 //---------------------------------------------------------------------------------------------------------------------
7316 {
7317  // Only true for rubber band selection
7318  emit EnableLabelSelection(false);
7319  emit EnablePointSelection(false);
7320  emit EnableLineSelection(false);
7321  emit EnableArcSelection(false);
7322  emit EnableElArcSelection(false);
7323  emit EnableSplineSelection(false);
7324  emit EnableSplinePathSelection(false);
7325 
7326  // Hovering
7327  emit EnableLabelHover(false);
7328  emit EnablePointHover(false);
7329  emit EnableLineHover(false);
7330  emit EnableArcHover(false);
7331  emit EnableElArcHover(false);
7332  emit EnableSplineHover(false);
7333  emit EnableSplinePathHover(true);
7334 
7336 
7337  ui->view->allowRubberBand(false);
7338 }
7339 
7340 //---------------------------------------------------------------------------------------------------------------------
7342 {
7343  // Only true for rubber band selection
7344  emit EnableLabelSelection(false);
7345  emit EnablePointSelection(false);
7346  emit EnableLineSelection(false);
7347  emit EnableArcSelection(false);
7348  emit EnableElArcSelection(false);
7349  emit EnableSplineSelection(false);
7350  emit EnableSplinePathSelection(false);
7351 
7352  // Hovering
7353  emit EnableLabelHover(false);
7354  emit EnablePointHover(false);
7355  emit EnableLineHover(false);
7356  emit EnableArcHover(true);
7357  emit EnableElArcHover(false);
7358  emit EnableSplineHover(false);
7359  emit EnableSplinePathHover(false);
7360 
7362 
7363  ui->view->allowRubberBand(false);
7364 }
7365 
7366 //---------------------------------------------------------------------------------------------------------------------
7368 {
7369  // Only true for rubber band selection
7370  emit EnableLabelSelection(false);
7371  emit EnablePointSelection(false);
7372  emit EnableLineSelection(false);
7373  emit EnableArcSelection(false);
7374  emit EnableElArcSelection(false);
7375  emit EnableSplineSelection(false);
7376  emit EnableSplinePathSelection(false);
7377 
7378  // Hovering
7379  emit EnableLabelHover(true);
7380  emit EnablePointHover(true);
7381  emit EnableLineHover(false);
7382  emit EnableArcHover(true);
7383  emit EnableElArcHover(false);
7384  emit EnableSplineHover(false);
7385  emit EnableSplinePathHover(false);
7386 
7388 
7389  ui->view->allowRubberBand(false);
7390 }
7391 
7392 //---------------------------------------------------------------------------------------------------------------------
7394 {
7395  // Only true for rubber band selection
7396  emit EnableLabelSelection(false);
7397  emit EnablePointSelection(false);
7398  emit EnableLineSelection(false);
7399  emit EnableArcSelection(false);
7400  emit EnableElArcSelection(false);
7401  emit EnableSplineSelection(false);
7402  emit EnableSplinePathSelection(false);
7403 
7404  // Hovering
7405  emit EnableLabelHover(false);
7406  emit EnablePointHover(false);
7407  emit EnableLineHover(false);
7408  emit EnableArcHover(true);
7409  emit EnableElArcHover(true);
7410  emit EnableSplineHover(true);
7411  emit EnableSplinePathHover(true);
7412 
7414 
7415  ui->view->allowRubberBand(false);
7416 }
7417 
7418 //---------------------------------------------------------------------------------------------------------------------
7420 {
7421  // Only true for rubber band selection
7422  emit EnableLabelSelection(false);
7423  emit EnablePointSelection(false);
7424  emit EnableLineSelection(false);
7425  emit EnableArcSelection(false);
7426  emit EnableElArcSelection(false);
7427  emit EnableSplineSelection(false);
7428  emit EnableSplinePathSelection(false);
7429 
7430  // Hovering
7431  emit EnableLabelHover(true);
7432  emit EnablePointHover(true);
7433  emit EnableLineHover(false);
7434  emit EnableArcHover(true);
7435  emit EnableElArcHover(true);
7436  emit EnableSplineHover(true);
7437  emit EnableSplinePathHover(true);
7438 
7440 
7441  ui->view->allowRubberBand(false);
7442 }
7443 
7444 //---------------------------------------------------------------------------------------------------------------------
7446 {
7447  // Only true for rubber band selection
7448  emit EnableLabelSelection(true);
7449  emit EnablePointSelection(true);
7450  emit EnableLineSelection(false);
7451  emit EnableArcSelection(true);
7452  emit EnableElArcSelection(true);
7453  emit EnableSplineSelection(true);
7454  emit EnableSplinePathSelection(true);
7455 
7456  // Hovering
7457  emit EnableLabelHover(true);
7458  emit EnablePointHover(true);
7459  emit EnableLineHover(false);
7460  emit EnableArcHover(true);
7461  emit EnableElArcHover(true);
7462  emit EnableSplineHover(true);
7463  emit EnableSplinePathHover(true);
7464 
7466 
7467  ui->view->allowRubberBand(true);
7468 }
7469 
7470 //---------------------------------------------------------------------------------------------------------------------
7472 {
7474  // Only true for rubber band selection
7475  emit EnableLineSelection(true);
7476 
7477  // Hovering
7478  emit EnableLineHover(true);
7479 }
7480 
7481 //---------------------------------------------------------------------------------------------------------------------
7483 {
7484  // Only true for rubber band selection
7485  emit EnableNodeLabelSelection(false);
7486  emit EnableNodePointSelection(false);
7487  emit enablePieceSelection(true); // Disable when done with pattern piece visualization.
7488 
7489  // Hovering
7490  emit EnableNodeLabelHover(true);
7491  emit EnableNodePointHover(true);
7492  emit enablePieceHover(true);
7493 
7495 
7496  ui->view->allowRubberBand(false);
7497 }
static AnchorPointTool * Create(QSharedPointer< DialogTool > dialog, VAbstractPattern *doc, VContainer *data)
QString name() const
Unit PatternUnit() const
void ToolTip(const QString &toolTip)
ToolTip emit tooltipe for tool.
virtual void ChosenObject(quint32 id, const SceneObject &type)
ChosenObject gets id and type of selected object. Save right data and ignore wrong.
void DialogClosed(int result)
DialogClosed signal dialog closed.
void DialogApplied()
DialogApplied emit signal dialog apply changes.
virtual void SelectedObject(bool selected, quint32 object, quint32 tool)
void setDestinationPath(const QString &cmdDestinationPath)
LayoutExportFormat format() const
static QString exportFormatSuffix(LayoutExportFormat format)
void setTextAsPaths(bool textAsPaths)
void setBinaryDXFFormat(bool binary)
void selectFormat(LayoutExportFormat format)
void showGroups(QMap< quint32, QString > groups)
void hideAllGroups()
void showAllGroups()
void unlockAllGroups()
void setAddGroupEnabled(bool value)
void lockAllGroups()
void deleteGroupFromList()
void addGroupToList()
The MainWindow class main windows.
Definition: mainwindow.h:87
void handlePointFromArcAndTangentTool(bool checked)
void handlePointOfIntersectionArcsTool(bool checked)
void selectPieceTool() const
void updateToolBarVisibility()
void EnableLabelSelection(bool enable) const
void EnableElArcSelection(bool enable) const
void ReopenFilesAfterCrash(QStringList &args)
QSharedPointer< VMeasurements > OpenMeasurementFile(const QString &path)
Definition: mainwindow.cpp:428
void ToolSelectSplinePath() const
void handleAlongLineTool(bool checked)
handleAlongLineTool handler for point along Line tools.
Definition: mainwindow.cpp:877
void handlePointsMenu()
void ToolSelectPointArc() const
QLabel * rightGoToStage
Definition: mainwindow.h:318
void initToolBarVisibility()
void enablePieceSelection(bool enable) const
void handleExportToCSV()
void zoomScaleChanged(qreal scale)
void zoomFirstShow()
zoomFirstShow Fit scene size to best size for first show
QPointer< QComboBox > gradationSizes
Definition: mainwindow.h:322
void EnableElArcHover(bool enable) const
void SetDefaultSize()
QPointer< MouseCoordinates > mouseCoordinates
mouseCoordinates pointer to label who show mouse coordinate.
Definition: mainwindow.h:280
@ MaxRecentFiles
Definition: mainwindow.h:313
void handleTriangleTool(bool checked)
handleTriangleTool handler Point - Intersect Axis and Triangle.
Definition: mainwindow.cpp:971
void FileClosedCorrect()
virtual void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE
closeEvent handle after close window.
void EnableNodeLabelHover(bool enable) const
void handleUnionTool(bool checked)
handleUnionTool handler for Union tool.
QPointer< HistoryDialog > historyDialog
Definition: mainwindow.h:298
void changeDraftBlock(int index, bool zoomBestFit=true)
void LoadMultisize()
void ProcessCMD()
bool UpdateMeasurements(const QString &path, int size, int height)
Definition: mainwindow.cpp:550
void updateZoomToPointComboBox(QStringList namesList)
updateZoomToPointComboBox updates the list of points included in the toolbar combobox.
virtual void ShowToolTip(const QString &toolTip) Q_DECL_OVERRIDE
ShowTool highlight tool.Tip show tools tooltip.
void showDraftMode(bool checked)
showDraftMode show draw scene.
void hideAllGroups()
void handleArcWithLengthTool(bool checked)
void EnableSplinePathHover(bool enable) const
QLabel * helpLabel
helpLabel help show tooltip.
Definition: mainwindow.h:285
void AddDocks()
void ClosedDrawDialogWithApply(int result)
Definition: mainwindow.cpp:801
bool isInitialized
isInitialized true after first show window.
Definition: mainwindow.h:288
void setToolBarVisibility(QToolBar *toolbar, bool visible)
bool patternReadOnly
Definition: mainwindow.h:294
QPointF draftBlockStartPosition() const
Definition: mainwindow.cpp:350
void UnloadMeasurements()
void exportPiecesAs()
bool SetHeight(const QString &text)
void addSelectedItemsToGroup()
void initPenToolBar()
initPenToolBar enable default color, line wight & type toolbar.
void InitAutoSave()
void AutoSavePattern()
AutoSavePattern start safe saving.
bool Save()
Save save pattern file.
void ClosedDialogInternalPath(int result)
void UpdateWindowTitle()
void EnableLineSelection(bool enable) const
void handleTrueDartTool(bool checked)
void handleShoulderPointTool(bool checked)
handleShoulderPointTool handler for shoulderPoint tool.
Definition: mainwindow.cpp:934
virtual void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE
keyPressEvent handle key press events.
bool mChangesAsked
Definition: mainwindow.h:292
virtual void customEvent(QEvent *event) Q_DECL_OVERRIDE
Ui::MainWindow * ui
ui keeps information about user interface
Definition: mainwindow.h:263
bool SavePattern(const QString &fileName, QString &error)
SavePattern save pattern file.
QTimer * autoSaveTimer
Definition: mainwindow.h:319
void EnablePointSelection(bool enable) const
void setCurrentFile(const QString &fileName)
setCurrentFile the function is called to reset the state of a few variables when a file is loaded or ...
void SetToolButtonWithApply(bool checked, Tool t, const QString &cursor, const QString &toolTip, Func closeDialogSlot, Func2 applyDialogSlot)
SetToolButtonWithApply set tool and show dialog.
Definition: mainwindow.cpp:703
void ToolSelectPoint() const
QComboBox * fontSizeComboBox
Definition: mainwindow.h:301
void zoomPan(bool checked)
void addDraftBlock(const QString &blockName)
Definition: mainwindow.cpp:298
bool drawMode
Definition: mainwindow.h:311
void CreateMenus()
void showAllGroups()
QAction * recentFileActs[MaxRecentFiles]
Definition: mainwindow.h:314
void handleInternalPathTool(bool checked)
VMainGraphicsScene * draftScene
draftScene draft block scene.
Definition: mainwindow.h:274
void ToolSelectCurve() const
void ApplyDrawDialog()
Definition: mainwindow.cpp:808
void handleCurveIntersectCurveTool(bool checked)
void handlePointAtDistanceAngleTool(bool checked)
handlePointAtDistanceAngleTool handler for handlePointAtDistanceAngle tool.
Definition: mainwindow.cpp:858
void handleSplineWithControlPointsTool(bool checked)
QFontComboBox * fontComboBox
Definition: mainwindow.h:300
void penChanged(Pen pen)
void UpdateHeightsList(const QStringList &list)
void ReadSettings()
ReadSettings read setting for app.
QAction * separatorAct
Definition: mainwindow.h:315
void EnablePointHover(bool enable) const
void New()
NewPattern create new empty pattern.
void enablePieceHover(bool enable) const
void showZoomToPointDialog()
zoomToPoint show dialog for choosing a point and update the graphics view to focus on it.
QPointer< QLabel > gradationSizesLabel
Definition: mainwindow.h:324
void EnableItemMove(bool move)
void handleMirrorByLineTool(bool checked)
void handleRotationTool(bool checked)
virtual void changeEvent(QEvent *event) Q_DECL_OVERRIDE
void ClosedInsertNodesDialog(int result)
void WriteSettings()
WriteSettings save setting for app.
void ChangedHeight(int index)
ChangedGrowth change new height value.
void EnableLineHover(bool enable) const
QString createDraftBlockName(const QString &text)
void resetPanShortcuts()
void ClosedDialogAnchorPoint(int result)
bool SaveAs()
SaveAs save as pattern file.
VToolOptionsPropertyBrowser * toolProperties
Definition: mainwindow.h:325
void handlePieceMenu()
bool isLayoutsDockVisible
Definition: mainwindow.h:309
void handleLineIntersectTool(bool checked)
handleLineIntersectTool handler for lineIntersect tool.
virtual void CleanLayout() Q_DECL_OVERRIDE
void ClosedEditGroupDialog(int result)
void handleNewLayout(bool checked)
handleNewLayout handler for New Layout tool.
QLabel * leftGoToStage
Definition: mainwindow.h:317
void handleCurveWithControlPointsTool(bool checked)
void handleEllipticalArcTool(bool checked)
handleEllipticalArcTool handler for EllipticalArc tool.
void MouseMove(const QPointF &scenePos)
mouseMove save mouse position and show user.
void handleSplineTool(bool checked)
handleSplineTool handler for spline tool.
void Open()
Open ask user select pattern file.
void exportDraftBlocksAs()
void zoomToPoint(const QString &pointName)
zoomToPoint show dialog for choosing a point and update the graphics view to focus on it.
void SetLayoutModeActions()
virtual void showEvent(QShowEvent *event) Q_DECL_OVERRIDE
showEvent handle after show window.
void ToolSelectOperationObjects() const
void ClosedDialogWithApply(int result, VMainGraphicsScene *scene)
ClosedDialogWithApply handle close dialog that has apply button.
Definition: mainwindow.cpp:747
Tool lastUsedTool
tool last used tool
Definition: mainwindow.h:271
void resetOrigins()
void showLayoutMode(bool checked)
showLayoutMode show layout scene.
PenToolBar * m_penToolBar
for selecting the current pen
Definition: mainwindow.h:331
virtual void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE
keyReleaseEvent handle key press events.
PiecesWidget * patternPiecesWidget
Definition: mainwindow.h:327
void deleteGroupFromList()
void ToolBarStyles()
GroupsWidget * groupsWidget
Definition: mainwindow.h:326
void RestoreCurrentScene()
RestoreCurrentScene restore scene options after change.
void handleGroupTool(bool checked)
void EnableSplineSelection(bool enable) const
void handleArrowTool(bool checked)
handleArrowTool enable arrow tool.
void handleNormalTool(bool checked)
handleNormalTool handler point on perpendicular tool.
Definition: mainwindow.cpp:896
void zoomToPrevious()
virtual ~MainWindow() Q_DECL_OVERRIDE
void handleArcTool(bool checked)
handleArcTool handler for arc tool.
void handleArcIntersectAxisTool(bool checked)
void zoomToArea(bool checked)
QFileSystemWatcher * watcher
Definition: mainwindow.h:265
void lockAllGroups()
virtual void exportToCSVData(const QString &fileName, const DialogExportToCSV &dialog) Q_DECL_FINAL
QComboBox * m_zoomToPointComboBox
Definition: mainwindow.h:333
void ItemsSelection(SelectionType type) const
bool LoadMeasurements(const QString &path)
Definition: mainwindow.cpp:498
void addGroupToList()
void MeasurementsChanged(const QString &path)
void EnableSplinePathSelection(bool enable) const
void handleBisectorTool(bool checked)
handleBisectorTool handler for bisector tool.
Definition: mainwindow.cpp:915
bool SetSize(const QString &text)
void InitScenes()
Definition: mainwindow.cpp:374
bool IgnoreLocking(int error, const QString &path)
bool isToolboxDockVisible
Definition: mainwindow.h:310
bool OpenNewSeamly2D(const QString &fileName=QString()) const
void ToolSelectPointByRelease() const
void EnableArcSelection(bool enable) const
void handleLineTool(bool checked)
handleLineTool handler for line tool.
void ChangedSize(int index)
ChangedSize change new size value.
bool LoadPattern(const QString &fileName, const QString &customMeasureFile=QString())
LoadPattern open pattern file.
void selectAllDraftObjectsTool() const
Tool currentTool
tool current tool
Definition: mainwindow.h:268
VMainGraphicsScene * pieceScene
pieceScene pattern piece scene.
Definition: mainwindow.h:277
void handleLineIntersectAxisTool(bool checked)
void EnableNodeLabelSelection(bool enable) const
void SaveCurrentScene()
SaveCurrentScene save scene options before set another.
void setEnableTools(bool enable)
setEnableTools enable button.
void handleMoveTool(bool checked)
void handleLinesMenu()
QString CheckPathToMeasurements(const QString &patternPath, const QString &path)
void ToolSelectPointByPress() const
void handlePointOfIntersectionCirclesTool(bool checked)
void RefreshHistory()
void handleMirrorByAxisTool(bool checked)
void handlePointOfContactTool(bool checked)
handlePointOfContactTool handler for pointOfContact tool.
Definition: mainwindow.cpp:953
void PatternChangesWereSaved(bool saved)
haveChange enable action save if we have unsaved change.
void handleMidpointTool(bool checked)
Definition: mainwindow.cpp:838
void EndVisualization(bool click=false)
EndVisualization try show dialog after and working with tool visualization.
QPointer< QComboBox > gradationHeights
Definition: mainwindow.h:321
QStringList GetUnlokedRestoreFileList() const
void initToolsToolBar()
void unlockAllGroups()
void applyPiecesDialog()
Definition: mainwindow.cpp:831
void handlePointAlongArcTool(bool checked)
handlePointAlongArcTool handler for PointAlongArc tool.
void SetDefaultHeight()
void initStatusBar()
initStatusBar initialize horizontal bar for presenting status information
void ToolSelectGroupObjects() const
void showLayoutPages(int index)
void handleLayoutMenu()
QString GetPatternFileName()
void SetToolButton(bool checked, Tool t, const QString &cursor, const QString &toolTip, Func closeDialogSlot)
SetToolButton set tool and show dialog.
Definition: mainwindow.cpp:632
void closeUnionDialog(int result)
closeUnionDialog actions after closing Union tool dialog.
void EnableSplineHover(bool enable) const
void LastUsedTool()
void initDraftToolBar()
initDraftToolBar enable draw toolbar.
bool guiEnabled
Definition: mainwindow.h:320
virtual void updateGroups() Q_DECL_OVERRIDE
triggers the update of the groups
void ToolSelectArc() const
void handlePointAlongCurveTool(bool checked)
handlePointAlongCurveTool handler for point along curve tool.
void showPieceMode(bool checked)
showPieceMode show Piece scene.
QDoubleSpinBox * zoomScaleSpinBox
Definition: mainwindow.h:330
void handlePatternPiecesMenu()
void CreateActions()
void FullParseFile()
void Clear()
Clear reset to default window.
QComboBox * SetGradationList(QLabel *label, const QStringList &list)
void GlobalchangeDraftBlock(const QString &patternPiece)
void handleCurvesMenu()
qint32 currentBlockIndex
mode stores current draw mode.
Definition: mainwindow.h:305
void handleCirclesMenu()
std::shared_ptr< VLockGuard< char > > lock
Definition: mainwindow.h:328
void ShowMeasurements()
void handlePointAlongSplineTool(bool checked)
handlePointAlongSplineTool handler for point along spline tool.
void InitToolButtons()
void updateViewToolbar()
void ToolSelectSpline() const
bool MaybeSave()
MaybeSave The function is called to save pending changes.
void UpdateSizesList(const QStringList &list)
void handlePatternPieceTool(bool checked)
handlePatternPieceTool handler for pattern piece tool.
bool mChanges
mChanges true if measurement file was changed.
Definition: mainwindow.h:291
void initModesToolBar()
qint32 currentToolBoxIndex
currentBlockIndex current selected draft block.
Definition: mainwindow.h:306
void LoadIndividual()
void SetEnableWidgets(bool enable)
SetEnableWidgets enable action button.
virtual void zoomToSelected() Q_DECL_OVERRIDE
void EnableArcHover(bool enable) const
void ApplyDialog(VMainGraphicsScene *scene)
ApplyDialog handle apply in dialog.
Definition: mainwindow.cpp:780
void EnableNodePointSelection(bool enable) const
QString GetMeasurementFileName()
void handleAnchorPointTool(bool checked)
void handleOperationsMenu()
void InitDocksContain()
bool isGroupsDockVisible
Definition: mainwindow.h:308
void editGroup()
void SyncMeasurements()
void handleCurveIntersectAxisTool(bool checked)
void UpdateRecentFileActions()
QPointer< QToolButton > infoToolButton
Definition: mainwindow.h:282
void MinimumScrollBar()
MinimumScrollBar set scroll bar to minimum.
void handlePointFromCircleAndTangentTool(bool checked)
QComboBox * draftBlockComboBox
Definition: mainwindow.h:302
QLabel * draftBlockLabel
draftBlockComboBox stores names of draft blocks.
Definition: mainwindow.h:303
void ClosedDialog(int result)
ClosedDialog handle close dialog.
Definition: mainwindow.cpp:726
void DoExport(const VCommandLinePtr &expParams)
void EnableNodePointHover(bool enable) const
QSharedPointer< DialogTool > dialogTool
Definition: mainwindow.h:297
virtual void PrepareSceneList() Q_DECL_OVERRIDE
void CancelTool()
CancelTool cancel tool.
void handleHeightTool(bool checked)
handleHeightTool handler tool height.
void EnableLabelHover(bool enable) const
void upDateScenes()
void exportLayoutAs()
QPointer< QLabel > gradationHeightsLabel
Definition: mainwindow.h:323
void ClosedPiecesDialogWithApply(int result)
Definition: mainwindow.cpp:815
void initPointNameToolBar()
initPointNameToolBar enable Point Name toolbar.
void handleCurveTool(bool checked)
handleCurveTool handler for curve tool.
QStringList draftPointNamesList()
draftPointNamesList gets the list of points in draft mode.
void Preferences()
void handlePointIntersectXYTool(bool checked)
handlePointIntersectXYTool handler for pointOfIntersection tool.
Definition: mainwindow.cpp:990
bool isToolOptionsDockVisible
currentToolBoxIndex current set of tools.
Definition: mainwindow.h:307
void handleInsertNodesTool(bool checked)
void SetEnabledGUI(bool enabled)
void CheckRequiredMeasurements(const VMeasurements *m)
Definition: mainwindow.cpp:602
void handleArcsMenu()
QGraphicsScene * tempSceneLayout
currentScene pointer to current scene.
void exportPPM(const QString &name, QGraphicsScene *scene) const
exportPPM save layout to gif file.
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)
void ExportData(const QVector< VLayoutPiece > &pieceList, const ExportLayoutDialog &dialog)
void refreshLabels()
refreshLabels call to recalculate piece labels. For example after changing a font.
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 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
static QVector< VLayoutPiece > preparePiecesForLayout(const QHash< quint32, VPiece > &pieces)
QList< QGraphicsItem * > papers
doc dom document container
QAction * actionDockWidgetGroups
QIcon ScenePreview(int i) const
void exportBMP(const QString &name, QGraphicsScene *scene) const
exportBMP save layout to bmp file.
void exportPNG(const QString &name, QGraphicsScene *scene) const
exportPNG save layout to png file.
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 exportPS(const QString &name, QGraphicsRectItem *paper, QGraphicsScene *scene, bool ignoreMargins, const QMarginsF &margins) const
exportPS save layout to ps file.
QAction * actionDockWidgetToolOptions
bool LayoutSettings(VLayoutGenerator &lGenerator)
QAction * actionDockWidgetToolbox
void toolLayoutSettings(QToolButton *tButton, bool checked)
QList< QGraphicsScene * > scenes
QAction * actionDockWidgetLayouts
VPattern * doc
pattern container with data (points, arcs, splines, spline paths, variables)
QString FileName() const
QGraphicsScene * currentScene
static void insertNodes(const QVector< VPieceNode > &nodes, quint32 pieceId, VMainGraphicsScene *scene, VContainer *data, VAbstractPattern *doc)
void penChanged(Pen pen)
Definition: pen.h:37
void togglePiece(quint32 id)
void Highlight(quint32 id)
void selectPiece(quint32 id)
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.
int GetCurrentFormatVarsion() const
QString GetVersionStr() const
void exportToCSV(QString &file)
void ToolBarStyle(QToolBar *bar)
bool ContinueFormatRewrite(const QString &currentFormatVersion, const QString &maxFormatVersion)
void FullUpdateFromFile()
FullUpdateFromFile update tool data form file.
void UpdateInLayoutList(quint32 id)
void SetModified(bool modified)
QString MPath() const
QStringList getPatternPieces() const
void SetPatternWasChanged(bool changed)
bool appendDraftBlock(const QString &name)
appendDraftBlock add new draft block.
void patternChanged(bool saved)
patternChanged emit if we have unsaved change.
void ClearMainWindow()
QDomElement addGroupItems(const QString &name, const QMap< quint32, quint32 > &groupData)
void UpdatePatternLabel()
QMap< GHeights, bool > GetGradationHeights() const
static VDataTool * getTool(quint32 id)
getTool return tool from tool list.
void setDefaultPen(Pen pen)
void SetEnabledGUI(bool enabled)
QStringList ListMeasurements() const
QMap< GSizes, bool > GetGradationSizes() const
void showPiece(quint32 id)
QString getActiveDraftBlockName() const
getActiveDraftBlockName return current draft block name.
QMap< quint32, QString > getGroupsContainingItem(quint32 toolId, quint32 objectId, bool containsItem)
Returns the groups that contain or do not contain the item identified by the toolid and the objectid.
quint32 getCursor() const
void setCurrentDraftBlock(const QString &patterPiece)
void changeActiveDraftBlock(const QString &name, const Document &parse=Document::FullParse)
changeActiveDraftBlock set new active draft block name.
void SetMPath(const QString &path)
The VAbstractTool abstract class for all tools.
Definition: vabstracttool.h:80
static bool m_suppressContextMenu
Definition: vabstracttool.h:87
static bool IsGUIMode()
static void NewSeamly2D(const QString &fileName=QString())
NewSeamly2D start Seamly2D in new process, send path to pattern file in argument.
static QString GetDefPathMultisizeMeasurements()
static QString PrepareMultisizeTables(const QString &currentPath)
void SetRecentFileList(const QStringList &value)
QByteArray GetGeometry() const
void SetToolbarsState(const QByteArray &value)
QByteArray GetToolbarsState() const
QStringList GetRecentFileList() const
void SetRestoreFileList(const QStringList &value)
void SetWindowState(const QByteArray &value)
int GetUndoCount() const
QByteArray GetWindowState() const
QStringList GetRestoreFileList() const
void SetGeometry(const QByteArray &value)
static qreal height()
height return height
Definition: vcontainer.cpp:690
static void SetSize(qreal size)
SetSize set value of size.
Definition: vcontainer.cpp:654
const QHash< quint32, VPiece > * DataPieces() const
Definition: vcontainer.cpp:712
void ClearVariables(const VarType &type=VarType::Unknown)
Definition: vcontainer.cpp:348
static qreal * rsize()
Definition: vcontainer.cpp:680
void Clear()
Clear clear data in container. Id will be 0.
Definition: vcontainer.cpp:281
void ClearGObjects()
ClearObject points, splines, arcs, spline paths will be cleared.
Definition: vcontainer.cpp:316
static qreal size()
size return size
Definition: vcontainer.cpp:674
static qreal * rheight()
Definition: vcontainer.cpp:696
const QMap< QString, QSharedPointer< VIncrement > > variablesData() const
Definition: vcontainer.cpp:543
const QHash< quint32, QSharedPointer< VGObject > > * DataGObjects() const
data container with datagObjects return container of gObjects
Definition: vcontainer.cpp:706
const Unit * GetPatternUnit() const
Definition: vcontainer.cpp:599
static void SetHeight(qreal height)
SetGrowth set value of growth.
Definition: vcontainer.cpp:664
Unit MUnit() const
static bool SafeCopy(const QString &source, const QString &destination, QString &error)
The VExceptionBadId class for exception bad id.
virtual QString ErrorMessage() const Q_DECL_OVERRIDE
ErrorMessage return main error message.
The VExceptionConversionError class for exception of conversion error.
The VExceptionEmptyParameter class for exception empty parameter.
virtual QString ErrorMessage() const Q_DECL_OVERRIDE
ErrorMessage return main error message.
virtual QString DetailedInformation() const Q_DECL_OVERRIDE
DetailedInformation return detailed information about error.
The VExceptionObjectError class for exception object error.
The VExceptionWrongId class for exception wrong id.
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
void AddMoreInformation(const QString &info)
AddMoreInformation add more information for error.
Definition: vexception.cpp:107
virtual QString DetailedInformation() const
DetailedInformation return detailed information about error.
Definition: vexception.cpp:134
quint32 getIdObject() const
getIdObject return parent id.
Definition: vgobject.cpp:128
quint32 getIdTool() const
Definition: vgobject.cpp:221
bool IsLocked() const
Definition: vlockguard.h:155
The VMainGraphicsScene class main scene.
void SetDisableTools(bool disable, const QString &draftBlockName)
QTransform transform() const
transform return view transformation.
void EnableItemMove(bool move)
QRectF visibleItemsBoundingRect() const
void setOriginsVisible(bool visible)
void ToggleArcHover(bool enabled)
void mouseMove(const QPointF &scenePos)
mouseMove send new mouse position.
void ToggleSplinePathSelection(bool enabled)
void TogglePointHover(bool enabled)
void ToggleElArcHover(bool enabled)
void ToggleElArcSelection(bool enabled)
void togglePieceSelection(bool enabled)
void ToggleNodePointSelection(bool enabled)
void ToggleNodeLabelHover(bool enabled)
void ToggleNodePointHover(bool enabled)
void SelectedObject(bool selected, quint32 object, quint32 tool)
qint32 getHorScrollBar() const
getHorScrollBar return scene horizontal scrollbar.
void ToggleSplinePathHover(bool enabled)
void ToggleNodeLabelSelection(bool enabled)
void setVerScrollBar(const qint32 &value)
setVerScrollBar set scene vertical scrollbar.
void ChosenObject(quint32 id, SceneObject type)
ChosenObject send option choosed object.
void ToggleSplineHover(bool enabled)
void setHorScrollBar(const qint32 &value)
setHorScrollBar set scene horizontal scrollbar.
void ToggleLabelSelection(bool enabled)
void ToggleSplineSelection(bool enabled)
void togglePieceHover(bool enabled)
void ToggleArcSelection(bool enabled)
void ToggleLabelHover(bool enabled)
void HighlightItem(quint32 id)
void setCurrentTransform(const QTransform &transform)
setCurrentTransform set view transformation.
void swapTransforms()
swapTransforms.
void enablePiecesMode(bool mode)
void ItemsSelection(const SelectionType &type)
void ToggleLineSelection(bool enabled)
void TogglePointSelection(bool enabled)
qint32 getVerScrollBar() const
getVerScrollBar return scene vertical scrollbar.
void ToggleLineHover(bool enabled)
void itemClicked(QGraphicsItem *item)
void signalZoomScaleChanged(qreal scale)
static qreal MinScale()
void mouseRelease()
mouseRelease help catch mouse release event.
static void NewSceneRect(QGraphicsScene *sc, QGraphicsView *view, QGraphicsItem *item=nullptr)
NewSceneRect calculate scene rect what contains all items and doesn't less that size of scene view.
static qreal MaxScale()
static QStringList ListSizes(QMap< GSizes, bool > sizes, Unit patternUnit)
static QStringList ListHeights(QMap< GHeights, bool > heights, Unit patternUnit)
QStringList ListAll() const
void SetSize(qreal *size)
void SetHeight(qreal *height)
MeasurementsType Type() const
virtual void setXMLContent(const QString &fileName) Q_DECL_OVERRIDE
static const QString PatternMaxVerStr
static Q_DECL_CONSTEXPR const int PatternMaxVer
The VPattern class working with pattern file.
Definition: vpattern.h:68
int GetDefCustomSize() const
Definition: vpattern.cpp:3823
QVector< quint32 > getActivePatternPieces() const
Definition: vpattern.cpp:385
QRectF ActiveDrawBoundingRect() const
Definition: vpattern.cpp:3959
int GetDefCustomHeight() const
Definition: vpattern.cpp:3764
bool IsReadOnly() const
Definition: vpattern.cpp:3882
virtual QString GenerateLabel(const LabelType &type, const QString &reservedName=QString()) const Q_DECL_OVERRIDE
GenerateLabel create name for draft block basepoint.
Definition: vpattern.cpp:3630
virtual void setXMLContent(const QString &fileName) Q_DECL_OVERRIDE
Definition: vpattern.cpp:149
virtual bool SaveDocument(const QString &fileName, QString &error) Q_DECL_OVERRIDE
Definition: vpattern.cpp:410
virtual void LiteParseTree(const Document &parse) Q_DECL_OVERRIDE
LiteParseTree lite parse file.
Definition: vpattern.cpp:515
void Parse(const Document &parse)
Parse parse file.
Definition: vpattern.cpp:160
void setCurrentData()
setCurrentData set current data set.
Definition: vpattern.cpp:274
The VPointF class keep data of point.
Definition: vpointf.h:75
QPointF toQPointF() const
Definition: vpointf.cpp:213
bool GetGraphicalOutput() const
Definition: vsettings.cpp:176
static VToolBasePoint * Create(quint32 _id, const QString &activeDraftBlock, VPointF *point, VMainGraphicsScene *scene, VAbstractPattern *doc, VContainer *data, const Document &parse, const Source &typeCreation)
static VToolInternalPath * Create(QSharedPointer< DialogTool > dialog, VMainGraphicsScene *scene, VAbstractPattern *doc, VContainer *data)
static void PopupMessage(QWidget *w, const QString &msg)
Error class of the parser.
const QEvent::Type UNDO_EVENT
Definition: customevents.h:61
QPixmap darkenPixmap(const QPixmap &pixmap)
Definition: def.cpp:489
const QString LONG_OPTION_NO_HDPI_SCALING
Definition: def.cpp:535
QString strippedName(const QString &fullFileName)
strippedName the function call around curFile to exclude the path to the file.
Definition: def.cpp:391
QString AbsoluteMPath(const QString &patternPath, const QString &relativeMPath)
Definition: def.cpp:424
QString UnitsToStr(const Unit &unit, const bool translate)
UnitsToStr translate unit to string.
Definition: def.cpp:702
QString RelativeMPath(const QString &patternPath, const QString &absoluteMPath)
Definition: def.cpp:408
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
MeasurementsType
Definition: def.h:104
Tool
Definition: def.h:161
@ CubicBezierPath
@ PointOfIntersectionCurves
@ PointOfIntersectionCircles
@ LineIntersectAxis
@ ArcWithLength
@ AlongLine
@ EndLine
@ SinglePoint
@ PointFromCircleAndTangent
@ InternalPath
@ MirrorByLine
@ ShoulderPoint
@ Spline
@ Bisector
@ NodeSplinePath
@ NodeSpline
@ NodeElArc
@ TrueDarts
@ Triangle
@ SplinePath
@ CurveIntersectAxis
@ LineIntersect
@ LinePoint
@ NodeArc
@ BasePoint
@ Midpoint
@ CutArc
@ ArcIntersectAxis
@ Normal
@ DoublePoint
@ EllipticalArc
@ PointOfContact
@ CutSplinePath
@ PointFromArcAndTangent
@ AbstractSpline
@ PointOfIntersection
@ NodePoint
@ CubicBezier
@ LAST_ONE_DO_NOT_USE
@ MirrorByAxis
@ PointOfIntersectionArcs
@ InsertNodes
@ Height
@ Rotation
@ CutSpline
@ AnchorPoint
#define NULL_ID
Definition: ifcdef.h:76
const QString strCtrl
Definition: mainwindow.cpp:127
QT_WARNING_PUSH QT_WARNING_POP const QString autosavePrefix
Definition: mainwindow.cpp:123
const QString strQShortcut
Definition: mainwindow.cpp:126
#define APP_VERSION
#define VER_INTERNALNAME_STR
Definition: version.h:57
#define qApp
Definition: vapplication.h:67
#define translate(context, source)
Definition: vcmdexport.cpp:41
std::shared_ptr< VCommandLine > VCommandLinePtr
Definition: vcmdexport.h:41
Draw
Definition: vgeometrydef.h:55
@ Modeling
@ Calculation
@ Layout
QT_WARNING_PUSH void VlpCreateLock(std::shared_ptr< VLockGuard< Guarded >> &r, const QString &lockName, int stale=0, int timeout=0)
Definition: vlockguard.h:213
static const auto V_EX_DATAERR
Definition: vsysexits.h:68
static const auto V_EX_OK
Definition: vsysexits.h:63
static const auto V_EX_NOINPUT
Definition: vsysexits.h:71