Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/svx/svdoedge.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#pragma once
21
22
#include <memory>
23
#include <optional>
24
#include <svx/svdotext.hxx>
25
#include <svx/svdglue.hxx>
26
#include <svx/svxdllapi.h>
27
#include <svx/xpoly.hxx>
28
29
30
class SdrDragMethod;
31
class SdrPageView;
32
33
namespace sdr::properties {
34
    class ConnectorProperties;
35
}
36
37
38
/// Utility class SdrObjConnection
39
class SdrObjConnection final
40
{
41
    friend class                SdrEdgeObj;
42
    friend class                ImpEdgeHdl;
43
    friend class                SdrCreateView;
44
45
    Point                       m_aObjOfs;       // set during dragging of a node
46
    SdrObject*                  m_pSdrObj;          // referenced object
47
    sal_uInt16                  m_nConId;        // connector number
48
49
    bool                        m_bBestConn : 1;   // true -> the best-matching connector is searched for
50
    bool                        m_bBestVertex : 1; // true -> the best-matching vertex to connect is searched for
51
    bool                        m_bAutoVertex : 1; // autoConnector at apex nCon
52
    bool                        m_bAutoCorner : 1; // autoConnector at corner nCon
53
54
public:
55
26.9k
    SdrObjConnection() { ResetVars(); }
56
57
    void ResetVars();
58
    bool TakeGluePoint(SdrGluePoint& rGP) const;
59
60
16.5k
    void SetBestConnection( bool rB ) { m_bBestConn = rB; };
61
16.5k
    void SetBestVertex( bool rB ) { m_bBestVertex = rB; };
62
16.5k
    void SetAutoVertex( bool rB ) { m_bAutoVertex = rB; };
63
16.5k
    void SetConnectorId( sal_uInt16 nId ) { m_nConId = nId; };
64
65
0
    bool IsBestConnection() const { return m_bBestConn; };
66
0
    bool IsAutoVertex() const { return m_bAutoVertex; };
67
0
    sal_uInt16 GetConnectorId() const { return m_nConId; };
68
30.5k
    SdrObject* GetSdrObject() const { return m_pSdrObj; }
69
};
70
71
72
enum class SdrEdgeLineCode { Obj1Line2, Obj1Line3, Obj2Line2, Obj2Line3, MiddleLine };
73
74
/// Utility class SdrEdgeInfoRec
75
class SdrEdgeInfoRec
76
{
77
public:
78
    // The 5 distances are set on dragging or via SetAttr and are
79
    // evaluated by ImpCalcEdgeTrack. Only 0-3 longs are transported
80
    // via Get/SetAttr/Get/SetStyleSh though.
81
    Point                       m_aObj1Line2;
82
    Point                       m_aObj1Line3;
83
    Point                       m_aObj2Line2;
84
    Point                       m_aObj2Line3;
85
    Point                       m_aMiddleLine;
86
87
    // Following values are set by ImpCalcEdgeTrack
88
    tools::Long                        m_nAngle1;           // exit angle at Obj1
89
    tools::Long                        m_nAngle2;           // exit angle at Obj2
90
    sal_uInt16                  m_nObj1Lines;        // 1..3
91
    sal_uInt16                  m_nObj2Lines;        // 1..3
92
    sal_uInt16                  m_nMiddleLine;       // 0xFFFF=none, otherwise point number of the beginning of the line
93
94
    // The value determines how curved connectors are routed. With value 'true' it is routed
95
    // compatible to OOXML, with value 'false' LO routing is used.
96
    // The value is set/get via property SDRATTR_EDGEOOXMLCURVE.
97
    bool m_bUseOOXMLCurve;
98
99
public:
100
    SdrEdgeInfoRec()
101
104k
    :   m_nAngle1(0),
102
104k
        m_nAngle2(0),
103
104k
        m_nObj1Lines(0),
104
104k
        m_nObj2Lines(0),
105
104k
        m_nMiddleLine(0xFFFF),
106
104k
        m_bUseOOXMLCurve(false)
107
104k
    {}
108
109
    Point& ImpGetLineOffsetPoint(SdrEdgeLineCode eLineCode);
110
    sal_uInt16 ImpGetPolyIdx(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const;
111
    bool ImpIsHorzLine(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const;
112
    void ImpSetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon& rXP, tools::Long nVal);
113
    tools::Long ImpGetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const;
114
};
115
116
117
/// Utility class SdrEdgeObjGeoData
118
class SdrEdgeObjGeoData final : public SdrTextObjGeoData
119
{
120
public:
121
    SdrObjConnection            m_aCon1;  // connection status of the beginning of the line
122
    SdrObjConnection            m_aCon2;  // connection status of the end of the line
123
    std::optional<XPolygon>     m_pEdgeTrack;
124
    bool                        m_bEdgeTrackDirty; // true -> connector track needs to be recalculated
125
    bool                        m_bEdgeTrackUserDefined;
126
    SdrEdgeInfoRec              m_aEdgeInfo;
127
128
public:
129
    SdrEdgeObjGeoData();
130
    virtual ~SdrEdgeObjGeoData() override;
131
};
132
133
134
/// Utility class SdrEdgeObj
135
class SVXCORE_DLLPUBLIC SdrEdgeObj final : public SdrTextObj
136
{
137
private:
138
    // to allow sdr::properties::ConnectorProperties access to ImpSetAttrToEdgeInfo()
139
    friend class sdr::properties::ConnectorProperties;
140
141
    friend class                SdrCreateView;
142
    friend class                ImpEdgeHdl;
143
144
    SAL_DLLPRIVATE virtual std::unique_ptr<sdr::contact::ViewContact> CreateObjectSpecificViewContact() override;
145
    SAL_DLLPRIVATE virtual std::unique_ptr<sdr::properties::BaseProperties> CreateObjectSpecificProperties() override;
146
147
    SdrObjConnection            m_aCon1;  // Connection status of the beginning of the line
148
    SdrObjConnection            m_aCon2;  // Connection status of the end of the line
149
150
    std::optional<XPolygon>     m_pEdgeTrack;
151
    sal_uInt16                  m_nNotifyingCount; // Locking
152
    SdrEdgeInfoRec              m_aEdgeInfo;
153
154
    bool                        m_bEdgeTrackDirty : 1; // true -> Connection track needs to be recalculated
155
    bool                        m_bEdgeTrackUserDefined : 1;
156
157
    // Bool to allow suppression of default connects at object
158
    // inside test (HitTest) and object center test (see ImpFindConnector())
159
    bool                        mbSuppressDefaultConnect : 1;
160
161
    // Flag value for avoiding infinite loops when calculating
162
    // BoundRects from ring-connected connectors. A coloring algorithm
163
    // is used here. When the GetCurrentBoundRect() calculation of a
164
    // SdrEdgeObj is running, the flag is set, else it is always
165
    // false.
166
    bool                        mbBoundRectCalculationRunning : 1;
167
168
    // #i123048# need to remember if layouting was suppressed before to get
169
    // to a correct state for first real layouting
170
    bool                        mbSuppressed : 1;
171
172
public:
173
    // Interface to default connect suppression
174
0
    void SetSuppressDefaultConnect(bool bNew) { mbSuppressDefaultConnect = bNew; }
175
0
    bool GetSuppressDefaultConnect() const { return mbSuppressDefaultConnect; }
176
177
private:
178
    SAL_DLLPRIVATE virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
179
180
    SAL_DLLPRIVATE static XPolygon ImpCalcObjToCenter(const Point& rStPt, tools::Long nEscAngle, const tools::Rectangle& rRect, const Point& rCenter);
181
    SAL_DLLPRIVATE void ImpRecalcEdgeTrack();   // recalculation of the connection track
182
    SAL_DLLPRIVATE XPolygon ImpCalcEdgeTrack(const XPolygon& rTrack0, SdrObjConnection& rCon1, SdrObjConnection& rCon2, SdrEdgeInfoRec* pInfo) const;
183
    SAL_DLLPRIVATE XPolygon ImpCalcEdgeTrack(const Point& rPt1, tools::Long nAngle1, const tools::Rectangle& rBoundRect1, const tools::Rectangle& rBewareRect1,
184
        const Point& rPt2, tools::Long nAngle2, const tools::Rectangle& rBoundRect2, const tools::Rectangle& rBewareRect2,
185
        sal_uInt64* pnQuality, SdrEdgeInfoRec* pInfo) const;
186
    SAL_DLLPRIVATE static bool ImpFindConnector(const Point& rPt, const SdrPageView& rPV, SdrObjConnection& rCon, const SdrEdgeObj* pThis, OutputDevice* pOut=nullptr, SdrDragStat* pDragStat = nullptr);
187
    SAL_DLLPRIVATE static SdrEscapeDirection ImpCalcEscAngle(SdrObject const * pObj, const Point& aPt2);
188
    SAL_DLLPRIVATE void ImpSetTailPoint(bool bTail1, const Point& rPt);
189
    SAL_DLLPRIVATE void ImpUndirtyEdgeTrack();  // potential recalculation of the connection track
190
    SAL_DLLPRIVATE void ImpDirtyEdgeTrack();    // invalidate connector path, so it will be recalculated next time
191
    SAL_DLLPRIVATE void ImpSetAttrToEdgeInfo(); // copying values from the pool to aEdgeInfo
192
    SAL_DLLPRIVATE void ImpSetEdgeInfoToAttr(); // copying values from the aEdgeInfo to the pool
193
194
    // protected destructor
195
    SAL_DLLPRIVATE virtual ~SdrEdgeObj() override;
196
197
public:
198
    SdrEdgeObj(SdrModel& rSdrModel);
199
    // Copy constructor
200
    SAL_DLLPRIVATE SdrEdgeObj(SdrModel& rSdrModel, SdrEdgeObj const & rSource);
201
202
    // react on model/page change
203
    SAL_DLLPRIVATE virtual void handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage) override;
204
205
135k
    SdrObjConnection& GetConnection(bool bTail1) { return *(bTail1 ? &m_aCon1 : &m_aCon2); }
206
    SAL_DLLPRIVATE virtual void TakeObjInfo(SdrObjTransformInfoRec& rInfo) const override;
207
    SAL_DLLPRIVATE virtual SdrObjKind GetObjIdentifier() const override;
208
    SAL_DLLPRIVATE virtual const tools::Rectangle& GetCurrentBoundRect() const override;
209
    SAL_DLLPRIVATE virtual const tools::Rectangle& GetSnapRect() const override;
210
    SAL_DLLPRIVATE virtual SdrGluePoint GetVertexGluePoint(sal_uInt16 nNum) const override;
211
    SAL_DLLPRIVATE virtual SdrGluePoint GetCornerGluePoint(sal_uInt16 nNum) const override;
212
    SAL_DLLPRIVATE virtual const SdrGluePointList* GetGluePointList() const override;
213
    SAL_DLLPRIVATE virtual SdrGluePointList* ForceGluePointList() override;
214
215
    // * for all of the below: bTail1=true: beginning of the line,
216
    //   otherwise end of the line
217
    // * pObj=NULL: disconnect connector
218
22.8k
    void SetEdgeTrackDirty() { m_bEdgeTrackDirty=true; }
219
    void ConnectToNode(bool bTail1, SdrObject* pObj) override;
220
    SAL_DLLPRIVATE void DisconnectFromNode(bool bTail1) override;
221
    SdrObject* GetConnectedNode(bool bTail1) const override;
222
72
    const SdrObjConnection& GetConnection(bool bTail1) const { return *(bTail1 ? &m_aCon1 : &m_aCon2); }
223
    SAL_DLLPRIVATE bool CheckNodeConnection(bool bTail1) const;
224
225
    SAL_DLLPRIVATE virtual void RecalcSnapRect() override;
226
    SAL_DLLPRIVATE virtual void TakeUnrotatedSnapRect(tools::Rectangle& rRect) const override;
227
    virtual rtl::Reference<SdrObject> CloneSdrObject(SdrModel& rTargetModel) const override;
228
    SAL_DLLPRIVATE virtual OUString TakeObjNameSingul() const override;
229
    SAL_DLLPRIVATE virtual OUString TakeObjNamePlural() const override;
230
231
    void    SetEdgeTrackPath( const basegfx::B2DPolyPolygon& rPoly );
232
    basegfx::B2DPolyPolygon GetEdgeTrackPath() const;
233
234
    SAL_DLLPRIVATE virtual basegfx::B2DPolyPolygon TakeXorPoly() const override;
235
    SAL_DLLPRIVATE virtual sal_uInt32 GetHdlCount() const override;
236
    SAL_DLLPRIVATE virtual void AddToHdlList(SdrHdlList& rHdlList) const override;
237
238
    // special drag methods
239
    SAL_DLLPRIVATE virtual bool hasSpecialDrag() const override;
240
    SAL_DLLPRIVATE virtual bool beginSpecialDrag(SdrDragStat& rDrag) const override;
241
    SAL_DLLPRIVATE virtual bool applySpecialDrag(SdrDragStat& rDrag) override;
242
    SAL_DLLPRIVATE virtual OUString getSpecialDragComment(const SdrDragStat& rDrag) const override;
243
244
    // FullDrag support
245
    SAL_DLLPRIVATE virtual rtl::Reference<SdrObject> getFullDragClone() const override;
246
247
    SAL_DLLPRIVATE virtual void NbcSetSnapRect(const tools::Rectangle& rRect) override;
248
    SAL_DLLPRIVATE virtual void NbcMove(const Size& aSize) override;
249
    SAL_DLLPRIVATE virtual void NbcResize(const Point& rRefPnt, double aXFact, double aYFact) override;
250
251
    // #i54102# added rotate, mirror and shear support
252
    SAL_DLLPRIVATE virtual void NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs) override;
253
    SAL_DLLPRIVATE virtual void NbcMirror(const Point& rRef1, const Point& rRef2) override;
254
    SAL_DLLPRIVATE virtual void NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear) override;
255
256
    // #102344# Added missing implementation
257
    SAL_DLLPRIVATE virtual void NbcSetAnchorPos(const Point& rPnt) override;
258
259
    SAL_DLLPRIVATE virtual bool BegCreate(SdrDragStat& rStat) override;
260
    SAL_DLLPRIVATE virtual bool MovCreate(SdrDragStat& rStat) override;
261
    SAL_DLLPRIVATE virtual bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) override;
262
    SAL_DLLPRIVATE virtual bool BckCreate(SdrDragStat& rStat) override;
263
    SAL_DLLPRIVATE virtual void BrkCreate(SdrDragStat& rStat) override;
264
    SAL_DLLPRIVATE virtual basegfx::B2DPolyPolygon TakeCreatePoly(const SdrDragStat& rDrag) const override;
265
    SAL_DLLPRIVATE virtual PointerStyle GetCreatePointer() const override;
266
    SAL_DLLPRIVATE virtual rtl::Reference<SdrObject> DoConvertToPolyObj(bool bBezier, bool bAddText) const override;
267
268
    SAL_DLLPRIVATE virtual sal_uInt32 GetSnapPointCount() const override;
269
    SAL_DLLPRIVATE virtual Point GetSnapPoint(sal_uInt32 i) const override;
270
    SAL_DLLPRIVATE virtual bool IsPolyObj() const override;
271
    SAL_DLLPRIVATE virtual sal_uInt32 GetPointCount() const override;
272
    SAL_DLLPRIVATE virtual Point GetPoint(sal_uInt32 i) const override;
273
    SAL_DLLPRIVATE virtual void NbcSetPoint(const Point& rPnt, sal_uInt32 i) override;
274
275
    SAL_DLLPRIVATE virtual std::unique_ptr<SdrObjGeoData> NewGeoData() const override;
276
    SAL_DLLPRIVATE virtual void SaveGeoData(SdrObjGeoData& rGeo) const override;
277
    SAL_DLLPRIVATE virtual void RestoreGeoData(const SdrObjGeoData& rGeo) override;
278
279
    /** updates edges that are connected to the edges of this object
280
        as if the connected objects send a repaint broadcast
281
        #103122#
282
    */
283
    SAL_DLLPRIVATE void Reformat();
284
285
    // helper methods for the StarOffice api
286
    SAL_DLLPRIVATE Point GetTailPoint( bool bTail ) const;
287
    void SetTailPoint( bool bTail, const Point& rPt );
