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