1 /************************************************************************
2  **
3  **  @file   vtoolsinglepoint.cpp
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 #include "vtoolbasepoint.h"
30 
31 #include <QApplication>
32 #include <QEvent>
33 #include <QFlags>
34 #include <QGraphicsLineItem>
35 #include <QGraphicsScene>
36 #include <QGraphicsSceneMouseEvent>
37 #include <QGraphicsView>
38 #include <QList>
39 #include <QMessageBox>
40 #include <QPen>
41 #include <QPointF>
42 #include <QPolygonF>
43 #include <QRectF>
44 #include <QSharedPointer>
45 #include <QStaticStringData>
46 #include <QStringData>
47 #include <QStringDataPtr>
48 #include <QUndoStack>
49 #include <new>
50 
51 #include "../../../../dialogs/tools/dialogtool.h"
52 #include "../../../../dialogs/tools/dialogsinglepoint.h"
53 #include "../../../../undocommands/addpatternpiece.h"
54 #include "../../../../undocommands/deletepatternpiece.h"
55 #include "../../../../undocommands/movespoint.h"
56 #include "../ifc/exception/vexception.h"
57 #include "../ifc/ifcdef.h"
58 #include "../vgeometry/vgobject.h"
59 #include "../vgeometry/vpointf.h"
60 #include "../vmisc/vabstractapplication.h"
61 #include "../vpatterndb/vcontainer.h"
62 #include "../vwidgets/vgraphicssimpletextitem.h"
63 #include "../vwidgets/vmaingraphicsscene.h"
64 #include "../vwidgets/vmaingraphicsview.h"
65 #include "../../../vabstracttool.h"
66 #include "../../../vdatatool.h"
67 #include "../../vdrawtool.h"
68 #include "vtoolsinglepoint.h"
69 
70 const QString VToolBasePoint::ToolType = QStringLiteral("single");
71 
72 //---------------------------------------------------------------------------------------------------------------------
73 /**
74  * @brief VToolBasePoint constructor.
75  * @param initData init data.
76  * @param parent parent object.
77  */
VToolBasePoint(const VToolBasePointInitData & initData,QGraphicsItem * parent)78 VToolBasePoint::VToolBasePoint (const VToolBasePointInitData &initData, QGraphicsItem * parent )
79     :VToolSinglePoint(initData.doc, initData.data, initData.id, initData.notes, parent),
80      namePP(initData.nameActivPP)
81 {
82     m_baseColor = Qt::red;
83     this->setFlag(QGraphicsItem::ItemIsMovable, true);
84     this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
85     m_namePoint->setBrush(Qt::black);
86     ToolCreation(initData.typeCreation);
87 }
88 
89 //---------------------------------------------------------------------------------------------------------------------
90 /**
91  * @brief setDialog set dialog when user want change tool option.
92  */
setDialog()93 void VToolBasePoint::setDialog()
94 {
95     SCASSERT(not m_dialog.isNull())
96     const QPointer<DialogSinglePoint> dialogTool = qobject_cast<DialogSinglePoint *>(m_dialog);
97     SCASSERT(not dialogTool.isNull())
98     const QSharedPointer<VPointF> p = VAbstractTool::data.GeometricObject<VPointF>(m_id);
99     dialogTool->SetData(p->name(), static_cast<QPointF>(*p));
100     dialogTool->SetNotes(m_notes);
101 }
102 
103 //---------------------------------------------------------------------------------------------------------------------
Create(VToolBasePointInitData initData)104 VToolBasePoint *VToolBasePoint::Create(VToolBasePointInitData initData)
105 {
106     VPointF *point = new VPointF(initData.x, initData.y, initData.name, initData.mx, initData.my);
107     point->SetShowLabel(initData.showLabel);
108 
109     if (initData.typeCreation == Source::FromGui)
110     {
111         initData.id = initData.data->AddGObject(point);
112     }
113     else
114     {
115         initData.data->UpdateGObject(initData.id, point);
116         if (initData.parse != Document::FullParse)
117         {
118             initData.doc->UpdateToolData(initData.id, initData.data);
119         }
120     }
121 
122     if (initData.parse == Document::FullParse)
123     {
124         VAbstractTool::AddRecord(initData.id, Tool::BasePoint, initData.doc);
125         VToolBasePoint *spoint = new VToolBasePoint(initData);
126         initData.scene->addItem(spoint);
127         InitToolConnections(initData.scene, spoint);
128         VAbstractPattern::AddTool(initData.id, spoint);
129         return spoint;
130     }
131     return nullptr;
132 }
133 
134 //---------------------------------------------------------------------------------------------------------------------
ShowVisualization(bool show)135 void VToolBasePoint::ShowVisualization(bool show)
136 {
137     Q_UNUSED(show) //don't have any visualization for base point yet
138 }
139 
140 //---------------------------------------------------------------------------------------------------------------------
141 /**
142  * @brief AddToFile add tag with informations about tool into file.
143  */
AddToFile()144 void VToolBasePoint::AddToFile()
145 {
146     Q_ASSERT_X(not namePP.isEmpty(), Q_FUNC_INFO, "name pattern piece is empty");
147 
148     QDomElement sPoint = doc->createElement(getTagName());
149 
150     // Create SPoint tag
151     QSharedPointer<VGObject> obj = VAbstractTool::data.GetGObject(m_id);
152     SaveOptions(sPoint, obj);
153 
154     //Create pattern piece structure
155     QDomElement patternPiece = doc->createElement(VAbstractPattern::TagDraw);
156     doc->SetAttribute(patternPiece, AttrName, namePP);
157 
158     QDomElement calcElement = doc->createElement(VAbstractPattern::TagCalculation);
159     calcElement.appendChild(sPoint);
160 
161     patternPiece.appendChild(calcElement);
162     patternPiece.appendChild(doc->createElement(VAbstractPattern::TagModeling));
163     patternPiece.appendChild(doc->createElement(VAbstractPattern::TagDetails));
164 
165     AddPatternPiece *addPP = new AddPatternPiece(patternPiece, doc, namePP);
166     connect(addPP, &AddPatternPiece::ClearScene, doc, &VAbstractPattern::ClearScene);
167     connect(addPP, &AddPatternPiece::NeedFullParsing, doc, &VAbstractPattern::NeedFullParsing);
168     VAbstractApplication::VApp()->getUndoStack()->push(addPP);
169 }
170 
171 //---------------------------------------------------------------------------------------------------------------------
172 /**
173  * @brief itemChange handle tool change.
174  * @param change change.
175  * @param value value.
176  * @return value.
177  */
itemChange(QGraphicsItem::GraphicsItemChange change,const QVariant & value)178 QVariant VToolBasePoint::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
179 {
180     if (change == ItemPositionChange && scene())
181     {
182         // Each time we move something we call recalculation scene rect. In some cases this can cause moving
183         // objects positions. And this cause infinite redrawing. That's why we wait the finish of saving the last move.
184         static bool changeFinished = true;
185         if (changeFinished)
186         {
187             changeFinished = false;
188             // value - this is new position.
189             QPointF newPos = value.toPointF();
190 
191             MoveSPoint *moveSP = new MoveSPoint(doc, newPos.x(), newPos.y(), m_id, this->scene());
192             connect(moveSP, &MoveSPoint::NeedLiteParsing, doc, &VAbstractPattern::LiteParseTree);
193             VAbstractApplication::VApp()->getUndoStack()->push(moveSP);
194             const QList<QGraphicsView *> viewList = scene()->views();
195             if (not viewList.isEmpty())
196             {
197                 if (VMainGraphicsView *view = qobject_cast<VMainGraphicsView *>(viewList.at(0)))
198                 {
199                     view->EnsureItemVisibleWithDelay(this, VMainGraphicsView::scrollDelay);
200                 }
201             }
202             changeFinished = true;
203         }
204     }
205     return VToolSinglePoint::itemChange(change, value);
206 }
207 
208 //---------------------------------------------------------------------------------------------------------------------
GetBasePointPos() const209 QPointF VToolBasePoint::GetBasePointPos() const
210 {
211     const QSharedPointer<VPointF> p = VAbstractTool::data.GeometricObject<VPointF>(m_id);
212     QPointF pos(VAbstractValApplication::VApp()->fromPixel(p->x()), VAbstractValApplication::VApp()->fromPixel(p->y()));
213     return pos;
214 }
215 
216 //---------------------------------------------------------------------------------------------------------------------
SetBasePointPos(const QPointF & pos)217 void VToolBasePoint::SetBasePointPos(const QPointF &pos)
218 {
219     QSharedPointer<VPointF> p = VAbstractTool::data.GeometricObject<VPointF>(m_id);
220     p->setX(VAbstractValApplication::VApp()->toPixel(pos.x()));
221     p->setY(VAbstractValApplication::VApp()->toPixel(pos.y()));
222 
223     QSharedPointer<VGObject> obj = qSharedPointerCast<VGObject>(p);
224 
225     SaveOption(obj);
226 }
227 
228 //---------------------------------------------------------------------------------------------------------------------
DeleteToolWithConfirm(bool ask)229 void VToolBasePoint::DeleteToolWithConfirm(bool ask)
230 {
231     if (doc->CountPP() <= 1)
232     {
233         return;
234     }
235 
236     qCDebug(vTool, "Deleting base point.");
237     emit VAbstractValApplication::VApp()->getSceneView()->itemClicked(nullptr);
238     if (ask)
239     {
240         qCDebug(vTool, "Asking.");
241         if (ConfirmDeletion() == QMessageBox::No)
242         {
243             qCDebug(vTool, "User said no.");
244             return;
245         }
246     }
247 
248     qCDebug(vTool, "Begin deleting.");
249     DeletePatternPiece *deletePP = new DeletePatternPiece(doc, nameActivDraw);
250     connect(deletePP, &DeletePatternPiece::NeedFullParsing, doc, &VAbstractPattern::NeedFullParsing);
251     VAbstractApplication::VApp()->getUndoStack()->push(deletePP);
252 
253     // Throw exception, this will help prevent case when we forget to immediately quit function.
254     VExceptionToolWasDeleted e("Tool was used after deleting.");
255     throw e;
256 }
257 
258 //---------------------------------------------------------------------------------------------------------------------
259 /**
260  * @brief SaveDialog save options into file after change in dialog.
261  */
SaveDialog(QDomElement & domElement,QList<quint32> & oldDependencies,QList<quint32> & newDependencies)262 void VToolBasePoint::SaveDialog(QDomElement &domElement, QList<quint32> &oldDependencies,
263                                 QList<quint32> &newDependencies)
264 {
265     SCASSERT(not m_dialog.isNull())
266     const QPointer<DialogSinglePoint> dialogTool = qobject_cast<DialogSinglePoint *>(m_dialog);
267     SCASSERT(not dialogTool.isNull())
268 
269     Q_UNUSED(oldDependencies)
270     Q_UNUSED(newDependencies)
271 
272     const QPointF p = dialogTool->GetPoint();
273     const QString name = dialogTool->GetPointName();
274     doc->SetAttribute(domElement, AttrName, name);
275     doc->SetAttribute(domElement, AttrX, QString().setNum(VAbstractValApplication::VApp()->fromPixel(p.x())));
276     doc->SetAttribute(domElement, AttrY, QString().setNum(VAbstractValApplication::VApp()->fromPixel(p.y())));
277 
278     const QString notes = dialogTool->GetNotes();
279     doc->SetAttributeOrRemoveIf(domElement, AttrNotes, notes, notes.isEmpty());
280 }
281 
282 //---------------------------------------------------------------------------------------------------------------------
hoverEnterEvent(QGraphicsSceneHoverEvent * event)283 void VToolBasePoint::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
284 {
285     VToolSinglePoint::hoverEnterEvent(event);
286 
287     if (flags() & QGraphicsItem::ItemIsMovable)
288     {
289         SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
290     }
291 }
292 
293 //---------------------------------------------------------------------------------------------------------------------
mousePressEvent(QGraphicsSceneMouseEvent * event)294 void VToolBasePoint::mousePressEvent(QGraphicsSceneMouseEvent *event)
295 {
296     if (flags() & QGraphicsItem::ItemIsMovable)
297     {
298         if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
299         {
300             SetItemOverrideCursor(this, cursorArrowCloseHand, 1, 1);
301             event->accept();
302         }
303     }
304     VToolSinglePoint::mousePressEvent(event);
305 }
306 
307 //---------------------------------------------------------------------------------------------------------------------
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)308 void VToolBasePoint::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
309 {
310     if (flags() & QGraphicsItem::ItemIsMovable)
311     {
312         if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
313         {
314             SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
315         }
316     }
317     VToolSinglePoint::mouseReleaseEvent(event);
318 }
319 
320 //---------------------------------------------------------------------------------------------------------------------
SaveOptions(QDomElement & tag,QSharedPointer<VGObject> & obj)321 void VToolBasePoint::SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj)
322 {
323     VToolSinglePoint::SaveOptions(tag, obj);
324 
325     QSharedPointer<VPointF> point = qSharedPointerDynamicCast<VPointF>(obj);
326     SCASSERT(point.isNull() == false)
327 
328     doc->SetAttribute(tag, AttrType, ToolType);
329     doc->SetAttribute(tag, AttrX, VAbstractValApplication::VApp()->fromPixel(point->x()));
330     doc->SetAttribute(tag, AttrY, VAbstractValApplication::VApp()->fromPixel(point->y()));
331 }
332 
333 //---------------------------------------------------------------------------------------------------------------------
MakeToolTip() const334 QString VToolBasePoint::MakeToolTip() const
335 {
336     const QSharedPointer<VPointF> point = VAbstractTool::data.GeometricObject<VPointF>(m_id);
337 
338     const QString toolTip = QString("<table>"
339                                     "<tr> <td><b>%1:</b> %2</td> </tr>"
340                                     "</table>")
341             .arg(tr("Label"), point->name());
342     return toolTip;
343 }
344 
345 //---------------------------------------------------------------------------------------------------------------------
ShowContextMenu(QGraphicsSceneContextMenuEvent * event,quint32 id)346 void VToolBasePoint::ShowContextMenu(QGraphicsSceneContextMenuEvent *event, quint32 id)
347 {
348     qCDebug(vTool, "Context menu base point");
349 #ifndef QT_NO_CURSOR
350     QGuiApplication::restoreOverrideCursor();
351     qCDebug(vTool, "Restored overriden cursor");
352 #endif
353 
354     try
355     {
356         if (doc->CountPP() > 1)
357         {
358             qCDebug(vTool, "PP count > 1");
359             ContextMenu<DialogSinglePoint>(event, id, RemoveOption::Enable, Referens::Ignore);
360         }
361         else
362         {
363             qCDebug(vTool, "PP count = 1");
364             ContextMenu<DialogSinglePoint>(event, id, RemoveOption::Disable);
365         }
366     }
367     catch(const VExceptionToolWasDeleted &e)
368     {
369         qCDebug(vTool, "Tool was deleted. Immediately leave method.");
370         Q_UNUSED(e)
371         return;//Leave this method immediately!!!
372     }
373     qCDebug(vTool, "Context menu closed. Tool was not deleted.");
374 }
375 
376 //---------------------------------------------------------------------------------------------------------------------
377 /**
378  * @brief FullUpdateFromFile update tool data form file.
379  */
FullUpdateFromFile()380 void VToolBasePoint::FullUpdateFromFile()
381 {
382     ReadAttributes();
383     RefreshPointGeometry(*VAbstractTool::data.GeometricObject<VPointF>(m_id));
384 }
385 
386 //---------------------------------------------------------------------------------------------------------------------
EnableToolMove(bool move)387 void VToolBasePoint::EnableToolMove(bool move)
388 {
389     this->setFlag(QGraphicsItem::ItemIsMovable, move);
390     VToolSinglePoint::EnableToolMove(move);
391 }
392