288
    SAL_DLLPRIVATE void setGluePointIndex( bool bTail, sal_Int32 nId = -1 );
289
    SAL_DLLPRIVATE sal_Int32 getGluePointIndex( bool bTail );
290
291
    SAL_DLLPRIVATE virtual bool TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& rPolyPolygon) const override;
292
    SAL_DLLPRIVATE virtual void TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& rPolyPolygon) override;
293
294
    // for geometry access
295
    SAL_DLLPRIVATE ::basegfx::B2DPolygon getEdgeTrack() const;
296
297
    // helper method for SdrDragMethod::AddConnectorOverlays. Adds an overlay polygon for
298
    // this connector to rResult.
299
    SAL_DLLPRIVATE basegfx::B2DPolygon ImplAddConnectorOverlay(const SdrDragMethod& rDragMethod, bool bTail1, bool bTail2, bool bDetail) const;
300
};
301
302
 // The following item parameters of the SdrItemPool are used to
303
 // determine the actual connector line routing:
304
 //
305
 //  sal_uInt16 EdgeFlowAngle       default 9000 (= 90.00 deg), min 0, max 9000
306
 //      Clearance angle.
307
 //      The angle at which the connecting line may run.
308
 //
309
 //  sal_uInt16 EdgeEscAngle        default 9000 (= 90.00 Deg), min 0, max 9000
310
 //      Object exit angle.
311
 //      The angle at which the connection line may exit from the object.
312
 //
313
 //  bool EdgeEscAsRay              default false
314
 //      true -> the connecting line emerges from the object radially.
315
 //      Thus, angle specification by the line ObjCenter / connector.
316
 //
317
 //  bool EdgeEscUseObjAngle        default false
318
 //      Object rotation angle is considered
319
 //      true -> when determining the connector exit angle, angle for
320
 //      object rotation is taken as an offset.
321
 //
322
 //  sal_uInt64 EdgeFlowDefDist    default 0, min 0, max ?
323
 //      This is the default minimum distance on calculation of the
324
 //      connection Line to the docked objects is in logical units.
325
 //      This distance is overridden within the object, as soon as the
326
 //      user drags on the lines. When docking onto a new object,
327
 //      however, this default is used again.
328
 //
329
 //
330
 // General Information About Connectors:
331
 //
332
 // There are nodes and edge objects. Two nodes can be joined by an
333
 // edge. If a connector is connected to a node only at one end, the
334
 // other end is fixed to an absolute position in the document. It is
335
 // of course also possible for a connector to be "free" at both ends,
336
 // i.e. not connected to a node object on each side.
337
 //
338
 // A connector object can also theoretically be a node object at the
339
 // same time. In the first version, however, this will not yet be
