Seamly2D
Code documentation
groups_widget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  ** @file groups_widget.cpp
3  ** @author Douglas S Caskey
4  ** @date 11 Jun, 2023
5  **
6  ** @copyright
7  ** Copyright (C) 2017 - 2023 Seamly, LLC
8  ** https://github.com/fashionfreedom/seamly2d
9  **
10  ** @brief
11  ** Seamly2D is free software: you can redistribute it and/or modify
12  ** it under the terms of the GNU General Public License as published by
13  ** the Free Software Foundation, either version 3 of the License, or
14  ** (at your option) any later version.
15  **
16  ** Seamly2D is distributed in the hope that it will be useful,
17  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  ** GNU General Public License for more details.
20  **
21  ** You should have received a copy of the GNU General Public License
22  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
23  **************************************************************************/
24 
25  /************************************************************************
26  **
27  ** @file vwidgetgroups.cpp
28  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
29  ** @date 6 4, 2016
30  **
31  ** @brief
32  ** @copyright
33  ** This source code is part of the Valentina project, a pattern making
34  ** program, whose allow create and modeling patterns of clothing.
35  ** Copyright (C) 2016 Valentina project
36  ** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
37  **
38  ** Valentina is free software: you can redistribute it and/or modify
39  ** it under the terms of the GNU General Public License as published by
40  ** the Free Software Foundation, either version 3 of the License, or
41  ** (at your option) any later version.
42  **
43  ** Valentina is distributed in the hope that it will be useful,
44  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
45  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46  ** GNU General Public License for more details.
47  **
48  ** You should have received a copy of the GNU General Public License
49  ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
50  **
51  *************************************************************************/
52 
53 #include "groups_widget.h"
54 #include "ui_groups_widget.h"
55 #include "../core/vapplication.h"
56 #include "../vtools/tools/vabstracttool.h"
57 #include "../vtools/dialogs/tools/dialogtool.h"
58 #include "../vtools/dialogs/tools/editgroup_dialog.h"
59 #include "../vtools/undocommands/delgroup.h"
60 #include "../vtools/undocommands/addgroup.h"
61 #include "../vtools/undocommands/add_groupitem.h"
62 #include "../vtools/undocommands/remove_groupitem.h"
63 #include "../vtools/undocommands/move_groupitem.h"
64 #include "../vtools/tools/vabstracttool.h"
65 #include "../vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcutspline.h"
66 #include "../vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcutsplinepath.h"
67 #include "../vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcutarc.h"
68 #include "../vgeometry/vabstractarc.h"
69 #include "../vgeometry/varc.h"
70 #include "../vgeometry/vellipticalarc.h"
71 #include "../vgeometry/vcubicbezier.h"
72 #include "../vgeometry/vsplinepath.h"
73 #include "../vgeometry/vcubicbezierpath.h"
74 #include "../vgeometry/vpointf.h"
75 #include "../vpatterndb/vcontainer.h"
76 #include "../vwidgets/group_tablewidgetitem.h"
77 #include "../vwidgets/vabstractmainwindow.h"
78 #include "../vmisc/vabstractapplication.h"
79 #include "../vmisc/vsettings.h"
80 #include "../vmisc/vcommonsettings.h"
81 #include "../vmisc/logging.h"
82 #include "../ifc/ifcdef.h"
83 #include "../ifc/xml/vabstractpattern.h"
84 
85 #include <Qt>
86 #include <QApplication>
87 #include <QColor>
88 #include <QIcon>
89 #include <QListWidget>
90 #include <QListWidgetItem>
91 #include <QMenu>
92 #include <QMessageBox>
93 #include <QMetaObject>
94 #include <QObject>
95 #include <QPointer>
96 #include <QScopedPointer>
97 #include <QSettings>
98 #include <QTableWidget>
99 #include <QtDebug>
100 
101 Q_LOGGING_CATEGORY(WidgetGroups, "vwidgetgroups")
102 
103 //---------------------------------------------------------------------------------------------------------------------
104 GroupsWidget::GroupsWidget(VContainer *data, VAbstractPattern *doc, QWidget *parent)
105  : QWidget(parent)
106  , ui(new Ui::GroupsWidget)
107  , m_doc(doc)
108  , m_data(data)
109  , m_patternHasGroups(false)
110  , m_currentGroupId(0)
111 
112 {
113  ui->setupUi(this);
114  QSettings settings;
115  ui->groups_Splitter->restoreState(settings.value("splitterSizes").toByteArray());
116 
117  fillTable(m_doc->getGroups());
118  ui->groups_TableWidget->sortItems(settings.value("groupSort", 4).toInt(), Qt::AscendingOrder);
119 
121 
122  connect(ui->showAllGroups_ToolButton, &QToolButton::clicked, this, &GroupsWidget::showAllGroups);
123  connect(ui->hideAllGroups_ToolButton, &QToolButton::clicked, this, &GroupsWidget::hideAllGroups);
124  connect(ui->lockAllGroups_ToolButton, &QToolButton::clicked, this, &GroupsWidget::lockAllGroups);
125  connect(ui->unlockAllGroups_ToolButton, &QToolButton::clicked, this, &GroupsWidget::unlockAllGroups);
126  connect(ui->addGroup_ToolButton, &QToolButton::clicked, this, &GroupsWidget::addGroupToList);
127  connect(ui->deleteGroup_ToolButton, &QToolButton::clicked, this, &GroupsWidget::deleteGroupFromList);
128  connect(ui->editGroup_ToolButton, &QToolButton::clicked, this, &GroupsWidget::editGroup);
129 
130  connect(ui->groups_TableWidget, &QTableWidget::cellClicked, this, &GroupsWidget::groupVisibilityChanged);
131  connect(ui->groups_TableWidget, &QTableWidget::cellClicked, this, &GroupsWidget::groupLockChanged);
132  connect(ui->groups_TableWidget, &QTableWidget::cellChanged, this, &GroupsWidget::renameGroup);
133  connect(ui->groups_TableWidget, &QTableWidget::cellClicked, this, &GroupsWidget::fillGroupItemList);
134  connect(ui->groups_TableWidget, &QTableWidget::currentCellChanged, this, &GroupsWidget::fillGroupItemList);
135 
136  ui->groups_TableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
137  connect(ui->groups_TableWidget, &QTableWidget::customContextMenuRequested, this, &GroupsWidget::groupContextMenu);
138 
139  ui->groupItems_ListWidget->setContextMenuPolicy(Qt::CustomContextMenu);
140  connect(ui->groupItems_ListWidget, &QListWidget::customContextMenuRequested, this, &GroupsWidget::groupItemContextMenu);
141  connect(ui->groupItems_ListWidget, &QListWidget::itemDoubleClicked, this, &GroupsWidget::itemDoubleClicked);
142 
143  connect(ui->groups_TableWidget->horizontalHeader(), &QHeaderView::sectionClicked, this, &GroupsWidget::headerClicked);
144  connect(ui->groups_Splitter, &QSplitter::splitterMoved, this, &GroupsWidget::splitterMoved);
145 }
146 
147 //---------------------------------------------------------------------------------------------------------------------
149 {
150  delete ui;
151 }
152 
153 //---------------------------------------------------------------------------------------------------------------------
154 void GroupsWidget::groupVisibilityChanged(int row, int column)
155 {
156  if (column != 0) return;
157 
158  QTableWidgetItem *item = ui->groups_TableWidget->item(row, column);
159  const quint32 groupId = item->data(Qt::UserRole).toUInt();
160  const bool locked = m_doc->getGroupLock(groupId);
161  if (locked == false)
162  {
163  const bool visible = !m_doc->getGroupVisibility(groupId);
164  setGroupVisibility(item, groupId, visible);
165  }
166 }
167 
168 //---------------------------------------------------------------------------------------------------------------------
169 void GroupsWidget::groupLockChanged(int row, int column)
170 {
171  if (column != 1)
172  {
173  return;
174  }
175 
176  QTableWidgetItem *item = ui->groups_TableWidget->item(row, column);
177  if (!item) return;
178  const quint32 groupId = item->data(Qt::UserRole).toUInt();
179  const bool locked = !m_doc->getGroupLock(groupId);
180  m_doc->setGroupLock(groupId, locked);
181  if (locked)
182  {
183  item->setIcon(QIcon("://icon/32x32/lock_on.png"));
184  }
185  else
186  {
187  item->setIcon(QIcon("://icon/32x32/lock_off.png"));
188  }
189 }
190 
191 //---------------------------------------------------------------------------------------------------------------------
192 void GroupsWidget::renameGroup(int row, int column)
193 {
194  if (column != 2)
195  {
196  return;
197  }
198 
199  const quint32 groupId = ui->groups_TableWidget->item(row, 0)->data(Qt::UserRole).toUInt();
200  const bool locked = m_doc->getGroupLock(groupId);
201  if (locked == false)
202  {
203  m_doc->setGroupName(groupId, ui->groups_TableWidget->item(row, column)->text());
204  updateGroups();
205  }
206 }
207 
209 {
211  for (i = groups.constBegin(); i != groups.constEnd(); ++i)
212  {
213  for (int j = 0; j < ui->groups_TableWidget->rowCount(); ++j)
214  {
215  QTableWidgetItem *item = ui->groups_TableWidget->item(j, 0);
216  if (item)
217  {
218  quint32 groupId = item->data(Qt::UserRole).toUInt();
219  if (groupId == i.key())
220  {
221  setGroupVisibility(item, groupId, true);
222  }
223  }
224  }
225  }
226  updateGroups();
227 }
228 
230 {
231  qCDebug(WidgetGroups, "Show All Groups");
232  quint32 groupId;
233  bool locked;
234  for (int i = 0; i < ui->groups_TableWidget->rowCount(); ++i)
235  {
236  QTableWidgetItem *item = ui->groups_TableWidget->item(i, 0);
237  if (!item)
238  {
239  return;
240  }
241  groupId = item->data(Qt::UserRole).toUInt();
242  locked = m_doc->getGroupLock(groupId);
243  if (item && locked == false)
244  {
245  setGroupVisibility(item, groupId, true);
246  }
247  }
248 }
249 
251 {
252  qCDebug(WidgetGroups, "Hide All Groups");
253  quint32 groupId;
254  bool locked;
255  for (int row = 0; row < ui->groups_TableWidget->rowCount(); ++row)
256  {
257  QTableWidgetItem *item = ui->groups_TableWidget->item(row, 0);
258  if (!item)
259  {
260  return;
261  }
262  groupId = item->data(Qt::UserRole).toUInt();
263  locked = m_doc->getGroupLock(groupId);
264  if (item && locked == false)
265  {
266  setGroupVisibility(item, groupId, false);
267  }
268  }
269 }
270 
272 {
273  qCDebug(WidgetGroups, "Lock All Groups");
274  for (int row = 0; row < ui->groups_TableWidget->rowCount(); ++row)
275  {
276  QTableWidgetItem *item = ui->groups_TableWidget->item(row, 1);
277  if (!item)
278  {
279  return;
280  }
281  const quint32 groupId = item->data(Qt::UserRole).toUInt();
282  m_doc->setGroupLock(groupId, true);
283  item->setIcon(QIcon("://icon/32x32/lock_on.png"));
284  }
285 }
286 
288 {
289  qCDebug(WidgetGroups, "Unlock All Groups");
290  for (int row = 0; row < ui->groups_TableWidget->rowCount(); ++row)
291  {
292  QTableWidgetItem *item = ui->groups_TableWidget->item(row, 1);
293  if (!item)
294  {
295  return;
296  }
297  const quint32 groupId = item->data(Qt::UserRole).toUInt();
298  m_doc->setGroupLock(groupId, false);
299  item->setIcon(QIcon("://icon/32x32/lock_off.png"));
300  }
301 }
302 
304 {
305  QScopedPointer<EditGroupDialog> dialog(new EditGroupDialog(new VContainer(qApp->TrVars(),
306  qApp->patternUnitP()), NULL_ID, this));
307  SCASSERT(dialog != nullptr)
308 
309  QString groupName;
310  while (1)
311  {
312  const bool result = dialog->exec();
313  groupName = dialog->getName();
314  if (result == false || groupName.isEmpty())
315  {
316  return;
317  }
318  bool exists = m_doc->groupNameExists(groupName);
319  if (exists == false)
320  {
321  break;
322  }
323 
324  QMessageBox messageBox;
325  messageBox.setWindowTitle(tr("Name Exists"));
326  messageBox.setIcon(QMessageBox::Warning);
327  messageBox.setStandardButtons(QMessageBox::Retry | QMessageBox::Cancel);
328  messageBox.setDefaultButton(QMessageBox::Retry);
329  messageBox.setText(tr("The action can't be completed because the group name already exists."));
330  int boxResult = messageBox.exec();
331 
332  switch (boxResult)
333  {
334  case QMessageBox::Retry:
335  break; // Repeat Add Group Dialog
336  case QMessageBox::Cancel:
337  return; // Exit Add Group Dialog
338  default:
339  break; // should never be reached
340  }
341  }
342 
343  const quint32 nextId = VContainer::getNextId();
344  qCDebug(WidgetGroups, "Group Name = %s", qUtf8Printable(groupName));
345  qCDebug(WidgetGroups, "Next Id = %d", nextId);
346 
347  const QDomElement group = m_doc->createGroup(nextId, groupName, dialog->getColor(), dialog->getLineType(),
348  dialog->getLineWeight(), dialog->getGroupData());
349 
350  if (!group.isNull())
351  {
352  qCDebug(WidgetGroups, "Add a Group to List");
353  AddGroup *command = new AddGroup(group, m_doc);
354  connect(command, &AddGroup::updateGroups, this, &GroupsWidget::updateGroups);
355  qApp->getUndoStack()->push(command);
356  }
357 }
358 
360 {
361  const quint32 groupId = getGroupId();
362  qCDebug(WidgetGroups, "Remove Group %d from List", groupId);
363  const bool locked = m_doc->getGroupLock(groupId);
364  QTableWidgetItem *item = ui->groups_TableWidget->currentItem();
365  if (!item)
366  {
367  return;
368  }
369 
370  if (item && (locked == false))
371  {
372  DelGroup *command = new DelGroup(m_doc, groupId);
373  connect(command, &DelGroup::updateGroups, this, &GroupsWidget::updateGroups);
374  qApp->getUndoStack()->push(command);
375  }
376 }
377 
379 {
380  ui->groups_TableWidget->blockSignals(true);
381  qCDebug(WidgetGroups, "Edit Group List");
382  const int row = ui->groups_TableWidget->currentRow();
383  if (ui->groups_TableWidget->rowCount() == 0 || row == -1 || row >= ui->groups_TableWidget->rowCount())
384  {
385  ui->groups_TableWidget->blockSignals(false);
386  return;
387  }
388 
389  const quint32 groupId = ui->groups_TableWidget->item(row, 0)->data(Qt::UserRole).toUInt();
390  const bool locked = m_doc->getGroupLock(groupId);
391  QString oldGroupName = m_doc->getGroupName(groupId);
392  if (locked == false)
393  {
394  qCDebug(WidgetGroups, "Row = %d", row);
395 
396  QScopedPointer<EditGroupDialog> dialog(new EditGroupDialog(new VContainer(qApp->TrVars(),
397  qApp->patternUnitP()), NULL_ID, this));
398  dialog->setName(oldGroupName);
399  dialog->setColor(m_doc->getGroupColor(groupId));
400  dialog->setLineType(m_doc->getGroupLineType(groupId));
401  dialog->setLineWeight(m_doc->getGroupLineWeight(groupId));
402  dialog->setWindowTitle(tr("Edit Group"));
403 
404  QString groupName;
405  while (1)
406  {
407  const bool result = dialog->exec();
408  groupName = dialog->getName();
409  if (result == false || groupName.isEmpty())
410  {
411  ui->groups_TableWidget->blockSignals(false);
412  return;
413  }
414  bool exists = m_doc->groupNameExists(groupName);
415  if (exists == false || groupName == oldGroupName)
416  {
417  break;
418  }
419 
420  QMessageBox messageBox;
421  messageBox.setWindowTitle(tr("Name Exists"));
422  messageBox.setIcon(QMessageBox::Warning);
423  messageBox.setStandardButtons(QMessageBox::Retry | QMessageBox::Cancel);
424  messageBox.setDefaultButton(QMessageBox::Retry);
425  messageBox.setText(tr("The action can't be completed because the group name already exists."));
426  int boxResult = messageBox.exec();
427 
428  switch (boxResult)
429  {
430  case QMessageBox::Retry:
431  break; // Repeat Add Group Dialog
432  case QMessageBox::Cancel:
433  return; // Exit Add Group Dialog
434  default:
435  break; // should never be reached
436  }
437  }
438 
439  const QString groupColor = dialog->getColor();
440  const QString groupLineType = dialog->getLineType();
441  const QString groupLineWeight = dialog->getLineWeight();
442 
443  QTableWidgetItem *item = ui->groups_TableWidget->item(row, 3);
444  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
445  item->setSizeHint(QSize(20, 20));
446  QPixmap pixmap(20, 20);
447  pixmap.fill(QColor(groupColor));
448  item->setIcon(QIcon(pixmap));
449  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
450  item->setToolTip(tr("Group color"));
451  ui->groups_TableWidget->setItem(row, 3, item);
452 
453  item = ui->groups_TableWidget->item(row, 4);
454  item->setText(groupName);
455 
456  m_doc->setGroupName(groupId, groupName);
457  m_doc->setGroupColor(groupId, groupColor);
458  m_doc->setGroupLineType(groupId, groupLineType);
459  m_doc->setGroupLineWeight(groupId, groupLineWeight);
460 
461  updateGroups();
462  }
463  ui->groups_TableWidget->blockSignals(false);
464 }
465 
466 //---------------------------------------------------------------------------------------------------------------------
467 void GroupsWidget::groupContextMenu(const QPoint &pos)
468 {
469  ui->groups_TableWidget->setSortingEnabled(false);
470  ui->groups_TableWidget->blockSignals(true);
471 
472  QTableWidgetItem *item = ui->groups_TableWidget->itemAt(pos);
473  if (!item)
474  {
475  return;
476  }
477 
478  const int row = item->row();
479  item = ui->groups_TableWidget->item(row, 0);
480  const quint32 groupId = item->data(Qt::UserRole).toUInt();
481 
482  const bool locked = m_doc->getGroupLock(groupId);
483  if (locked)
484  {
485  return;
486  }
487 
488  QScopedPointer<QMenu> menu(new QMenu());
489  QAction *actionRename = menu->addAction(QIcon("://icon/32x32/rename_32"), tr("Rename"));
490  QAction *actionDelete = menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete"));
491  QAction *selectedAction = menu->exec(ui->groups_TableWidget->viewport()->mapToGlobal(pos));
492  if(selectedAction == nullptr)
493  {
494  return;
495  }
496  else if (selectedAction == actionRename)
497  {
498  QString oldGroupName = m_doc->getGroupName(groupId);
499  QScopedPointer<EditGroupDialog> dialog(new EditGroupDialog(new VContainer(qApp->TrVars(),
500  qApp->patternUnitP()), NULL_ID, this));
501  dialog->setName(m_doc->getGroupName(groupId));
502  dialog->setColor(m_doc->getGroupColor(groupId));
503  dialog->setLineType(m_doc->getGroupLineType(groupId));
504  dialog->setLineWeight(m_doc->getGroupLineWeight(groupId));
505  dialog->setWindowTitle(tr("Edit Group"));
506 
507  QString groupName;
508  while (1)
509  {
510  const bool result = dialog->exec();
511  groupName = dialog->getName();
512  if (result == false || groupName.isEmpty())
513  {
514  return;
515  }
516  bool exists = m_doc->groupNameExists(groupName);
517  if (exists == false || groupName == oldGroupName)
518  {
519  break;
520  }
521 
522  QMessageBox messageBox;
523  messageBox.setWindowTitle(tr("Name Exists"));
524  messageBox.setIcon(QMessageBox::Warning);
525  messageBox.setStandardButtons(QMessageBox::Retry | QMessageBox::Cancel);
526  messageBox.setDefaultButton(QMessageBox::Retry);
527  messageBox.setText(tr("The action can't be completed because the group name already exists."));
528  int boxResult = messageBox.exec();
529 
530  switch (boxResult)
531  {
532  case QMessageBox::Retry:
533  break; // Repeat Add Group Dialog
534  case QMessageBox::Cancel:
535  return; // Exit Add Group Dialog
536  default:
537  break; // should never be reached
538  }
539  }
540 
541  const QString groupColor = dialog->getColor();
542  const QString groupLineType = dialog->getLineType();
543  const QString groupLineWeight = dialog->getLineWeight();
544 
545  item = ui->groups_TableWidget->item(row, 3);
546  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
547  item->setSizeHint(QSize(20, 20));
548  QPixmap pixmap(20, 20);
549  pixmap.fill(QColor(groupColor));
550  item->setIcon(QIcon(pixmap));
551  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
552  item->setToolTip(tr("Group color"));
553  ui->groups_TableWidget->setItem(row, 3, item);
554 
555  item = ui->groups_TableWidget->item(row, 4);
556  item->setText(groupName);
557  m_doc->setGroupName(groupId, groupName);
558  m_doc->setGroupColor(groupId, groupColor);
559  m_doc->setGroupLineType(groupId, groupLineType);
560  m_doc->setGroupLineWeight(groupId, groupLineWeight);
561  }
562  else if (selectedAction == actionDelete)
563  {
564  DelGroup *command = new DelGroup(m_doc, groupId);
565  connect(command, &DelGroup::updateGroups, this, &GroupsWidget::updateGroups);
566  qApp->getUndoStack()->push(command);
567  }
568 
569  ui->groups_TableWidget->setSortingEnabled(true);
570  ui->groups_TableWidget->blockSignals(false);
571 
572 }
573 
574 //---------------------------------------------------------------------------------------------------------------------
576 {
577  int row = ui->groups_TableWidget->currentRow();
579  if (ui->groups_TableWidget->rowCount() != 0 || row != -1 || row <= ui->groups_TableWidget->rowCount())
580  {
581  ui->groups_TableWidget->selectRow(row);
582  }
584 }
585 
586 //---------------------------------------------------------------------------------------------------------------------
588 {
589  ui->groups_TableWidget->blockSignals(true);
590  ui->groups_TableWidget->clear();
591  ui->groups_TableWidget->setColumnCount(5);
592  ui->groups_TableWidget->setRowCount(groups.size());
593  ui->groups_TableWidget->setSortingEnabled(false);
594 
595  qint32 currentRow = -1;
596  auto i = groups.constBegin();
597  while (i != groups.constEnd())
598  {
599  ++currentRow;
600  const GroupAttributes data = i.value();
601 
602  // Add visibility item
604  item->setTextAlignment(Qt::AlignHCenter);
605  item->setSizeHint(QSize(20, 20));
606 
607  setGroupVisibility(item, i.key(), data.visible);
608 
609  item->setData(Qt::UserRole, i.key());
610  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
611  item->setToolTip(tr("Show which groups in the list are visible"));
612  ui->groups_TableWidget->setItem(currentRow, 0, item);
613 
614  // Add locked item
615  item = new GroupTableWidgetItem(m_doc);
616  item->setTextAlignment(Qt::AlignHCenter);
617  item->setSizeHint(QSize(20, 20));
618  item->setIcon(data.locked ? QIcon("://icon/32x32/lock_on.png") : QIcon("://icon/32x32/lock_off.png"));
619  item->setData(Qt::UserRole, i.key());
620  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
621  item->setToolTip(tr("Show which groups in the list are locked"));
622  ui->groups_TableWidget->setItem(currentRow, 1, item);
623 
624  // Add contain objects Item
625  item = new GroupTableWidgetItem(m_doc);
626  item->setTextAlignment(Qt::AlignHCenter);
627  item->setIcon(!m_doc->isGroupEmpty(i.key()) ? QIcon("://icon/32x32/history.png") : QIcon());
628  item->setData(Qt::UserRole, i.key());
629  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
630  item->setToolTip(tr("Show which groups contain objects"));
631  ui->groups_TableWidget->setItem(currentRow, 2, item);
632 
633  // Add color item
634  item = new GroupTableWidgetItem(m_doc);
635  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
636  item->setSizeHint(QSize(20, 20));
637  QPixmap pixmap(20, 20);
638  pixmap.fill(QColor(data.color));
639  item->setIcon(QIcon(pixmap));
640  item->setData(Qt::UserRole, data.color);
641  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
642  item->setToolTip(tr("Group color"));
643  ui->groups_TableWidget->setItem(currentRow, 3, item);
644 
645  // Add group name item
646  QTableWidgetItem *nameItem = new QTableWidgetItem(data.name);
647  nameItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
648  nameItem->setToolTip(tr("Group name"));
649  ui->groups_TableWidget->setItem(currentRow, 4, nameItem);
650 
651  ++i;
652  }
653 
654  ui->groups_TableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem(makeHeaderName(QString("Visible"))));
655  ui->groups_TableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem(makeHeaderName(QString("Locked"))));
656  ui->groups_TableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem(makeHeaderName(QString("Objects"))));
657  ui->groups_TableWidget->setHorizontalHeaderItem(3, new QTableWidgetItem(makeHeaderName(QString("Color"))));
658  ui->groups_TableWidget->setHorizontalHeaderItem(4, new QTableWidgetItem(tr("Name")));
659  ui->groups_TableWidget->horizontalHeaderItem(4)->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
660  ui->groups_TableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
661  ui->groups_TableWidget->resizeColumnsToContents();
662  ui->groups_TableWidget->resizeRowsToContents();
663  ui->groups_TableWidget->setSortingEnabled(true);
664  ui->groups_TableWidget->blockSignals(false);
665 }
666 
668 {
669  m_patternHasGroups = value;
670 
671  ui->showAllGroups_ToolButton->setEnabled(value);
672  ui->hideAllGroups_ToolButton->setEnabled(value);
673  ui->lockAllGroups_ToolButton->setEnabled(value);
674  ui->unlockAllGroups_ToolButton->setEnabled(value);
675  ui->deleteGroup_ToolButton->setEnabled(value);
676  ui->editGroup_ToolButton->setEnabled(value);
677  qCDebug(WidgetGroups, "Draft Block Has Groups = %d", value);
678 }
679 
681 {
682  ui->addGroup_ToolButton->setEnabled(value);
683 }
684 
686 {
687  ui->groups_TableWidget->setRowCount(0);
688  ui->groups_TableWidget->clearContents();
689  ui->groupItems_ListWidget->clear();
690 }
691 
693 {
694  QTableWidgetItem *item = ui->groups_TableWidget->currentItem();
695  if (!item)
696  {
697  return 0;
698  }
699  int row = ui->groups_TableWidget->row(item);
700  qCDebug(WidgetGroups, "Row = %d\n", row);
701  const quint32 groupId = ui->groups_TableWidget->item(row, 0)->data(Qt::UserRole).toUInt();
702  return groupId;
703 }
704 
706 {
707  QTableWidgetItem *item = ui->groups_TableWidget->currentItem();
708  if (!item)
709  {
710  return QString();
711  }
712  int row = ui->groups_TableWidget->row(item);
713  qCDebug(WidgetGroups, "Row = %d\n", row);
714  const QString groupName = ui->groups_TableWidget->item(row, 4)->text();
715  return groupName;
716 }
717 
719 {
720  ui->groupItems_ListWidget->blockSignals(true);
721  ui->groupItems_ListWidget->clear();
722  QString groupName = getCurrentGroupName();
723  QDomElement groupDomElement = m_doc->getGroupByName(groupName);
724  if (groupDomElement.isNull())
725  {
726  return;
727  }
729  QPair<bool, QMap<quint32, quint32> > group = m_doc->parseItemElement(groupDomElement);
730  const QMap<quint32, quint32> groupData = group.second;
731  if (!groupData.isEmpty())
732  {
733  auto i = groupData.begin();
734  while (i != groupData.end())
735  {
736  quint32 toolId = i.value();
737  quint32 objId = i.key();
738  Tool tooltype = history.value(toolId);
739  addGroupItem(toolId, objId, tooltype);
740  ++i;
741  }
742  }
743  ui->groupItems_ListWidget->sortItems(Qt::AscendingOrder);
744  ui->groupItems_ListWidget->blockSignals(false);
745 }
746 
747 //---------------------------------------------------------------------------------------------------------------------
748 QT_WARNING_PUSH
749 QT_WARNING_DISABLE_GCC("-Wswitch-default")
750 /**
751  * @brief addGroupItem Add group item with description in listwidget.
752  * @param toolID ToolID of item to add to list.
753  * @param objId ObjectID of item to add to list.
754  * @param tooltype Tooltype of item to add to list.
755  */
756 void GroupsWidget::addGroupItem(const quint32 &toolId, const quint32 &objId, const Tool &tooltype)
757 {
758  // This check helps to find missing tools in the switch
759  Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 53, "Not all tools were used in history.");
760 
761  QString iconFileName = "";
762  QString objName = tr("Unknown Object");
763  const QDomElement domElement = m_doc->elementById(toolId);
764  if (domElement.isElement() == false)
765  {
766  qDebug()<<"Can't find element by id"<<Q_FUNC_INFO;
767  return;
768  }
769  try
770  {
771  switch ( tooltype )
772  {
773  case Tool::Arrow:
774  case Tool::SinglePoint:
775  case Tool::DoublePoint:
776  case Tool::LinePoint:
778  case Tool::Cut:
779  case Tool::Midpoint: // Same as Tool::AlongLine, but tool will never have such type
780  case Tool::ArcIntersectAxis: // Same as Tool::CurveIntersectAxis, but tool will never have such type
782  Q_UNREACHABLE(); //-V501
783  break;
784 
785  case Tool::BasePoint:
786  iconFileName = ":/toolicon/32x32/point_basepoint_icon.png";
787  objName = tr("%1 - Base point").arg(getPointName(toolId));
788  break;
789 
790  case Tool::EndLine:
791  iconFileName = ":/toolicon/32x32/segment.png";
792  objName = tr("%1 - Point Length and Angle").arg(getPointName(toolId));
793  break;
794 
795  case Tool::Line:
796  iconFileName = ":/toolicon/32x32/line.png";
797  objName = tr("Line %1_%2")
798  .arg(getPointName(attrUInt(domElement, AttrFirstPoint)))
799  .arg(getPointName(attrUInt(domElement, AttrSecondPoint)));
800  break;
801 
802  case Tool::AlongLine:
803  iconFileName = ":/toolicon/32x32/along_line.png";
804  objName = tr("%1 - Point On Line").arg(getPointName(toolId));
805  break;
806 
807  case Tool::ShoulderPoint:
808  iconFileName = ":/toolicon/32x32/shoulder.png";
809  objName = tr("%1 - Point Length to Line").arg(getPointName(toolId));
810  break;
811 
812  case Tool::Normal:
813  iconFileName = ":/toolicon/32x32/normal.png";
814  objName = tr("%1 - Point On Perpendicular").arg(getPointName(toolId));
815  break;
816 
817  case Tool::Bisector:
818  iconFileName = ":/toolicon/32x32/bisector.png";
819  objName = tr("%1 - Point On Bisector").arg(getPointName(toolId));
820  break;
821 
822  case Tool::LineIntersect:
823  iconFileName = ":/toolicon/32x32/intersect.png";
824  objName = tr("%1 - Point Intersect Lines").arg(getPointName(toolId));
825  break;
826 
827  case Tool::Spline:
828  {
829  const QSharedPointer<VSpline> spl = m_data->GeometricObject<VSpline>(toolId);
830  SCASSERT(!spl.isNull())
831  iconFileName = ":/toolicon/32x32/spline.png";
832  objName = tr("%1 - Curve Interactive").arg(spl->NameForHistory(tr("Spl_")));
833  break;
834  }
835 
836  case Tool::CubicBezier:
837  {
838  const QSharedPointer<VCubicBezier> spl = m_data->GeometricObject<VCubicBezier>(toolId);
839  SCASSERT(!spl.isNull())
840  iconFileName = ":/toolicon/32x32/cubic_bezier.png";
841  objName = tr("%1 - Curve Fixed").arg(spl->NameForHistory(tr("Spl_")));
842  break;
843  }
844 
845  case Tool::Arc:
846  {
847  const QSharedPointer<VArc> arc = m_data->GeometricObject<VArc>(toolId);
848  SCASSERT(!arc.isNull())
849  iconFileName = ":/toolicon/32x32/arc.png";
850  objName = tr("%1 - Arc Radius & Angles").arg(arc->NameForHistory(tr("Arc_")));
851  break;
852  }
853 
854  case Tool::ArcWithLength:
855  {
856  const QSharedPointer<VArc> arc = m_data->GeometricObject<VArc>(toolId);
857  SCASSERT(!arc.isNull())
858  iconFileName = ":/toolicon/32x32/arc_with_length.png";
859  objName = tr("%1 - Arc Radius & Length").arg(arc->NameForHistory(tr("Arc_")));
860  break;
861  }
862 
863  case Tool::SplinePath:
864  {
865  const QSharedPointer<VSplinePath> splPath = m_data->GeometricObject<VSplinePath>(toolId);
866  SCASSERT(!splPath.isNull())
867  iconFileName = ":/toolicon/32x32/splinePath.png";
868  objName = tr("%1 - Spline Interactive").arg(splPath->NameForHistory(tr("SplPath_")));
869  break;
870  }
871 
873  {
874  const QSharedPointer<VCubicBezierPath> splPath = m_data->GeometricObject<VCubicBezierPath>(toolId);
875  SCASSERT(!splPath.isNull())
876  iconFileName = ":/toolicon/32x32/cubic_bezier_path.png";
877  objName = tr("%1 - Spline Fixed").arg(splPath->NameForHistory(tr("SplPath_")));
878  break;
879  }
880 
882  iconFileName = ":/toolicon/32x32/point_of_contact.png";
883  objName = tr("%1 - Point Intersect Arc & Line").arg(getPointName(toolId));
884  break;
885 
886  case Tool::Height:
887  iconFileName = ":/toolicon/32x32/height.png";
888  objName = tr("%1 - Point Intersect Line & Perpendicular").arg(getPointName(toolId));
889  break;
890 
891  case Tool::Triangle:
892  iconFileName = ":/toolicon/32x32/triangle.png";
893  objName = tr("%1 - Point Intersect Axis & Triangle").arg(getPointName(toolId));
894  break;
895 
897  iconFileName = ":/toolicon/32x32/point_intersectxy_icon.png";
898  objName = tr("%1 - Point Intersect XY").arg(getPointName(toolId));
899  break;
900 
901  case Tool::CutArc:
902  {
903  const QSharedPointer<VArc> arc = m_data->GeometricObject<VArc>(attrUInt(domElement, AttrArc));
904  SCASSERT(!arc.isNull())
905  iconFileName = ":/toolicon/32x32/arc_cut.png";
906  objName = tr("%1 - Point On Arc").arg(getPointName(toolId));
907  break;
908  }
909 
910  case Tool::CutSpline:
911  {
912  const quint32 splineId = attrUInt(domElement, VToolCutSpline::AttrSpline);
914  m_data->GeometricObject<VAbstractCubicBezier>(splineId);
915  SCASSERT(!spl.isNull())
916  iconFileName = ":/toolicon/32x32/spline_cut_point.png";
917  objName = tr("%1 - Point On Curve").arg(getPointName(toolId));
918  break;
919  }
920 
921  case Tool::CutSplinePath:
922  {
923  const quint32 splinePathId = attrUInt(domElement, VToolCutSplinePath::AttrSplinePath);
925  m_data->GeometricObject<VAbstractCubicBezierPath>(splinePathId);
926  SCASSERT(!splPath.isNull())
927  iconFileName = ":/toolicon/32x32/splinePath_cut_point.png";
928  objName = tr("%1 - Point On Spline").arg(getPointName(toolId));
929  break;
930  }
931 
933  iconFileName = ":/toolicon/32x32/line_intersect_axis.png";
934  objName = tr("%1 - Point Intersect Line & Axis").arg(getPointName(toolId));
935  break;
936 
938  iconFileName = ":/toolicon/32x32/arc_intersect_axis.png";
939  objName = tr("%1 - Point Intersect Curve & Axis").arg(getPointName(toolId));
940  break;
941 
943  iconFileName = ":/toolicon/32x32/point_of_intersection_arcs.png";
944  objName = tr("%1 - Point Intersect Arcs").arg(getPointName(toolId));
945  break;
946 
948  iconFileName = ":/toolicon/32x32/point_of_intersection_circles.png";
949  objName = tr("%1 - Point Intersect Circles").arg(getPointName(toolId));
950  break;
951 
953  iconFileName = ":/toolicon/32x32/intersection_curves.png";
954  objName = tr("%1 - Point Intersect Curves").arg(getPointName(toolId));
955  break;
956 
958  iconFileName = ":/toolicon/32x32/point_from_circle_and_tangent.png";
959  objName = tr("%1 - Point Intersect Circle & Tangent").arg(getPointName(toolId));
960  break;
961 
963  iconFileName = ":/toolicon/32x32/point_from_arc_and_tangent.png";
964  objName = tr("%1 - Point Intersect Arc & Tangent").arg(getPointName(toolId));
965  break;
966 
967  case Tool::TrueDarts:
968  iconFileName = ":/toolicon/32x32/true_darts.png";
969  objName = tr("%1 - True Dart %2_%3_%4")
970  .arg(getObjName(objId))
971  .arg(getPointName(attrUInt(domElement, AttrDartP1)))
972  .arg(getPointName(attrUInt(domElement, AttrDartP2)))
973  .arg(getPointName(attrUInt(domElement, AttrDartP3)));
974  break;
975 
976  case Tool::EllipticalArc:
977  {
978  const QSharedPointer<VEllipticalArc> elArc = m_data->GeometricObject<VEllipticalArc>(toolId);
979  SCASSERT(!elArc.isNull())
980  iconFileName = ":/toolicon/32x32/el_arc.png";
981  objName = tr("%1 - Arc Elliptical").arg(elArc->NameForHistory(tr("ElArc_")));
982  break;
983  }
984 
985  case Tool::Rotation:
986  {
987  iconFileName = ":/toolicon/32x32/rotation.png";
988  objName = tr("%1 - Rotation")
989  .arg(getObjName(objId == NULL_ID ? toolId : objId));
990  break;
991  }
992 
993  case Tool::Move:
994  {
995  const QSharedPointer<VGObject> obj = m_data->GetGObject(objId);
996  iconFileName = ":/toolicon/32x32/move.png";
997  objName = tr("%1 - Move")
998  .arg(getObjName(objId == NULL_ID ? toolId : objId));
999  break;
1000  }
1001 
1002  case Tool::MirrorByLine:
1003  {
1004  const QSharedPointer<VGObject> obj = m_data->GetGObject(objId);
1005  iconFileName = ":/toolicon/32x32/mirror_by_line.png";
1006  objName = tr("%1 - Mirror by Line")
1007  .arg(getObjName(objId == NULL_ID ? toolId : objId));
1008  break;
1009  }
1010 
1011  case Tool::MirrorByAxis:
1012  {
1013  const QSharedPointer<VGObject> obj = m_data->GetGObject(objId);
1014  iconFileName = ":/toolicon/32x32/mirror_by_axis.png";
1015  objName = tr("%1 - Mirror by Axis")
1016  .arg(getObjName(objId == NULL_ID ? toolId : objId));
1017  break;
1018  }
1019 
1020  case Tool::Piece:
1021  case Tool::Union:
1022  case Tool::NodeArc:
1023  case Tool::NodeElArc:
1024  case Tool::NodePoint:
1025  case Tool::NodeSpline:
1026  case Tool::NodeSplinePath:
1027  case Tool::Group:
1028  case Tool::InternalPath:
1029  case Tool::AnchorPoint:
1030  case Tool::InsertNodes:
1031  return;
1032  }
1033  QList<quint32>itemData;
1034  itemData.append(objId);
1035  itemData.append(toolId);
1036 
1037  QListWidgetItem *item = new QListWidgetItem(objName);
1038  item->setIcon(QIcon(iconFileName));
1039  item->setData(Qt::UserRole, QVariant::fromValue(itemData));
1040  ui->groupItems_ListWidget->addItem(item);
1041  return;
1042  }
1043 
1044  catch (const VExceptionBadId &e)
1045  {
1046  QList<quint32>itemData;
1047  itemData.append(objId);
1048  itemData.append(toolId);
1049 
1050  qDebug()<<e.ErrorMessage()<<Q_FUNC_INFO;
1051  QListWidgetItem *item = new QListWidgetItem(objName);
1052  item->setIcon(QIcon(":/icons/win.icon.theme/16x16/status/dialog-warning.png"));
1053  item->setData(Qt::UserRole, QVariant::fromValue(itemData));
1054  ui->groupItems_ListWidget->addItem(item);
1055  return;
1056  }
1057 }
1058 
1060 
1061 //---------------------------------------------------------------------------------------------------------------------
1062 /**
1063  * @brief getPointName get the name of the point by tool id.
1064  * @param toolId Id of the tool the object belongs to.
1065  * @return name of point.
1066  */
1067 QString GroupsWidget::getPointName(quint32 toolId)
1068 {
1069  return m_data->GeometricObject<VPointF>(toolId)->name();
1070 }
1071 
1072 //---------------------------------------------------------------------------------------------------------------------
1073 /**
1074  * @brief attrUInt get unsigned integer attribute.
1075  * @param domElement Dom Element.
1076  * @param name Name of Attribute.
1077  * @return unsigned interger.
1078  */
1079 quint32 GroupsWidget::attrUInt(const QDomElement &domElement, const QString &name)
1080 {
1081  return m_doc->GetParametrUInt(domElement, name, "0");
1082 }
1083 
1084 //---------------------------------------------------------------------------------------------------------------------
1085 /**
1086  * @brief getObjName get the name of the graphics object.
1087  * @param toolId Id of the tool the object belongs to.
1088  * @return name of object.
1089  */
1090 QString GroupsWidget::getObjName(quint32 toolId)
1091 {
1092  try
1093  {
1094  const auto obj = m_data->GetGObject(toolId);
1095  return obj->name();
1096  }
1097  catch (const VExceptionBadId &e)
1098  {
1099  qCDebug(WidgetGroups, "Error! Couldn't get object name by id = %s. %s %s", qUtf8Printable(QString().setNum(toolId)),
1100  qUtf8Printable(e.ErrorMessage()),
1101  qUtf8Printable(e.DetailedInformation()));
1102  return QString("Unknown Object");// Return Unknown string
1103  }
1104 }
1105 
1106 //---------------------------------------------------------------------------------------------------------------------
1107 /**
1108  * @brief ContextMenu show context menu for group objects.
1109  * @param pos Mouse position of right click.
1110  */
1111  void GroupsWidget::groupItemContextMenu(const QPoint &pos)
1112 {
1113  const quint32 groupId = getGroupId();
1114  const int row = ui->groupItems_ListWidget->currentRow();
1115  if (ui->groupItems_ListWidget->count() == 0 || row == -1 || row >= ui->groupItems_ListWidget->count())
1116  {
1117  return;
1118  }
1119 
1120  QListWidgetItem *rowItem = ui->groupItems_ListWidget->item(row);
1121  SCASSERT(rowItem != nullptr);
1122  QList<quint32> itemData = rowItem->data(Qt::UserRole).value<QList<quint32>>();
1123  const quint32 toolId = itemData.last();
1124  const quint32 objId = itemData.first();
1125 
1126  QMenu menu;
1127  // Add Move Group Item menu
1128  QMap<quint32,QString> groupsNotContainingItem = m_doc->getGroupsContainingItem(toolId, objId, false);
1129  QActionGroup *actionMoveGroupMenu= new QActionGroup(this);
1130 
1131  if(!groupsNotContainingItem.empty())
1132  {
1133  QMenu *menuMoveGroupItem = menu.addMenu(QIcon("://icon/32x32/list-move_32.png"), tr("Move Group Object"));
1134  QStringList list = QStringList(groupsNotContainingItem.values());
1135  list.sort(Qt::CaseInsensitive);
1136 
1137  for(int i=0; i<list.count(); ++i)
1138  {
1139  QAction *actionMoveGroupItem = menuMoveGroupItem->addAction(list[i]);
1140  actionMoveGroupMenu->addAction(actionMoveGroupItem);
1141  const quint32 groupId = groupsNotContainingItem.key(list[i]);
1142  actionMoveGroupItem->setData(groupId);
1143  }
1144  }
1145  // Add Remove Group Item menu
1146  QAction *actionRemove = menu.addAction(QIcon::fromTheme("edit-delete"), tr("Remove Group Object"));
1147 
1148  QAction *selectedAction = menu.exec(ui->groupItems_ListWidget->viewport()->mapToGlobal(pos));
1149  if(selectedAction == nullptr)
1150  {
1151  return;
1152  }
1153  else if (selectedAction == actionRemove)
1154  {
1155  const bool locked = m_doc->getGroupLock(groupId);
1156  if (locked == false)
1157  {
1158  qCDebug(WidgetGroups, "Remove Tool %s from Group %s.",
1159  qUtf8Printable(QString().setNum(toolId)),
1160  qUtf8Printable(QString().setNum(groupId)));
1161 
1162  QListWidgetItem *rowItem = ui->groupItems_ListWidget->item(row);
1163  SCASSERT(rowItem != nullptr);
1164  QList<quint32> itemData = rowItem->data(Qt::UserRole).value<QList<quint32>>();
1165  delete ui->groupItems_ListWidget->item(row);
1166 
1167  QDomElement item = m_doc->removeGroupItem(itemData.last(), itemData.first(), groupId);
1168 
1169  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(qApp->getCurrentScene());
1170  SCASSERT(scene != nullptr)
1171  scene->clearSelection();
1172 
1173  VAbstractMainWindow *window = qobject_cast<VAbstractMainWindow *>(qApp->getMainWindow());
1174  SCASSERT(window != nullptr)
1175  {
1176  RemoveGroupItem *command = new RemoveGroupItem(item, m_doc, groupId);
1178  qApp->getUndoStack()->push(command);
1179  }
1180  }
1181  }
1182  else if (selectedAction->actionGroup() == actionMoveGroupMenu)
1183  {
1184  const quint32 destinationGroupId = selectedAction->data().toUInt();
1185  const bool sourceLock = m_doc->getGroupLock(groupId);
1186  const bool destinationLock = m_doc->getGroupLock(destinationGroupId);
1187  if ((sourceLock == false) && (destinationLock == false)) //only move if both groups are unlocked
1188  {
1189 
1190  qCDebug(WidgetGroups, "Move Tool %s from Group %s to Group %s.",
1191  qUtf8Printable(QString().setNum(toolId)),
1192  qUtf8Printable(QString().setNum(groupId)),
1193  qUtf8Printable(QString().setNum(destinationGroupId)));
1194 
1195  QListWidgetItem *rowItem = ui->groupItems_ListWidget->item(row);
1196  SCASSERT(rowItem != nullptr);
1197  QList<quint32> itemData = rowItem->data(Qt::UserRole).value<QList<quint32>>();
1198  delete ui->groupItems_ListWidget->item(row);
1199 
1200  QDomElement sourceItem = m_doc->removeGroupItem(itemData.last(), itemData.first(), groupId);
1201  QDomElement destItem = m_doc->addGroupItem(itemData.last(), itemData.first(), destinationGroupId);
1202 
1203  updateGroups();
1204 
1205  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(qApp->getCurrentScene());
1206  SCASSERT(scene != nullptr)
1207  scene->clearSelection();
1208 
1209  VAbstractMainWindow *window = qobject_cast<VAbstractMainWindow *>(qApp->getMainWindow());
1210  SCASSERT(window != nullptr)
1211  {
1212  MoveGroupItem *command = new MoveGroupItem(sourceItem, destItem, m_doc, groupId, destinationGroupId);
1214  qApp->getUndoStack()->push(command);
1215  }
1216  }
1217  }
1218 }
1219 
1220 //---------------------------------------------------------------------------------------------------------------------
1221 /**
1222  * @brief Handle double clicking of list item.
1223  * @param item selected list widget item.
1224  */
1225 void GroupsWidget::itemDoubleClicked(QListWidgetItem *item)
1226 {
1227  GOType objType;
1228  const auto objects = m_data->DataGObjects();
1229  QList<quint32> itemData = item->data(Qt::UserRole).value<QList<quint32>>();
1230  quint32 toolId = itemData.last();
1231  quint32 objId = itemData.first();
1232  if (objId != NULL_ID)
1233  {
1234  toolId = objId;
1235  }
1236 
1237  if (objects->contains(toolId))
1238  {
1239  objType = m_data->GetGObject(toolId)->getType();
1240  }
1241  else
1242  {
1243  //Some tools are not GObjects in the container. Need to look in the Dom Doc instead
1244  const QDomElement domElement = m_doc->elementById(toolId);
1245  if (domElement.tagName() == VAbstractPattern::TagLine)
1246  {
1247  //Use the line's FirstPoint as toolId and reset toolType
1248  toolId = attrUInt(domElement, AttrFirstPoint);
1249  }
1250  else
1251  {
1252  return;
1253  }
1254  objType = m_data->GetGObject(toolId)->getType();
1255  }
1256 
1257  switch(objType)
1258  {
1259  case GOType::Point:
1260  {
1262  zoomToObject(point);
1263  return;
1264  }
1265 
1266  case GOType::Arc:
1267  case GOType::EllipticalArc:
1268  {
1270  QSharedPointer<VPointF>point(new VPointF(curve->GetCenter()));
1271 
1272  zoomToObject(point);
1273  return;
1274  }
1275 
1276  case GOType::Spline:
1277  case GOType::SplinePath:
1278  case GOType::CubicBezier:
1280  {
1282  QSharedPointer<VPointF>point(new VPointF(curve->getFirstPoint()));
1283  zoomToObject(point);
1284  return;
1285  }
1286 
1287  case GOType::Unknown:
1288  case GOType::Curve:
1289  case GOType::Path:
1290  case GOType::AllCurves:
1291  default:
1292  break;
1293  }
1294 
1295  return;
1296 }
1297 
1298 //---------------------------------------------------------------------------------------------------------------------
1299 /**
1300  * @brief zoomToObject zoom to selected (point) object.
1301  * @param point If selected list item is a point use the item's toolId. if the list item is a curve or line then
1302  use the tool's first point.
1303  */
1305 {
1306  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(qApp->getCurrentScene());
1307  SCASSERT(scene != nullptr)
1308  scene->clearSelection();
1309 
1310  VMainGraphicsView *view = qobject_cast<VMainGraphicsView *>(scene->views().first());
1311  view->zoomByScale(1.3);
1312  view->centerOn(point->toQPointF());
1313 
1314  int row = ui->groups_TableWidget->currentRow();
1315  setGroupVisibility(ui->groups_TableWidget->item(row, 0), getGroupId(), true);
1316 
1317  // show point name if it's hidden
1318  quint32 toolId = point->getIdTool();
1319  const quint32 objectId = point->getIdObject();
1320  if (objectId != NULL_ID)
1321  {
1322  toolId = objectId;
1323  }
1324  if (toolId != NULL_ID)
1325  {
1326  if (VAbstractTool *tool = qobject_cast<VAbstractTool *>(VAbstractPattern::getTool(toolId)))
1327  {
1328  tool->setPointNameVisiblity(toolId, true);
1329  }
1330  }
1331 
1332  // show any hiden groups containing object
1333  showGroups(m_doc->getGroupsContainingItem(toolId, objectId, true));
1334 
1335  return;
1336 }
1337 
1338 void GroupsWidget::setGroupVisibility(QTableWidgetItem *item, const quint32 &groupId, const bool &visible)
1339 {
1340  m_doc->setGroupVisibility(groupId, visible);
1341  if (visible)
1342  {
1343  item->setIcon(QIcon("://icon/32x32/visible_on.png"));
1344  }
1345  else
1346  {
1347  item->setIcon(QIcon("://icon/32x32/visible_off.png"));
1348  }
1349 }
1350 
1351 //---------------------------------------------------------------------------------------------------------------------
1352 /**
1353  * @brief splitterMoved Save splitter state whenever it's moved.
1354  * @param pos
1355  * @param index
1356  */
1357 void GroupsWidget::splitterMoved(int pos, int index)
1358 {
1359  Q_UNUSED(pos)
1360  Q_UNUSED(index)
1361 
1362  QSettings settings;
1363  settings.setValue("splitterSizes", ui->groups_Splitter->saveState());
1364 }
1365 
1366 //---------------------------------------------------------------------------------------------------------------------
1367 /**
1368  * @brief headerClicked Sort state whenever header section clicked.
1369  * @param index
1370  */
1372 {
1373  QSettings settings;
1374  settings.setValue("groupSort", index);
1375 }
void updateGroups()
void updateGroups()
void renameGroup(int row, int column)
virtual ~GroupsWidget()
quint32 attrUInt(const QDomElement &domElement, const QString &name)
attrUInt get unsigned integer attribute.
void showGroups(QMap< quint32, QString > groups)
QString getPointName(quint32 pointId)
getPointName get the name of the point by tool id.
void draftBlockHasGroups(bool value)
VContainer * m_data
void groupItemContextMenu(const QPoint &pos)
ContextMenu show context menu for group objects.
void headerClicked(int index)
headerClicked Sort state whenever header section clicked.
void hideAllGroups()
quint32 getGroupId()
void fillTable(const QMap< quint32, GroupAttributes > &groups)
void groupVisibilityChanged(int row, int column)
void addGroupItem(const quint32 &toolId, const quint32 &objId, const Tool &tooltype)
addGroupItem Add group item with description in listwidget.
void showAllGroups()
void unlockAllGroups()
void setGroupVisibility(QTableWidgetItem *item, const quint32 &groupId, const bool &visible)
void zoomToObject(QSharedPointer< VPointF > point)
zoomToObject zoom to selected (point) object.
QString getObjName(quint32 id)
getObjName get the name of the graphics object.
bool m_patternHasGroups
void groupContextMenu(const QPoint &pos)
void fillGroupItemList()
void setAddGroupEnabled(bool value)
void splitterMoved(int pos, int index)
splitterMoved Save splitter state whenever it's moved.
void lockAllGroups()
void deleteGroupFromList()
Ui::GroupsWidget * ui
void addGroupToList()
VAbstractPattern * m_doc
void itemDoubleClicked(QListWidgetItem *item)
Handle double clicking of list item.
void groupLockChanged(int row, int column)
QString getCurrentGroupName()
void updateGroups()
virtual void updateGroups()=0
void setGroupLock(quint32 id, bool locked)
bool getGroupLock(quint32 id)
void setGroupColor(quint32 id, QString color)
QMap< quint32, GroupAttributes > getGroups()
void setGroupLineWeight(quint32 id, QString weight)
QDomElement removeGroupItem(quint32 toolId, quint32 objectId, quint32 groupId)
Removes the item of given toolId and objectId from the group of given groupId.
QDomElement getGroupByName(const QString &name)
QPair< bool, QMap< quint32, quint32 > > parseItemElement(const QDomElement &domElement)
bool isGroupEmpty(quint32 id)
Returns true if the given group is empty.
QDomElement addGroupItem(quint32 toolId, quint32 objectId, quint32 groupId)
Adds an item to the given group with the given toolId and objectId.
QString getGroupName(quint32 id)
QDomElement createGroup(quint32 id, const QString &name, const QString &color, const QString &type, const QString &weight, const QMap< quint32, quint32 > &groupData)
bool getGroupVisibility(quint32 id)
QString getGroupLineWeight(quint32 id)
static const QString TagLine
void setGroupName(quint32 id, const QString &name)
static VDataTool * getTool(quint32 id)
getTool return tool from tool list.
void setGroupLineType(quint32 id, QString type)
QString getGroupLineType(quint32 id)
QMap< quint32, Tool > getGroupObjHistory() const
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.
bool groupNameExists(const QString &groupName)
QString getGroupColor(quint32 id)
void setGroupVisibility(quint32 id, bool visible)
void patternHasGroups(bool value)
The VAbstractTool abstract class for all tools.
Definition: vabstracttool.h:80
VArc class for anticlockwise arc.
Definition: varc.h:74
The VContainer class container of all variables.
Definition: vcontainer.h:141
static quint32 getNextId()
getNextId generate next unique id
Definition: vcontainer.cpp:251
const QSharedPointer< VGObject > GetGObject(quint32 id) const
GetGObject returns a point by id.
Definition: vcontainer.cpp:150
const QSharedPointer< T > GeometricObject(const quint32 &id) const
Definition: vcontainer.h:266
const QHash< quint32, QSharedPointer< VGObject > > * DataGObjects() const
data container with datagObjects return container of gObjects
Definition: vcontainer.cpp:706
QDomElement elementById(quint32 id, const QString &tagName=QString())
static quint32 GetParametrUInt(const QDomElement &domElement, const QString &name, const QString &defValue)
Returns the long long value of the given attribute. RENAME: GetParameterLongLong?
The VExceptionBadId class for exception bad id.
virtual QString ErrorMessage() const Q_DECL_OVERRIDE
ErrorMessage return main error message.
virtual QString DetailedInformation() const
DetailedInformation return detailed information about error.
Definition: vexception.cpp:134
The VMainGraphicsScene class main scene.
The VMainGraphicsView class main scene view.
void zoomByScale(qreal scale)
The VPointF class keep data of point.
Definition: vpointf.h:75
The VSplinePath class keep information about splinePath.
Definition: vsplinepath.h:72
VSpline class that implements the spline.
Definition: vspline.h:75
static const QString AttrSplinePath
static const QString AttrSpline
QString makeHeaderName(const QString &name)
makeHeaderName make a 1 char tablewidgetitem header name based on a translated string.
Definition: def.cpp:401
#define SCASSERT(cond)
Definition: def.h:317
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
const QString splPath
Definition: ifcdef.cpp:419
const QString AttrSecondPoint
Definition: ifcdef.cpp:97
const QString AttrFirstPoint
Definition: ifcdef.cpp:96
const QString AttrDartP2
Definition: ifcdef.cpp:86
const QString AttrDartP1
Definition: ifcdef.cpp:85
const QString AttrDartP3
Definition: ifcdef.cpp:87
const QString AttrArc
Definition: ifcdef.cpp:146
#define NULL_ID
Definition: ifcdef.h:76
#define qApp
Definition: vapplication.h:67
GOType
Definition: vgeometrydef.h:56
@ CubicBezierPath
@ SplinePath
@ EllipticalArc
@ CubicBezier