1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 #include <svx/sdr/contact/viewcontact.hxx>
27 #include <svx/sdr/contact/viewobjectcontact.hxx>
28 #include <svx/sdr/contact/objectcontact.hxx>
29 #include <basegfx/polygon/b2dpolygon.hxx>
30 #include <basegfx/polygon/b2dpolygontools.hxx>
31 #include <basegfx/color/bcolor.hxx>
32 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <svx/sdr/contact/objectcontactofpageview.hxx>
35 
36 //////////////////////////////////////////////////////////////////////////////
37 
38 namespace sdr
39 {
40 	namespace contact
41 	{
42 		// Create a Object-Specific ViewObjectContact, set ViewContact and
43 		// ObjectContact. Always needs to return something. Default is to create
44 		// a standard ViewObjectContact containing the given ObjectContact and *this
CreateObjectSpecificViewObjectContact(ObjectContact & rObjectContact)45 		ViewObjectContact& ViewContact::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
46 		{
47 			return *(new ViewObjectContact(rObjectContact, *this));
48 		}
49 
ViewContact()50 		ViewContact::ViewContact()
51 		:	maViewObjectContactVector(),
52 			mxViewIndependentPrimitive2DSequence()
53 		{
54 		}
55 
56 		// Methods to react on start getting viewed or stop getting
57 		// viewed. This info is derived from the count of members of
58 		// registered ViewObjectContacts. Default does nothing.
StartGettingViewed()59 		void ViewContact::StartGettingViewed()
60 		{
61 		}
62 
StopGettingViewed()63 		void ViewContact::StopGettingViewed()
64 		{
65 		}
66 
~ViewContact()67 		ViewContact::~ViewContact()
68 		{
69 			deleteAllVOCs();
70 		}
71 
deleteAllVOCs()72 		void ViewContact::deleteAllVOCs()
73 		{
74 			// get rid of all VOCs
75 			// #i84257# To avoid that each 'delete pCandidate' again uses
76 			// the local RemoveViewObjectContact with a search and removal in the
77 			// vector, simply copy and clear local vector.
78 			std::vector< ViewObjectContact* > aLocalVOCList(maViewObjectContactVector);
79 			maViewObjectContactVector.clear();
80 
81 			while(!aLocalVOCList.empty())
82 			{
83 				ViewObjectContact* pCandidate = aLocalVOCList.back();
84 				aLocalVOCList.pop_back();
85 				DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList in VC (!)");
86 
87 				// ViewObjectContacts only make sense with View and Object contacts.
88 				// When the contact to the SdrObject is deleted like in this case,
89 				// all ViewObjectContacts can be deleted, too.
90 				delete pCandidate;
91 			}
92 
93 			// assert when there were new entries added during deletion
94 			DBG_ASSERT(maViewObjectContactVector.empty(), "Corrupted ViewObjectContactList in VC (!)");
95 		}
96 
97 		// get a Object-specific ViewObjectContact for a specific
98 		// ObjectContact (->View). Always needs to return something.
GetViewObjectContact(ObjectContact & rObjectContact)99 		ViewObjectContact& ViewContact::GetViewObjectContact(ObjectContact& rObjectContact)
100 		{
101 			ViewObjectContact* pRetval = 0L;
102 			const sal_uInt32 nCount(maViewObjectContactVector.size());
103 
104 			// first search if there exists a VOC for the given OC
105 			for(sal_uInt32 a(0); !pRetval && a < nCount; a++)
106 			{
107 				ViewObjectContact* pCandidate = maViewObjectContactVector[a];
108 				DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList (!)");
109 
110 				if(&(pCandidate->GetObjectContact()) == &rObjectContact)
111 				{
112 					pRetval = pCandidate;
113 				}
114 			}
115 
116 			if(!pRetval)
117 			{
118 				// create a new one. It's inserted to the local list from the
119 				// VieObjectContact constructor via AddViewObjectContact()
120 				pRetval = &CreateObjectSpecificViewObjectContact(rObjectContact);
121 			}
122 
123 			return *pRetval;
124 		}
125 
126 		// A new ViewObjectContact was created and shall be remembered.
AddViewObjectContact(ViewObjectContact & rVOContact)127 		void ViewContact::AddViewObjectContact(ViewObjectContact& rVOContact)
128 		{
129 			maViewObjectContactVector.push_back(&rVOContact);
130 
131 			if(1L == maViewObjectContactVector.size())
132 			{
133 				StartGettingViewed();
134 			}
135 		}
136 
137 		// A ViewObjectContact was deleted and shall be forgotten.
RemoveViewObjectContact(ViewObjectContact & rVOContact)138 		void ViewContact::RemoveViewObjectContact(ViewObjectContact& rVOContact)
139 		{
140 			std::vector< ViewObjectContact* >::iterator aFindResult = std::find(maViewObjectContactVector.begin(), maViewObjectContactVector.end(), &rVOContact);
141 
142 			if(aFindResult != maViewObjectContactVector.end())
143 			{
144 				maViewObjectContactVector.erase(aFindResult);
145 
146 				if(maViewObjectContactVector.empty())
147 				{
148 					// This may need to get asynchron later since it eventually triggers
149 					// deletes of OCs where the VOC is still added.
150 					StopGettingViewed();
151 				}
152 			}
153 		}
154 
155 		// Test if this ViewContact has ViewObjectContacts at all. This can
156 		// be used to test if this ViewContact is visualized ATM or not
HasViewObjectContacts(bool bExcludePreviews) const157 		bool ViewContact::HasViewObjectContacts(bool bExcludePreviews) const
158 		{
159 			const sal_uInt32 nCount(maViewObjectContactVector.size());
160 
161 			if(bExcludePreviews)
162 			{
163 				for(sal_uInt32 a(0); a < nCount; a++)
164 				{
165 					if(!maViewObjectContactVector[a]->GetObjectContact().IsPreviewRenderer())
166 					{
167 						return true;
168 					}
169 				}
170 
171 				return false;
172 			}
173 			else
174 			{
175 				return (0L != nCount);
176 			}
177 		}
178 
179 		// Test if this ViewContact has ViewObjectContacts at all. This can
180 		// be used to test if this ViewContact is visualized ATM or not
isAnimatedInAnyViewObjectContact() const181 		bool ViewContact::isAnimatedInAnyViewObjectContact() const
182 		{
183 			const sal_uInt32 nCount(maViewObjectContactVector.size());
184 
185 			for(sal_uInt32 a(0); a < nCount; a++)
186 			{
187 				if(maViewObjectContactVector[a]->isAnimated())
188 				{
189 					return true;
190 				}
191 			}
192 
193 			return false;
194 		}
195 
196 		// Access to possible sub-hierarchy and parent. GetObjectCount() default is 0L
197 		// and GetViewContact default pops up an assert since it's an error if
198 		// GetObjectCount has a result != 0 and it's not overloaded.
GetObjectCount() const199 		sal_uInt32 ViewContact::GetObjectCount() const
200 		{
201 			// no sub-objects
202 			return 0;
203 		}
204 
GetViewContact(sal_uInt32) const205 		ViewContact& ViewContact::GetViewContact(sal_uInt32 /*nIndex*/) const
206 		{
207 			// This is the default implementation; call would be an error
208 			DBG_ERROR("ViewContact::GetViewContact: This call needs to be overloaded when GetObjectCount() can return results != 0 (!)");
209 			return (ViewContact&)(*this);
210 		}
211 
GetParentContact() const212 		ViewContact* ViewContact::GetParentContact() const
213 		{
214 			// default has no parent
215 			return 0;
216 		}
217 
ActionChildInserted(ViewContact & rChild)218 		void ViewContact::ActionChildInserted(ViewContact& rChild)
219 		{
220 			// propagate change to all existing visualizations which
221 			// will force a VOC for the new child and invalidate it's range
222 			const sal_uInt32 nCount(maViewObjectContactVector.size());
223 
224 			for(sal_uInt32 a(0); a < nCount; a++)
225 			{
226 				ViewObjectContact* pCandidate = maViewObjectContactVector[a];
227 				DBG_ASSERT(pCandidate, "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");
228 
229 				// take action at all VOCs. At the VOCs ObjectContact the initial
230 				// rectangle will be invalidated at the associated OutputDevice.
231 				pCandidate->ActionChildInserted(rChild);
232 			}
233 		}
234 
235 		// React on changes of the object of this ViewContact
ActionChanged()236 		void ViewContact::ActionChanged()
237 		{
238 			// propagate change to all existing VOCs. This will invalidate
239 			// all drawn visualizations in all known views
240 			const sal_uInt32 nCount(maViewObjectContactVector.size());
241 
242 			for(sal_uInt32 a(0); a < nCount; a++)
243 			{
244 				ViewObjectContact* pCandidate = maViewObjectContactVector[a];
245 				DBG_ASSERT(pCandidate, "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");
246 
247 				pCandidate->ActionChanged();
248 			}
249 		}
250 
251 		// access to SdrObject and/or SdrPage. May return 0L like the default
252 		// implementations do. Needs to be overloaded as needed.
TryToGetSdrObject() const253 		SdrObject* ViewContact::TryToGetSdrObject() const
254 		{
255 			return 0L;
256 		}
257 
TryToGetSdrPage() const258 		SdrPage* ViewContact::TryToGetSdrPage() const
259 		{
260 			return 0L;
261 		}
262 
263 		//////////////////////////////////////////////////////////////////////////////
264 		// primitive stuff
265 
createViewIndependentPrimitive2DSequence() const266 		drawinglayer::primitive2d::Primitive2DSequence ViewContact::createViewIndependentPrimitive2DSequence() const
267 		{
268 			// This is the default implementation and should never be called (see header). If this is called,
269 			// someone implemented a ViewContact (VC) visualization object without defining the visualization by
270 			// providing a sequence of primitives -> which cannot be correct.
271 			// Since we have no access to any known model data here, the default implementation creates a yellow placeholder
272 			// hairline polygon with a default size of (1000, 1000, 5000, 3000)
273 			DBG_ERROR("ViewContact::createViewIndependentPrimitive2DSequence(): Never call the fallback base implementation, this is always an error (!)");
274 			const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(1000.0, 1000.0, 5000.0, 3000.0)));
275 			const basegfx::BColor aYellow(1.0, 1.0, 0.0);
276 			const drawinglayer::primitive2d::Primitive2DReference xReference(
277 				new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aYellow));
278 
279 			return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1);
280 		}
281 
getViewIndependentPrimitive2DSequence() const282 		drawinglayer::primitive2d::Primitive2DSequence ViewContact::getViewIndependentPrimitive2DSequence() const
283 		{
284 			// local up-to-date checks. Create new list and compare.
285 			drawinglayer::primitive2d::Primitive2DSequence xNew(createViewIndependentPrimitive2DSequence());
286 
287 			if(xNew.hasElements())
288 			{
289 				// allow evtl. embedding in object-specific infos, e.g. Name, Title, Description
290 				xNew = embedToObjectSpecificInformation(xNew);
291 			}
292 
293 			if(!drawinglayer::primitive2d::arePrimitive2DSequencesEqual(mxViewIndependentPrimitive2DSequence, xNew))
294 			{
295 				// has changed, copy content
296 				const_cast< ViewContact* >(this)->mxViewIndependentPrimitive2DSequence = xNew;
297 			}
298 
299 			// return current Primitive2DSequence
300 			return mxViewIndependentPrimitive2DSequence;
301 		}
302 
303 		// add Gluepoints (if available)
createGluePointPrimitive2DSequence() const304 		drawinglayer::primitive2d::Primitive2DSequence ViewContact::createGluePointPrimitive2DSequence() const
305 		{
306 			// default returns empty reference
307 			return drawinglayer::primitive2d::Primitive2DSequence();
308 		}
309 
embedToObjectSpecificInformation(const drawinglayer::primitive2d::Primitive2DSequence & rSource) const310 		drawinglayer::primitive2d::Primitive2DSequence ViewContact::embedToObjectSpecificInformation(const drawinglayer::primitive2d::Primitive2DSequence& rSource) const
311 		{
312 			// nothing to do for default
313 			return rSource;
314 		}
315 
flushViewObjectContacts(bool bWithHierarchy)316 		void ViewContact::flushViewObjectContacts(bool bWithHierarchy)
317 		{
318 			if(bWithHierarchy)
319 			{
320 				// flush DrawingLayer hierarchy
321 				const sal_uInt32 nCount(GetObjectCount());
322 
323 				for(sal_uInt32 a(0); a < nCount; a++)
324 				{
325 					ViewContact& rChild = GetViewContact(a);
326 					rChild.flushViewObjectContacts(bWithHierarchy);
327 				}
328 			}
329 
330 			// delete local VOCs
331 			deleteAllVOCs();
332 		}
333 	} // end of namespace contact
334 } // end of namespace sdr
335 
336 //////////////////////////////////////////////////////////////////////////////
337 // eof
338