340
 // realized.
341
 //
342
 // A connection between node and connector edge can be established by:
343
 // - Interactive creation of a new edge object at the SdrView where
344
 //   the beginning or end point of the edge is placed on a connector
345
 //   (glueing point) of an already existing node object.
346
 // - Interactive dragging of the beginning or end point of an
347
 //   existing connector edge object on the SdrView to a connector
348
 //   (glueing point) of an already existing node object.
349
 // - Undo/Redo
350
 //   Moving node objects does not make any connections. Also not the
351
 //   direct shifting of edge endpoints on the SdrModel... Connections
352
 //   can also be established, if the connectors are not configured to
353
 //   be visible in the view.
354
 //
355
 // An existing connection between node and edge is retained for:
356
 // - Dragging (Move/Resize/Rotate/...) of the node object
357
 // - Moving a connector position in the node object
358
 // - Simultaneous dragging (Move/Resize/Rotate/...) of the node and the
359
 //   edge
360
 //
361
 // A connection between node and edge can be removed by:
362
 // - Deleting one of the objects
363
 // - Dragging the edge object without simultaneously dragging the node
364
 // - Deleting the connector at the node object
365
 // - Undo/Redo/Repeat
366
 // When dragging, the request to remove the connection must be
367
 // requested from outside of the model (for example, from the
368
 // SdrView). SdrEdgeObj::Move() itself does not remove the
369
 // connection.
370
 //
371
 // Each node object can have connectors, so-called gluepoints. These
372
 // are the geometric points at which the connecting edge object ends
373
 // when the connection is established. By default, each object has no
374
 // connectors.  Nevertheless, one can dock an edge in certain view
375
 // settings since then, e.g., connectors can be automatically
376
 // generated at the 4 vertices of the node object when needed. Each
377
 // object provides 2x4 so-called default connector positions, 4 at
378
 // the vertices and 4 at the corner positions. In the normal case,
379
 // these are located at the 8 handle positions; exceptions here are
380
 // ellipses, parallelograms, ... .  In addition, user-specific
381
 // connectors can be set for each node object.
382
 //
383
 // Then there is also the possibility to dock an edge on an object
384
 // with the attribute "bUseBestConnector". The best-matching
385
 // connector position for the routing of the connection line is then
386
 // used from the offering of connectors of the object or/and of the
387
 // vertices. The user assigns this attribute by docking the node in
388
 // its center (see, e.g., Visio).
389
 // 09-06-1996: bUseBestConnector uses vertex gluepoints only.
390
 //
391
 // And here is some terminology:
392
 //   Connector : The connector object (edge object)
393
 //   Node      : Any object to which a connector can be glued to, e.g., a rectangle,
394
 //               etc.
395
 //   Gluepoint: The point at which the connector is glued to the node object.
396
 //               There are:
397
 //                 Vertex gluepoints: Each node object presents these glue
398
 //                     points inherently. Perhaps there is already the option
399
 //                     "automatically glue to object vertex" in Draw (default is
400
 //                     on).
401
 //                 Corner gluepoints: These gluepoints, too, are already
402
 //                     auto-enabled on objects. Similar to the ones above,
403
 //                     there may already be an option for them in Draw (default is
404
 //                     off).
405
 //                 In contrast to Visio, vertex gluepoints and corner glue
406
 //                     points are not displayed in the UI; they are simply there (if
407
 //                     the option is activated).
408
 //                 Custom gluepoints: Any number of them are present on each
409
 //                     node object. They can be made visible using the option
410
 //                     (always visible when editing). At the moment, however, they
411
 //                     are not yet fully implemented.
412
 //                 Automatic gluepoint selection: If the connector is docked
413
 //                     to the node object so that the black frame encompasses the
414
 //                     entire object, then the connector tries to find the most
415
 //                     convenient of the 4 vertex gluepoints (and only of those).
416
417
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */