1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svx/sdr/contact/viewcontact.hxx>
21 #include <svx/sdr/contact/viewobjectcontact.hxx>
22 #include <svx/sdr/contact/objectcontact.hxx>
23 #include <basegfx/polygon/b2dpolygon.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <basegfx/color/bcolor.hxx>
26 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
27 #include <osl/diagnose.h>
28 #include <tools/debug.hxx>
30 namespace sdr::contact
32 // Create an Object-Specific ViewObjectContact, set ViewContact and
33 // ObjectContact. Always needs to return something. Default is to create
34 // a standard ViewObjectContact containing the given ObjectContact and *this
35 ViewObjectContact
& ViewContact::CreateObjectSpecificViewObjectContact(ObjectContact
& rObjectContact
)
37 return *(new ViewObjectContact(rObjectContact
, *this));
40 ViewContact::ViewContact() {}
42 ViewContact::~ViewContact() { deleteAllVOCs(); }
44 void ViewContact::deleteAllVOCs()
46 // get rid of all VOCs
47 // #i84257# To avoid that each 'delete pCandidate' again uses
48 // the local RemoveViewObjectContact with a search and removal in the
49 // vector, simply copy and clear local vector.
50 std::vector
<ViewObjectContact
*> aLocalVOCList
;
51 aLocalVOCList
.swap(maViewObjectContactVector
);
53 for (const auto& pCandidate
: aLocalVOCList
)
54 // ViewObjectContacts only make sense with View and Object contacts.
55 // When the contact to the SdrObject is deleted like in this case,
56 // all ViewObjectContacts can be deleted, too.
59 // assert when there were new entries added during deletion
60 DBG_ASSERT(maViewObjectContactVector
.empty(), "Corrupted ViewObjectContactList in VC (!)");
63 // get an Object-specific ViewObjectContact for a specific
64 // ObjectContact (->View). Always needs to return something.
65 ViewObjectContact
& ViewContact::GetViewObjectContact(ObjectContact
& rObjectContact
)
67 ViewObjectContact
* pRetval
= nullptr;
68 const sal_uInt32
nCount(maViewObjectContactVector
.size());
70 // first search if there exists a VOC for the given OC
71 for (sal_uInt32
a(0); !pRetval
&& a
< nCount
; a
++)
73 ViewObjectContact
* pCandidate
= maViewObjectContactVector
[a
];
74 DBG_ASSERT(pCandidate
, "Corrupted ViewObjectContactList (!)");
76 if (&(pCandidate
->GetObjectContact()) == &rObjectContact
)
84 // create a new one. It's inserted to the local list from the
85 // ViewObjectContact constructor via AddViewObjectContact()
86 pRetval
= &CreateObjectSpecificViewObjectContact(rObjectContact
);
92 // A new ViewObjectContact was created and shall be remembered.
93 void ViewContact::AddViewObjectContact(ViewObjectContact
& rVOContact
)
95 maViewObjectContactVector
.push_back(&rVOContact
);
98 // A ViewObjectContact was deleted and shall be forgotten.
99 void ViewContact::RemoveViewObjectContact(ViewObjectContact
& rVOContact
)
101 std::vector
<ViewObjectContact
*>::iterator aFindResult
= std::find(
102 maViewObjectContactVector
.begin(), maViewObjectContactVector
.end(), &rVOContact
);
104 if (aFindResult
!= maViewObjectContactVector
.end())
106 maViewObjectContactVector
.erase(aFindResult
);
110 // Test if this ViewContact has ViewObjectContacts at all. This can
111 // be used to test if this ViewContact is visualized ATM or not
112 bool ViewContact::HasViewObjectContacts() const
114 const sal_uInt32
nCount(maViewObjectContactVector
.size());
116 for (sal_uInt32
a(0); a
< nCount
; a
++)
118 if (!maViewObjectContactVector
[a
]->GetObjectContact().IsPreviewRenderer())
126 // Test if this ViewContact has ViewObjectContacts at all. This can
127 // be used to test if this ViewContact is visualized ATM or not
128 bool ViewContact::isAnimatedInAnyViewObjectContact() const
130 const sal_uInt32
nCount(maViewObjectContactVector
.size());
132 for (sal_uInt32
a(0); a
< nCount
; a
++)
134 if (maViewObjectContactVector
[a
]->isAnimated())
143 // Access to possible sub-hierarchy and parent. GetObjectCount() default is 0L
144 // and GetViewContact default pops up an assert since it's an error if
145 // GetObjectCount has a result != 0 and it's not overridden.
146 sal_uInt32
ViewContact::GetObjectCount() const
152 ViewContact
& ViewContact::GetViewContact(sal_uInt32
/*nIndex*/) const
154 // This is the default implementation; call would be an error
155 OSL_FAIL("ViewContact::GetViewContact: This call needs to be overridden when GetObjectCount() "
156 "can return results != 0 (!)");
157 return const_cast<ViewContact
&>(*this);
160 ViewContact
* ViewContact::GetParentContact() const
162 // default has no parent
166 void ViewContact::ActionChildInserted(ViewContact
& rChild
)
168 // propagate change to all existing visualisations which
169 // will force a VOC for the new child and invalidate its range
170 const sal_uInt32
nCount(maViewObjectContactVector
.size());
172 for (sal_uInt32
a(0); a
< nCount
; a
++)
174 ViewObjectContact
* pCandidate
= maViewObjectContactVector
[a
];
175 DBG_ASSERT(pCandidate
,
176 "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");
178 // take action at all VOCs. At the VOCs ObjectContact the initial
179 // rectangle will be invalidated at the associated OutputDevice.
180 pCandidate
->ActionChildInserted(rChild
);
184 // React on changes of the object of this ViewContact
185 void ViewContact::ActionChanged()
187 // propagate change to all existing VOCs. This will invalidate
188 // all drawn visualisations in all known views
189 const sal_uInt32
nCount(maViewObjectContactVector
.size());
191 for (sal_uInt32
a(0); a
< nCount
; a
++)
193 ViewObjectContact
* pCandidate
= maViewObjectContactVector
[a
];
194 DBG_ASSERT(pCandidate
,
195 "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");
199 pCandidate
->ActionChanged();
204 // access to SdrObject and/or SdrPage. May return 0L like the default
205 // implementations do. Override as needed.
206 SdrObject
* ViewContact::TryToGetSdrObject() const { return nullptr; }
210 void ViewContact::createViewIndependentPrimitive2DSequence(
211 drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) const
213 // This is the default implementation and should never be called (see header). If this is called,
214 // someone implemented a ViewContact (VC) visualisation object without defining the visualisation by
215 // providing a sequence of primitives -> which cannot be correct.
216 // Since we have no access to any known model data here, the default implementation creates a yellow placeholder
217 // hairline polygon with a default size of (1000, 1000, 5000, 3000)
218 OSL_FAIL("ViewContact::createViewIndependentPrimitive2DSequence(): Never call the fallback "
219 "base implementation, this is always an error (!)");
220 basegfx::B2DPolygon
aOutline(
221 basegfx::utils::createPolygonFromRect(basegfx::B2DRange(1000.0, 1000.0, 5000.0, 3000.0)));
222 const basegfx::BColor
aYellow(1.0, 1.0, 0.0);
223 const drawinglayer::primitive2d::Primitive2DReference
xReference(
224 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aOutline
), aYellow
));
226 rVisitor
.visit(xReference
);
229 void ViewContact::getViewIndependentPrimitive2DContainer(
230 drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) const
232 /* Local up-to-date checks. Create new list and compare.
233 We cannot just always use the new data because the old data has cached bitmaps in it e.g. see the document in tdf#146108.
235 drawinglayer::primitive2d::Primitive2DContainer xNew
;
236 createViewIndependentPrimitive2DSequence(xNew
);
240 // allow evtl. embedding in object-specific infos, e.g. Name, Title, Description
241 xNew
= embedToObjectSpecificInformation(std::move(xNew
));
244 if (mxViewIndependentPrimitive2DSequence
!= xNew
)
246 // has changed, copy content
247 const_cast<ViewContact
*>(this)->mxViewIndependentPrimitive2DSequence
= std::move(xNew
);
250 // return current Primitive2DContainer
251 rVisitor
.visit(mxViewIndependentPrimitive2DSequence
);
254 // add Gluepoints (if available)
255 drawinglayer::primitive2d::Primitive2DContainer
256 ViewContact::createGluePointPrimitive2DSequence() const
258 // default returns empty reference
259 return drawinglayer::primitive2d::Primitive2DContainer();
262 drawinglayer::primitive2d::Primitive2DContainer
ViewContact::embedToObjectSpecificInformation(
263 drawinglayer::primitive2d::Primitive2DContainer aSource
) const
265 // nothing to do for default
270 ViewContact::getRange(const drawinglayer::geometry::ViewInformation2D
& /*rViewInfo2D*/) const
272 // Return empty range.
273 return basegfx::B2DRange();
276 void ViewContact::flushViewObjectContacts(bool bWithHierarchy
)
280 // flush DrawingLayer hierarchy
281 const sal_uInt32
nCount(GetObjectCount());
283 for (sal_uInt32
a(0); a
< nCount
; a
++)
285 ViewContact
& rChild
= GetViewContact(a
);
286 rChild
.flushViewObjectContacts(bWithHierarchy
);
295 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */