/src/libreoffice/svx/source/sdr/contact/viewcontact.cxx
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 | | #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> |
29 | | |
30 | | namespace sdr::contact |
31 | | { |
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) |
36 | 0 | { |
37 | 0 | return *(new ViewObjectContact(rObjectContact, *this)); |
38 | 0 | } |
39 | | |
40 | 11.2M | ViewContact::ViewContact() {} |
41 | | |
42 | 11.2M | ViewContact::~ViewContact() { deleteAllVOCs(); } |
43 | | |
44 | | void ViewContact::deleteAllVOCs() |
45 | 20.2M | { |
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 | 20.2M | std::vector<ViewObjectContact*> aLocalVOCList; |
51 | 20.2M | aLocalVOCList.swap(maViewObjectContactVector); |
52 | | |
53 | 20.2M | 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. |
57 | 0 | delete pCandidate; |
58 | | |
59 | | // assert when there were new entries added during deletion |
60 | 20.2M | DBG_ASSERT(maViewObjectContactVector.empty(), "Corrupted ViewObjectContactList in VC (!)"); |
61 | | |
62 | 20.2M | mxViewIndependentPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer(); |
63 | 20.2M | } |
64 | | |
65 | | // get an Object-specific ViewObjectContact for a specific |
66 | | // ObjectContact (->View). Always needs to return something. |
67 | | ViewObjectContact& ViewContact::GetViewObjectContact(ObjectContact& rObjectContact) |
68 | 269k | { |
69 | 269k | ViewObjectContact* pRetval = nullptr; |
70 | 269k | const sal_uInt32 nCount(maViewObjectContactVector.size()); |
71 | | |
72 | | // first search if there exists a VOC for the given OC |
73 | 449k | for (sal_uInt32 a(0); !pRetval && a < nCount; a++) |
74 | 179k | { |
75 | 179k | ViewObjectContact* pCandidate = maViewObjectContactVector[a]; |
76 | 179k | assert(pCandidate && "Corrupted ViewObjectContactList (!)"); |
77 | | |
78 | 179k | if (&(pCandidate->GetObjectContact()) == &rObjectContact) |
79 | 179k | { |
80 | 179k | pRetval = pCandidate; |
81 | 179k | } |
82 | 179k | } |
83 | | |
84 | 269k | if (!pRetval) |
85 | 90.2k | { |
86 | | // create a new one. It's inserted to the local list from the |
87 | | // ViewObjectContact constructor via AddViewObjectContact() |
88 | 90.2k | pRetval = &CreateObjectSpecificViewObjectContact(rObjectContact); |
89 | 90.2k | } |
90 | | |
91 | 269k | return *pRetval; |
92 | 269k | } |
93 | | |
94 | | // A new ViewObjectContact was created and shall be remembered. |
95 | | void ViewContact::AddViewObjectContact(ViewObjectContact& rVOContact) |
96 | 90.2k | { |
97 | 90.2k | maViewObjectContactVector.push_back(&rVOContact); |
98 | 90.2k | } |
99 | | |
100 | | // A ViewObjectContact was deleted and shall be forgotten. |
101 | | void ViewContact::RemoveViewObjectContact(ViewObjectContact& rVOContact) |
102 | 90.2k | { |
103 | 90.2k | std::vector<ViewObjectContact*>::iterator aFindResult = std::find( |
104 | 90.2k | maViewObjectContactVector.begin(), maViewObjectContactVector.end(), &rVOContact); |
105 | | |
106 | 90.2k | if (aFindResult != maViewObjectContactVector.end()) |
107 | 90.2k | { |
108 | 90.2k | maViewObjectContactVector.erase(aFindResult); |
109 | 90.2k | } |
110 | 90.2k | } |
111 | | |
112 | | // Test if this ViewContact has ViewObjectContacts at all. This can |
113 | | // be used to test if this ViewContact is visualized ATM or not |
114 | | bool ViewContact::HasViewObjectContacts() const |
115 | 0 | { |
116 | 0 | const sal_uInt32 nCount(maViewObjectContactVector.size()); |
117 | |
|
118 | 0 | for (sal_uInt32 a(0); a < nCount; a++) |
119 | 0 | { |
120 | 0 | if (!maViewObjectContactVector[a]->GetObjectContact().IsPreviewRenderer()) |
121 | 0 | { |
122 | 0 | return true; |
123 | 0 | } |
124 | 0 | } |
125 | 0 | return false; |
126 | 0 | } |
127 | | |
128 | | // Test if this ViewContact has ViewObjectContacts at all. This can |
129 | | // be used to test if this ViewContact is visualized ATM or not |
130 | | bool ViewContact::isAnimatedInAnyViewObjectContact() const |
131 | 0 | { |
132 | 0 | const sal_uInt32 nCount(maViewObjectContactVector.size()); |
133 | |
|
134 | 0 | for (sal_uInt32 a(0); a < nCount; a++) |
135 | 0 | { |
136 | 0 | if (maViewObjectContactVector[a]->isAnimated()) |
137 | 0 | { |
138 | 0 | return true; |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | 0 | return false; |
143 | 0 | } |
144 | | |
145 | | // Access to possible sub-hierarchy and parent. GetObjectCount() default is 0L |
146 | | // and GetViewContact default pops up an assert since it's an error if |
147 | | // GetObjectCount has a result != 0 and it's not overridden. |
148 | | sal_uInt32 ViewContact::GetObjectCount() const |
149 | 4.76M | { |
150 | | // no sub-objects |
151 | 4.76M | return 0; |
152 | 4.76M | } |
153 | | |
154 | | ViewContact& ViewContact::GetViewContact(sal_uInt32 /*nIndex*/) const |
155 | 0 | { |
156 | | // This is the default implementation; call would be an error |
157 | 0 | OSL_FAIL("ViewContact::GetViewContact: This call needs to be overridden when GetObjectCount() " |
158 | 0 | "can return results != 0 (!)"); |
159 | 0 | return const_cast<ViewContact&>(*this); |
160 | 0 | } |
161 | | |
162 | | ViewContact* ViewContact::GetParentContact() const |
163 | 0 | { |
164 | | // default has no parent |
165 | 0 | return nullptr; |
166 | 0 | } |
167 | | |
168 | | void ViewContact::ActionChildInserted(ViewContact& rChild) |
169 | 2.14M | { |
170 | | // propagate change to all existing visualisations which |
171 | | // will force a VOC for the new child and invalidate its range |
172 | 2.14M | const sal_uInt32 nCount(maViewObjectContactVector.size()); |
173 | | |
174 | 2.14M | for (sal_uInt32 a(0); a < nCount; a++) |
175 | 0 | { |
176 | 0 | ViewObjectContact* pCandidate = maViewObjectContactVector[a]; |
177 | 0 | DBG_ASSERT(pCandidate, |
178 | 0 | "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)"); |
179 | | |
180 | | // take action at all VOCs. At the VOCs ObjectContact the initial |
181 | | // rectangle will be invalidated at the associated OutputDevice. |
182 | 0 | pCandidate->ActionChildInserted(rChild); |
183 | 0 | } |
184 | 2.14M | } |
185 | | |
186 | | // React on changes of the object of this ViewContact |
187 | | void ViewContact::ActionChanged() |
188 | 55.8M | { |
189 | | // propagate change to all existing VOCs. This will invalidate |
190 | | // all drawn visualisations in all known views |
191 | 55.8M | const sal_uInt32 nCount(maViewObjectContactVector.size()); |
192 | | |
193 | 55.8M | for (sal_uInt32 a(0); a < nCount; a++) |
194 | 0 | { |
195 | 0 | ViewObjectContact* pCandidate = maViewObjectContactVector[a]; |
196 | 0 | DBG_ASSERT(pCandidate, |
197 | 0 | "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)"); |
198 | |
|
199 | 0 | if (pCandidate) |
200 | 0 | { |
201 | 0 | pCandidate->ActionChanged(); |
202 | 0 | } |
203 | 0 | } |
204 | 55.8M | } |
205 | | |
206 | | // IASS: helper for IASS invalidates |
207 | | void ViewContact::ActionChangedIfDifferentPageView(const SdrPageView& rSdrPageView) |
208 | 0 | { |
209 | 0 | const sal_uInt32 nCount(maViewObjectContactVector.size()); |
210 | |
|
211 | 0 | for (sal_uInt32 a(0); a < nCount; a++) |
212 | 0 | { |
213 | 0 | ViewObjectContact* pCandidate = maViewObjectContactVector[a]; |
214 | 0 | DBG_ASSERT(pCandidate, |
215 | 0 | "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)"); |
216 | |
|
217 | 0 | if (pCandidate) |
218 | 0 | { |
219 | 0 | pCandidate->ActionChangedIfDifferentPageView(rSdrPageView); |
220 | 0 | } |
221 | 0 | } |
222 | 0 | } |
223 | | |
224 | | bool ViewContact::hasMultipleViewObjectContacts() const |
225 | 0 | { |
226 | 0 | return maViewObjectContactVector.size() > 1; |
227 | 0 | } |
228 | | |
229 | | // access to SdrObject and/or SdrPage. May return 0L like the default |
230 | | // implementations do. Override as needed. |
231 | 316 | SdrObject* ViewContact::TryToGetSdrObject() const { return nullptr; } |
232 | | |
233 | | // primitive stuff |
234 | | |
235 | | void ViewContact::createViewIndependentPrimitive2DSequence( |
236 | | drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const |
237 | 0 | { |
238 | | // This is the default implementation and should never be called (see header). If this is called, |
239 | | // someone implemented a ViewContact (VC) visualisation object without defining the visualisation by |
240 | | // providing a sequence of primitives -> which cannot be correct. |
241 | | // Since we have no access to any known model data here, the default implementation creates a yellow placeholder |
242 | | // hairline polygon with a default size of (1000, 1000, 5000, 3000) |
243 | 0 | OSL_FAIL("ViewContact::createViewIndependentPrimitive2DSequence(): Never call the fallback " |
244 | 0 | "base implementation, this is always an error (!)"); |
245 | 0 | basegfx::B2DPolygon aOutline( |
246 | 0 | basegfx::utils::createPolygonFromRect(basegfx::B2DRange(1000.0, 1000.0, 5000.0, 3000.0))); |
247 | 0 | const basegfx::BColor aYellow(1.0, 1.0, 0.0); |
248 | 0 | const drawinglayer::primitive2d::Primitive2DReference xReference( |
249 | 0 | new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aOutline), aYellow)); |
250 | |
|
251 | 0 | rVisitor.visit(xReference); |
252 | 0 | } |
253 | | |
254 | | void ViewContact::getViewIndependentPrimitive2DContainer( |
255 | | drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const |
256 | 2.82k | { |
257 | | /* Local up-to-date checks. Create new list and compare. |
258 | | 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. |
259 | | */ |
260 | 2.82k | drawinglayer::primitive2d::Primitive2DContainer xNew; |
261 | 2.82k | createViewIndependentPrimitive2DSequence(xNew); |
262 | | |
263 | 2.82k | if (!xNew.empty()) |
264 | 2.24k | { |
265 | | // allow evtl. embedding in object-specific infos, e.g. Name, Title, Description |
266 | 2.24k | xNew = embedToObjectSpecificInformation(std::move(xNew)); |
267 | 2.24k | } |
268 | | |
269 | 2.82k | if (mxViewIndependentPrimitive2DSequence != xNew) |
270 | 1.57k | { |
271 | | // has changed, copy content |
272 | 1.57k | const_cast<ViewContact*>(this)->mxViewIndependentPrimitive2DSequence = std::move(xNew); |
273 | 1.57k | } |
274 | | |
275 | | // return current Primitive2DContainer |
276 | 2.82k | rVisitor.visit(mxViewIndependentPrimitive2DSequence); |
277 | 2.82k | } |
278 | | |
279 | | // add Gluepoints (if available) |
280 | | drawinglayer::primitive2d::Primitive2DContainer |
281 | | ViewContact::createGluePointPrimitive2DSequence() const |
282 | 0 | { |
283 | | // default returns empty reference |
284 | 0 | return drawinglayer::primitive2d::Primitive2DContainer(); |
285 | 0 | } |
286 | | |
287 | | drawinglayer::primitive2d::Primitive2DContainer ViewContact::embedToObjectSpecificInformation( |
288 | | drawinglayer::primitive2d::Primitive2DContainer aSource) const |
289 | 0 | { |
290 | | // nothing to do for default |
291 | 0 | return aSource; |
292 | 0 | } |
293 | | |
294 | | basegfx::B2DRange |
295 | | ViewContact::getRange(const drawinglayer::geometry::ViewInformation2D& /*rViewInfo2D*/) const |
296 | 2.82k | { |
297 | | // Return empty range. |
298 | 2.82k | return basegfx::B2DRange(); |
299 | 2.82k | } |
300 | | |
301 | | void ViewContact::flushViewObjectContacts(bool bWithHierarchy) |
302 | 9.05M | { |
303 | 9.05M | if (bWithHierarchy) |
304 | 9.05M | { |
305 | | // flush DrawingLayer hierarchy |
306 | 9.05M | const sal_uInt32 nCount(GetObjectCount()); |
307 | | |
308 | 17.0M | for (sal_uInt32 a(0); a < nCount; a++) |
309 | 7.97M | { |
310 | 7.97M | ViewContact& rChild = GetViewContact(a); |
311 | 7.97M | rChild.flushViewObjectContacts(bWithHierarchy); |
312 | 7.97M | } |
313 | 9.05M | } |
314 | | |
315 | | // delete local VOCs |
316 | 9.05M | deleteAllVOCs(); |
317 | 9.05M | } |
318 | | |
319 | | void ViewContact::getPrimitive2DSequenceHierarchyOfIndex( |
320 | | sal_uInt32 a, DisplayInfo& rDisplayInfo, ObjectContact& rObjectContact, |
321 | | drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) |
322 | 86.5k | { |
323 | 86.5k | const ViewObjectContact& rCandidate(GetViewContact(a).GetViewObjectContact(rObjectContact)); |
324 | 86.5k | rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor); |
325 | 86.5k | } |
326 | | } |
327 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |