1 /************************************************************************
2  **
3  **  @file   vdrawtool.h
4  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
5  **  @date   November 15, 2013
6  **
7  **  @brief
8  **  @copyright
9  **  This source code is part of the Valentina project, a pattern making
10  **  program, whose allow create and modeling patterns of clothing.
11  **  Copyright (C) 2013-2015 Valentina project
12  **  <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
13  **
14  **  Valentina is free software: you can redistribute it and/or modify
15  **  it under the terms of the GNU General Public License as published by
16  **  the Free Software Foundation, either version 3 of the License, or
17  **  (at your option) any later version.
18  **
19  **  Valentina is distributed in the hope that it will be useful,
20  **  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  **  GNU General Public License for more details.
23  **
24  **  You should have received a copy of the GNU General Public License
25  **  along with Valentina.  If not, see <http://www.gnu.org/licenses/>.
26  **
27  *************************************************************************/
28 
29 #ifndef VDRAWTOOL_H
30 #define VDRAWTOOL_H
31 
32 #include <qcompilerdetection.h>
33 #include <QAction>
34 #include <QByteArray>
35 #include <QColor>
36 #include <QDomElement>
37 #include <QGraphicsSceneContextMenuEvent>
38 #include <QIcon>
39 #include <QMenu>
40 #include <QMetaObject>
41 #include <QObject>
42 #include <QString>
43 #include <QtGlobal>
44 
45 #include "../ifc/exception/vexceptionbadid.h"
46 #include "../vinteractivetool.h"
47 #include "../vmisc/vabstractapplication.h"
48 #include "../vmisc/def.h"
49 #include "../vwidgets/vmaingraphicsscene.h"
50 #include "../vwidgets/vmaingraphicsview.h"
51 #include "../vwidgets/vabstractmainwindow.h"
52 #include "../vdatatool.h"
53 #include "../vgeometry/vpointf.h"
54 #include "../vtools/undocommands/undogroup.h"
55 #include "../toolsdef.h"
56 
57 struct VDrawToolInitData : VAbstractToolInitData
58 {
VDrawToolInitDataVDrawToolInitData59     VDrawToolInitData()
60         : VAbstractToolInitData(),
61         notes()
62     {}
63 
64     QString notes;
65 };
66 
67 /**
68  * @brief The VDrawTool abstract class for all draw tool.
69  */
70 class VDrawTool : public VInteractiveTool
71 {
72     Q_OBJECT
73 public:
74 
75     VDrawTool(VAbstractPattern *doc, VContainer *data, quint32 id, const QString &notes, QObject *parent = nullptr);
76     virtual ~VDrawTool() Q_DECL_EQ_DEFAULT;
77 
78     QString      getLineType() const;
79     virtual void SetLineType(const QString &value);
80 
81     virtual bool IsLabelVisible(quint32 id) const;
82 
83     QString      GetNotes() const;
84     virtual void SetNotes(const QString &notes);
85 
86 signals:
87     void ChangedToolSelection(bool selected, quint32 object, quint32 tool);
88 
89 public slots:
90     virtual void ShowTool(quint32 id, bool enable);
91     virtual void ChangedActivDraw(const QString &newName);
92     void         ChangedNameDraw(const QString &oldName, const QString &newName);
93     virtual void EnableToolMove(bool move);
94     virtual void Disable(bool disable, const QString &namePP)=0;
95     virtual void DetailsMode(bool mode);
96 protected slots:
97     virtual void ShowContextMenu(QGraphicsSceneContextMenuEvent *event, quint32 id=NULL_ID)=0;
98 protected:
99 
100     enum class RemoveOption : bool {Disable = false, Enable = true};
101     enum class Referens : bool {Follow = true, Ignore = false};
102 
103     /** @brief nameActivDraw name of tool's pattern peace. */
104     QString      nameActivDraw;
105 
106     /** @brief typeLine line type. */
107     QString      m_lineType;
108 
109     QString      m_notes{};
110 
111     void AddToCalculation(const QDomElement &domElement);
112     void AddDependence(QList<quint32> &list, quint32 objectId) const;
113 
114     /** @brief SaveDialog save options into file after change in dialog. */
115     virtual void    SaveDialog(QDomElement &domElement, QList<quint32> &oldDependencies,
116                                QList<quint32> &newDependencies)=0;
117     virtual void    SaveDialogChange(const QString &undoText = QString()) final;
118     virtual void    ApplyToolOptions(const QList<quint32> &oldDependencies, const QList<quint32> &newDependencies,
119                                      const QDomElement &oldDomElement, const QDomElement &newDomElement);
120     virtual void    AddToFile() override;
121     void            SaveOption(QSharedPointer<VGObject> &obj);
122     virtual void    SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj);
123     virtual QString MakeToolTip() const;
124     virtual void    UpdateNamePosition(quint32 id, const QPointF &pos);
125 
126     bool         CorrectDisable(bool disable, const QString &namePP) const;
127 
128     void         ReadAttributes();
129     virtual void ReadToolAttributes(const QDomElement &domElement);
130     virtual void ChangeLabelVisibility(quint32 id, bool visible);
131 
132     template <class Dialog>
133     void ContextMenu(QGraphicsSceneContextMenuEvent *event, quint32 itemId = NULL_ID,
134                      const RemoveOption &showRemove = RemoveOption::Enable,
135                      const Referens &ref = Referens::Follow);
136 
137     template <class Item>
138     void ShowItem(Item *item, quint32 id, bool enable);
139 
140     template <class T>
141     QString ObjectName(quint32 id) const;
142 
143     template <class T>
144     QString ObjectAliasSuffix(quint32 id) const;
145 
146     template <class T>
147     static void InitDrawToolConnections(VMainGraphicsScene *scene, T *tool);
148 private:
149     Q_DISABLE_COPY(VDrawTool)
150 };
151 
152 //---------------------------------------------------------------------------------------------------------------------
153 template <class Dialog>
154 /**
155  * @brief ContextMenu show context menu for tool.
156  * @param event context menu event.
157  * @param itemId id of point. 0 if not a point
158  * @param showRemove true - tool enable option delete.
159  * @param ref true - do not ignore referens value.
160  */
ContextMenu(QGraphicsSceneContextMenuEvent * event,quint32 itemId,const RemoveOption & showRemove,const Referens & ref)161 void VDrawTool::ContextMenu(QGraphicsSceneContextMenuEvent *event, quint32 itemId, const RemoveOption &showRemove,
162                             const Referens &ref)
163 {
164     SCASSERT(event != nullptr)
165 
166     if (m_suppressContextMenu)
167     {
168         return;
169     }
170 
171     GOType itemType =  GOType::Unknown;
172     if(itemId != NULL_ID)
173     {
174         try
175         {
176             itemType = data.GetGObject(itemId)->getType();
177         }
178         catch (const VExceptionBadId &e)
179         { // Possible case. Parent was deleted, but the node object is still here.
180             qWarning() << qUtf8Printable(e.ErrorMessage());
181         }
182     }
183 
184     qCDebug(vTool, "Creating tool context menu.");
185     QMenu menu;
186     QAction *actionOption = menu.addAction(QIcon::fromTheme(QStringLiteral("preferences-other")),
187                                            VDrawTool::tr("Options"));
188 
189     // add the menu "add to group" to the context menu
190     QMap<quint32,QString> groupsNotContainingItem =  doc->GetGroupsContainingItem(this->getId(), itemId, false);
191     QActionGroup* actionsAddToGroup = new QActionGroup(this);
192     if(not groupsNotContainingItem.empty())
193     {
194         QMenu *menuAddToGroup = menu.addMenu(QIcon::fromTheme(QStringLiteral("list-add")),
195                                              VDrawTool::tr("Add to group"));
196 
197         QStringList list = QStringList(groupsNotContainingItem.values());
198         list.sort(Qt::CaseInsensitive);
199 
200         for(int i=0; i<list.count(); ++i)
201         {
202             QAction *actionAddToGroup = menuAddToGroup->addAction(list[i]);
203             actionsAddToGroup->addAction(actionAddToGroup);
204             const quint32 groupId = groupsNotContainingItem.key(list[i]);
205             actionAddToGroup->setData(groupId);
206 
207             // removes the group we just treated, because we can have several group
208             // with the same name. Otherwise the groupId would always be the same
209             groupsNotContainingItem.remove(groupId);
210         }
211     }
212 
213     // add the menu "remove from group" to the context menu
214     QMap<quint32,QString> groupsContainingItem =  doc->GetGroupsContainingItem(this->getId(), itemId, true);
215     QActionGroup* actionsRemoveFromGroup = new QActionGroup(this);
216     if(not groupsContainingItem.empty())
217     {
218         QMenu *menuRemoveFromGroup = menu.addMenu(QIcon::fromTheme(QStringLiteral("list-remove")),
219                                                   VDrawTool::tr("Remove from group"));
220 
221         QStringList list = QStringList(groupsContainingItem.values());
222         list.sort(Qt::CaseInsensitive);
223 
224         for(int i=0; i<list.count(); ++i)
225         {
226             QAction *actionRemoveFromGroup = menuRemoveFromGroup->addAction(list[i]);
227             actionsRemoveFromGroup->addAction(actionRemoveFromGroup);
228             const quint32 groupId = groupsContainingItem.key(list[i]);
229             actionRemoveFromGroup->setData(groupId);
230             groupsContainingItem.remove(groupId);
231         }
232     }
233 
234     QAction *actionShowLabel = menu.addAction(VDrawTool::tr("Show label"));
235     actionShowLabel->setCheckable(true);
236 
237     if (itemType == GOType::Point)
238     {
239         actionShowLabel->setChecked(IsLabelVisible(itemId));
240     }
241     else
242     {
243        actionShowLabel->setVisible(false);
244     }
245 
246     QAction *actionRestoreLabelPosition = menu.addAction(VDrawTool::tr("Restore label position"));
247     actionRestoreLabelPosition->setVisible(itemType == GOType::Point);
248 
249     QAction *actionRemove = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), VDrawTool::tr("Delete"));
250     if (showRemove == RemoveOption::Enable)
251     {
252         if (ref == Referens::Follow)
253         {
254             if (_referens > 0)
255             {
256                 qCDebug(vTool, "Remove disabled. Tool has childern.");
257                 actionRemove->setEnabled(false);
258             }
259             else
260             {
261                 qCDebug(vTool, "Remove enabled. Tool has not childern.");
262                 actionRemove->setEnabled(true);
263             }
264         }
265         else
266         {
267             qCDebug(vTool, "Remove enabled. Ignore referens value.");
268             actionRemove->setEnabled(true);
269         }
270     }
271     else
272     {
273         qCDebug(vTool, "Remove disabled.");
274         actionRemove->setEnabled(false);
275     }
276 
277     QAction *selectedAction = menu.exec(event->screenPos());
278 
279     if(selectedAction == nullptr)
280     {
281         return;
282     }
283     else if (selectedAction == actionOption)
284     {
285         qCDebug(vTool, "Show options.");
286         emit VAbstractValApplication::VApp()->getSceneView()->itemClicked(nullptr);
287         m_dialog = QPointer<Dialog>(new Dialog(getData(), m_id, VAbstractValApplication::VApp()->getMainWindow()));
288         m_dialog->setModal(true);
289 
290         connect(m_dialog.data(), &DialogTool::DialogClosed, this, &VDrawTool::FullUpdateFromGuiOk);
291         connect(m_dialog.data(), &DialogTool::DialogApplied, this, &VDrawTool::FullUpdateFromGuiApply);
292 
293         this->setDialog();
294 
295         m_dialog->show();
296     }
297     else if (selectedAction == actionRemove)
298     {
299         qCDebug(vTool, "Deleting tool.");
300         DeleteToolWithConfirm(); // do not catch exception here
301         return; //Leave this method immediately after call!!!
302     }
303     else if (selectedAction == actionShowLabel)
304     {
305         ChangeLabelVisibility(itemId, selectedAction->isChecked());
306     }
307     else if (selectedAction == actionRestoreLabelPosition)
308     {
309         UpdateNamePosition(itemId, QPointF(labelMX, labelMY));
310     }
311     else if (selectedAction->actionGroup() == actionsAddToGroup)
312     {
313         quint32 groupId = selectedAction->data().toUInt();
314         QDomElement item = doc->AddItemToGroup(this->getId(), itemId, groupId);
315 
316         VMainGraphicsScene *scene =
317                 qobject_cast<VMainGraphicsScene *>(VAbstractValApplication::VApp()->getCurrentScene());
318         SCASSERT(scene != nullptr)
319         scene->clearSelection();
320 
321         VAbstractMainWindow *window =
322                 qobject_cast<VAbstractMainWindow *>(VAbstractValApplication::VApp()->getMainWindow());
323         SCASSERT(window != nullptr)
324         {
325             AddItemToGroup *addItemToGroup = new AddItemToGroup(item, doc, groupId);
326             connect(addItemToGroup, &AddItemToGroup::UpdateGroups, window,
327                     &VAbstractMainWindow::UpdateVisibilityGroups);
328             VAbstractApplication::VApp()->getUndoStack()->push(addItemToGroup);
329         }
330     }
331     else if (selectedAction->actionGroup() == actionsRemoveFromGroup)
332     {
333         quint32 groupId = selectedAction->data().toUInt();
334         QDomElement item = doc->RemoveItemFromGroup(this->getId(), itemId, groupId);
335 
336         VAbstractMainWindow *window =
337                 qobject_cast<VAbstractMainWindow *>(VAbstractValApplication::VApp()->getMainWindow());
338         SCASSERT(window != nullptr)
339         {
340             RemoveItemFromGroup *removeItemFromGroup = new RemoveItemFromGroup(item, doc, groupId);
341             connect(removeItemFromGroup, &RemoveItemFromGroup::UpdateGroups, window,
342                     &VAbstractMainWindow::UpdateVisibilityGroups);
343             VAbstractApplication::VApp()->getUndoStack()->push(removeItemFromGroup);
344         }
345     }
346 }
347 
348 //---------------------------------------------------------------------------------------------------------------------
349 template <class Item>
350 /**
351  * @brief ShowItem highlight tool.
352  * @param item tool.
353  * @param id object id in container.
354  * @param enable enable or disable highlight.
355  */
ShowItem(Item * item,quint32 id,bool enable)356 void VDrawTool::ShowItem(Item *item, quint32 id, bool enable)
357 {
358     SCASSERT(item != nullptr)
359     if (id == item->m_id)
360     {
361         ShowVisualization(enable);
362     }
363 }
364 
365 //---------------------------------------------------------------------------------------------------------------------
366 template <class T>
367 /**
368  * @brief ObjectName get object (point, curve, arc) name.
369  * @param id object id in container.
370  */
ObjectName(quint32 id)371 QString VDrawTool::ObjectName(quint32 id) const
372 {
373     try
374     {
375         return data.GeometricObject<T>(id)->ObjectName();
376     }
377     catch (const VExceptionBadId &e)
378     {
379         qCDebug(vTool, "Error! Couldn't get object name by id = %s. %s %s", qUtf8Printable(QString().setNum(id)),
380                 qUtf8Printable(e.ErrorMessage()),
381                 qUtf8Printable(e.DetailedInformation()));
382         return QString();// Return empty string for property browser
383     }
384 }
385 
386 //---------------------------------------------------------------------------------------------------------------------
387 template <class T>
388 /**
389  * @brief ObjectAlias get object (point, curve, arc) alias.
390  * @param id object id in container.
391  */
ObjectAliasSuffix(quint32 id)392 QString VDrawTool::ObjectAliasSuffix(quint32 id) const
393 {
394     try
395     {
396         return data.GeometricObject<T>(id)->GetAliasSuffix();
397     }
398     catch (const VExceptionBadId &e)
399     {
400         qCDebug(vTool, "Error! Couldn't get object alias suffix by id = %s. %s %s", qUtf8Printable(QString().setNum(id)),
401                 qUtf8Printable(e.ErrorMessage()),
402                 qUtf8Printable(e.DetailedInformation()));
403         return QString();// Return empty string for property browser
404     }
405 }
406 
407 //---------------------------------------------------------------------------------------------------------------------
408 template <class T>
InitDrawToolConnections(VMainGraphicsScene * scene,T * tool)409 void VDrawTool::InitDrawToolConnections(VMainGraphicsScene *scene, T *tool)
410 {
411     SCASSERT(scene != nullptr)
412     SCASSERT(tool != nullptr)
413 
414     QObject::connect(tool, &T::ChoosedTool, scene, &VMainGraphicsScene::ChoosedItem);
415     QObject::connect(tool, &T::ChangedToolSelection, scene, &VMainGraphicsScene::SelectedItem);
416     QObject::connect(scene, &VMainGraphicsScene::DisableItem, tool, &T::Disable);
417     QObject::connect(scene, &VMainGraphicsScene::EnableToolMove, tool, &T::EnableToolMove);
418     QObject::connect(scene, &VMainGraphicsScene::CurveDetailsMode, tool, &T::DetailsMode);
419     QObject::connect(scene, &VMainGraphicsScene::ItemSelection, tool, &T::ToolSelectionType);
420 }
421 
422 #endif // VDRAWTOOL_H
423